diff -u --recursive --new-file v2.4.2/linux/CREDITS linux/CREDITS --- v2.4.2/linux/CREDITS Wed Feb 21 18:20:08 2001 +++ linux/CREDITS Sat Mar 3 10:52:18 2001 @@ -316,8 +316,8 @@ S: Australia N: Hugh Blemings -E: hugh@linuxcare.com -W: http://www.linuxcare.com.au/hugh/ +E: hugh@misc.nu +W: http://misc.nu/hugh/ D: Author and maintainer of the Keyspan USB to Serial drivers S: Po Box 234 S: Belconnen ACT 2616 @@ -679,12 +679,8 @@ N: Cort Dougan E: cort@fsmlabs.com -W: http://www.ppc.kernel.org/~cort/ +W: http://www.fsmlabs.com/linuxppcbk.html D: PowerPC -S: Finite State Machine Labs -S: P.O. 1829 -S: Socorro, New Mexico 87801 -S: USA N: Oleg Drokin E: green@ccssu.crimea.ua @@ -1026,11 +1022,11 @@ S: Canada N: Richard Günther -E: richard.guenther@student.uni-tuebingen.de +E: rguenth@tat.physik.uni-tuebingen.de +W: http://www.tat.physik.uni-tuebingen.de/~rguenth P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2 93 7A 32 42 45 37 23 57 D: binfmt_misc -S: Fichtenweg 3/511 -S: 72076 Tübingen +S: 72074 Tübingen S: Germany N: Justin Guyett @@ -1347,9 +1343,7 @@ N: Dave Jones E: davej@suse.de -E: dave@powertweak.com -E: djones2@glam.ac.uk -W: http://powertweak.sourceforge.net +W: http://www.suse.de/~davej D: Moved PCI bridge tuning to userspace (Powertweak). D: Centaur/IDT Winchip/Winchip 2 tweaks. D: AFFS fixes for 2.3.x @@ -2191,15 +2185,15 @@ S: USA N: Kai Petzke -E: wpp@marie.physik.tu-berlin.de -W: http://physik.tu-berlin.de/~wpp -P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1 +E: petzke@teltarif.de +W: http://www.teltarif.de/ +P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1 D: Driver for Laser Magnetic Storage CD-ROM D: Some kernel bug fixes D: Port of the database Postgres -D: "Unix fuer Jedermann" a German introduction to linux (see my web page) -S: M"ullerstr. 69 -S: 13349 Berlin +D: Book: "Linux verstehen und anwenden" (Hanser-Verlag) +S: Triftstra=DFe 55 +S: 13353 Berlin S: Germany N: Emanuel Pirker diff -u --recursive --new-file v2.4.2/linux/Documentation/Changes linux/Documentation/Changes --- v2.4.2/linux/Documentation/Changes Wed Feb 21 18:20:08 2001 +++ linux/Documentation/Changes Tue Mar 6 19:44:34 2001 @@ -54,7 +54,7 @@ o util-linux 2.10o # fdformat --version o modutils 2.4.2 # insmod -V o e2fsprogs 1.19 # tune2fs -o reiserfsprogs 3.x.0b # reiserfsck 2>&1|grep reiserfsprogs +o reiserfsprogs 3.x.0d # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version @@ -316,7 +316,7 @@ Reiserfsprogs ------------- -o +o LVM toolset ----------- diff -u --recursive --new-file v2.4.2/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.2/linux/Documentation/Configure.help Wed Feb 21 18:20:08 2001 +++ linux/Documentation/Configure.help Mon Mar 12 18:13:28 2001 @@ -1501,15 +1501,6 @@ If unsure, say Y. -RAID-1/RAID-5 code (DANGEROUS) -CONFIG_RAID15_DANGEROUS - This new RAID1/RAID5 code has been freshly merged, and has not seen - enough testing yet. While there are no known bugs in it, it might - destroy your filesystems, eat your data and start World War III. - You have been warned. - - If unsure, say N. - RAID-1 (mirroring) mode CONFIG_MD_RAID1 A RAID-1 set consists of several disk drives which are exact copies @@ -1989,6 +1980,40 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +TCPMSS target support +CONFIG_IP_NF_TARGET_TCPMSS + This option adds a `TCPMSS' target, which allows you to alter the + MSS value of TCP SYN packets, to control the maximum size for that + connection (usually limiting it to your outgoing interface's MTU + minus 40). + + This is used to overcome criminally braindead ISPs or servers which + block ICMP Fragmentation Needed packets. The symptoms of this + problem are that everything works fine from your Linux + firewall/router, but machines behind it can never exchange large + packets: + 1) Web browsers connect, then hang with no data received. + 2) Small mail works fine, but large emails hang. + 3) ssh works fine, but scp hangs after initial handshaking. + + Workaround: activate this option and add a rule to your firewall + configuration like: + + iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \ + -j TCPMSS --clamp-mss-to-pmtu + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +tcpmss match support +CONFIG_IP_NF_MATCH_TCPMSS + This option adds a `tcpmss' match, which allows you to examine the + MSS value of TCP SYN packets, which control the maximum packet size + for that connection. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + LOG target support CONFIG_IP_NF_TARGET_LOG This option adds a `LOG' target, which allows you to create rules in @@ -2019,6 +2044,73 @@ If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +IP6 tables support (required for filtering/masq/NAT) +CONFIG_IP6_NF_IPTABLES + ip6tables is a general, extensible packet identification framework. + Currently only the packet filtering and packet mangling subsystem + for IPv6 use this, but connection tracking is going to follow. + Say 'Y' or 'M' here if you want to use either of those. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +IPv6 limit match support +CONFIG_IP6_NF_MATCH_LIMIT + limit matching allows you to control the rate at which a rule can be + matched: mainly useful in combination with the LOG target ("LOG + target support", below) and to avoid some Denial of Service attacks. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +MAC address match support +CONFIG_IP6_NF_MATCH_MAC + mac matching allows you to match packets based on the source + ethernet address of the packet. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +netfilter mark match support +CONFIG_IP6_NF_MATCH_MARK + Netfilter mark matching allows you to match packets based on the + `nfmark' value in the packet. This can be set by the MARK target + (see below). + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +Packet filtering +CONFIG_IP6_NF_FILTER + Packet filtering defines a table `filter', which has a series of + rules for simple packet filtering at local input, forwarding and + local output. See the man page for iptables(8). + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +Packet mangling +CONFIG_IP6_NF_MANGLE + This option adds a `mangle' table to iptables: see the man page for + iptables(8). This table is used for various packet alterations + which can effect how the packet is routed. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + +MARK target support +CONFIG_IP6_NF_TARGET_MARK + This option adds a `MARK' target, which allows you to create rules + in the `mangle' table which alter the netfilter mark (nfmark) field + associated with the packet packet prior to routing. This can change + the routing method (see `IP: use netfilter MARK value as routing + key') and can also be used by other subsystems to change their + behavior. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + + TCP Explicit Congestion Notification support CONFIG_INET_ECN Explicit Congestion Notification (ECN) allows routers to notify @@ -5469,6 +5561,45 @@ Adaptec AIC7xxx chipset SCSI controller support CONFIG_SCSI_AIC7XXX + This driver supports all of Adaptec's PCI based SCSI controllers (not + the hardware RAID controllers though) as well as the aic7770 based + EISA and VLB SCSI controllers (the 274x and 284x series). This is + an Adaptec sponsored driver written by Justin Gibbs. It is intended + to replace the previous aic7xxx driver maintained by Doug Ledford since + Doug is no longer maintaining that driver. + +Default number of TCQ commands per device +CONFIG_AIC7XXX_CMDS_PER_DEVICE + Specify the number of commands you would like to allocate per SCSI + device when Tagged Command Queueing (TCQ) is enabled on that device. + + This is an upper bound value for the number of tagged transactions + to be used for any device. The aic7xxx driver will automatically + vary this number based on device behavior. For devices with a + fixed maximum, the driver will eventually lock to this maximum + and display a console message inidicating this value. + + Note: Unless you experience some type of device failure, the default + value, no enforced limit, should work for you. + + Default: 253 + +Initial Bus Reset Settle Delay +CONFIG_AIC7XXX_RESET_DELAY + The number of milliseconds to delay after an initial bus reset. + The bus settle delay following all error recovery actions is + dictated by the SCSI layer and is not affected by this value. + + Default: 5000 (5 seconds) + +Old Adaptec AIC7xxx chipset SCSI controller support +CONFIG_SCSI_AIC7XXX_OLD + WARNING This driver is an older aic7xxx driver and is no longer under + active development. Adaptec, Inc. is writing a new driver to take the + place of this one, and it is recommended that whenever possible, people + should use the new Adaptec written driver instead of this one. This + driver will eventually be phased out entirely. + This is support for the various aic7xxx based Adaptec SCSI controllers. These include the 274x EISA cards; 284x VLB cards; 2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and @@ -5490,7 +5621,7 @@ Information on the configuration options for this controller can be found by checking the help file for each of the available - configuration options. You should read drivers/scsi/README.aic7xxx + configuration options. You should read drivers/scsi/aic7xxx_old/README.aic7xxx at a minimum before contacting the maintainer with any questions. The SCSI-HOWTO, available from http://www.linuxdoc.org/docs.html#howto , can also be of great @@ -5499,10 +5630,10 @@ If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be - called aic7xxx.o. + called aic7xxx_old.o. Enable or Disable Tagged Command Queueing by default -CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT +CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT This option causes the aic7xxx driver to attempt to use Tagged Command Queueing (TCQ) on all devices that claim to support it. @@ -5536,7 +5667,7 @@ reduce performance. Default number of TCQ commands per device -CONFIG_AIC7XXX_CMDS_PER_DEVICE +CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE Specify the number of commands you would like to allocate per SCSI device when Tagged Command Queueing (TCQ) is enabled on that device. @@ -5557,7 +5688,7 @@ Default: 8 Collect statistics to report in /proc -CONFIG_AIC7XXX_PROC_STATS +CONFIG_AIC7XXX_OLD_PROC_STATS This option tells the driver to keep track of how many commands have been sent to each particular device and report that information to the user via the /proc/scsi/aic7xxx/n file, where n is the number of @@ -5569,21 +5700,6 @@ If unsure, say N. -Delay in seconds after SCSI bus reset -CONFIG_AIC7XXX_RESET_DELAY - This sets how long the driver will wait after resetting the SCSI bus - before attempting to communicate with the devices on the SCSI bus - again. This delay will be used during the reset phase at bootup time - as well as after any reset that might occur during normal operation. - Reasonable numbers range anywhere from 5 to 15 seconds depending on - your devices. DAT tape drives are notorious for needing more time - after a bus reset to be ready for the next command, but most hard - drives and CD-ROM devices are ready in only a few seconds. This - option has a maximum upper limit of 20 seconds to avoid bad - interactions between the aic7xxx driver and the rest of the Linux - kernel. The default value has been reduced to 5 seconds. If this - doesn't work with your hardware, try increasing this value. - IBM ServeRAID Support CONFIG_SCSI_IPS This is support for the IBM ServeRAID hardware RAID controllers. @@ -8390,22 +8506,6 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. -RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL) -CONFIG_RTL8129 - This is NOT for RTL-8139 cards. Instead, select the 8139too driver - (CONFIG_8139TOO). - This is a driver for the Fast Ethernet PCI network cards based on - the RTL8129 chip. If you have one of those, say Y and - read the Ethernet-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . - - Note: the 8029 is a NE2000 PCI clone, you can use the NE2K-PCI 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. This is recommended. - The module will be called rtl8129.o. - RealTek RTL-8139 PCI Fast Ethernet Adapter support CONFIG_8139TOO This is a driver for the Fast Ethernet PCI network cards based on @@ -8481,7 +8581,7 @@ 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. This is recommended. - The module will be called starfile.o. + The module will be called starfire.o. Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support CONFIG_ACENIC @@ -9399,7 +9499,7 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will will be called olympic.o. If you want to compile it + The module will be called olympic.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. Also read the file Documentation/networking/olympic.txt or check the @@ -9439,7 +9539,7 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will will be called tms380tr.o. If you want to compile it + The module will be called tms380tr.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. Generic TMS380 PCI support @@ -9454,7 +9554,7 @@ This driver is available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will will be called tmspci.o. If you want to compile it + The module will be called tmspci.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. Madge Smart 16/4 PCI Mk2 support @@ -9464,7 +9564,7 @@ This driver is available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will will be called abyss.o. If you want to compile it + The module will be called abyss.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. Madge Smart 16/4 Ringode MicroChannel @@ -9474,7 +9574,7 @@ This driver is available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will will be called madgemc.o. If you want to compile it + The module will be called madgemc.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. SMC ISA TokenRing adapter support @@ -9490,7 +9590,7 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will will be called smctr.o. If you want to compile it + The module will be called smctr.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. Sun Happy Meal 10/100baseT support diff -u --recursive --new-file v2.4.2/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt --- v2.4.2/linux/Documentation/DMA-mapping.txt Mon Dec 11 13:45:42 2000 +++ linux/Documentation/DMA-mapping.txt Tue Mar 6 22:44:15 2001 @@ -59,7 +59,7 @@ 1) Use some non-DMA mode for data transfer, if possible. 2) Ignore this device and do not initialize it. -It is recommended that your driver print a kernel KERN_WARN message +It is recommended that your driver print a kernel KERN_WARNING message when you do one of these two things. In this manner, if a user of your driver reports that performance is bad or that the device is not even detected, you can ask him for the kernel messages to find out @@ -71,12 +71,35 @@ if (! pci_dma_supported(pdev, 0x00ffffff)) goto ignore_this_device; +When DMA is possible for a given mask, the PCI layer must be informed of the +mask for later allocation operations on the device. This is achieved by +setting the dma_mask member of the pci_dev structure, like so: + +#define MY_HW_DMA_MASK 0x00ffffff + + if (! pci_dma_supported(pdev, MY_HW_DMA_MASK)) + goto ignore_this_device; + + pdev->dma_mask = MY_HW_DMA_MASK; + +A helper function is provided which performs this common code sequence: + + int pci_set_dma_mask(struct pci_dev *pdev, dma_addr_t device_mask) + +Unlike pci_dma_supported(), this returns -EIO when the PCI layer will not be +able to DMA with addresses restricted by that mask, and returns 0 when DMA +transfers are possible. If the call succeeds, the dma_mask will have been +updated so that your driver need not worry about it. + There is a case which we are aware of at this time, which is worth mentioning in this documentation. If your device supports multiple functions (for example a sound card provides playback and record functions) and the various different functions have _different_ DMA addressing limitations, you may wish to probe each mask and -only provide the functionality which the machine can handle. +only provide the functionality which the machine can handle. It +is important that the last call to pci_set_dma_mask() be for the +most specific mask. + Here is pseudo-code showing how this might be done: #define PLAYBACK_ADDRESS_BITS 0xffffffff @@ -86,14 +109,14 @@ struct pci_dev *pdev; ... - if (pci_dma_supported(pdev, PLAYBACK_ADDRESS_BITS)) { + if (pci_set_dma_mask(pdev, PLAYBACK_ADDRESS_BITS)) { card->playback_enabled = 1; } else { card->playback_enabled = 0; printk(KERN_WARN "%s: Playback disabled due to DMA limitations.\n", card->name); } - if (pci_dma_supported(pdev, RECORD_ADDRESS_BITS)) { + if (pci_set_dma_mask(pdev, RECORD_ADDRESS_BITS)) { card->record_enabled = 1; } else { card->record_enabled = 0; diff -u --recursive --new-file v2.4.2/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl --- v2.4.2/linux/Documentation/DocBook/kernel-api.tmpl Sat Dec 30 18:16:13 2000 +++ linux/Documentation/DocBook/kernel-api.tmpl Fri Mar 2 18:43:10 2001 @@ -34,6 +34,18 @@ + + + Driver Basic + Driver Entry and Exit points +!Iinclude/linux/init.h + + + Atomics +!Iinclude/asm-i386/atomic.h + + + Data Types Doubly Linked Lists diff -u --recursive --new-file v2.4.2/linux/Documentation/arm/SA1100/Brutus linux/Documentation/arm/SA1100/Brutus --- v2.4.2/linux/Documentation/arm/SA1100/Brutus Fri May 12 11:21:20 2000 +++ linux/Documentation/arm/SA1100/Brutus Fri Mar 2 11:12:06 2001 @@ -3,7 +3,7 @@ http://developer.intel.com/design/strong/applnots/sa1100lx/getstart.htm -To compile for Brutus, you must issue the following comands: +To compile for Brutus, you must issue the following commands: make brutus_config make config diff -u --recursive --new-file v2.4.2/linux/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt --- v2.4.2/linux/Documentation/binfmt_misc.txt Tue Apr 28 14:22:03 1998 +++ linux/Documentation/binfmt_misc.txt Fri Mar 2 18:38:37 2001 @@ -81,6 +81,6 @@ There is a web page about binfmt_misc at -http://www.anatom.uni-tuebingen.de/~richi/linux/binfmt_misc.html +http://www.tat.physik.uni-tuebingen.de/~rguenth/linux/binfmt_misc.html -Richard Günther, richard.guenther@student.uni-tuebingen.de +Richard Günther diff -u --recursive --new-file v2.4.2/linux/Documentation/dnotify.txt linux/Documentation/dnotify.txt --- v2.4.2/linux/Documentation/dnotify.txt Tue Nov 14 10:54:07 2000 +++ linux/Documentation/dnotify.txt Fri Mar 2 18:38:37 2001 @@ -28,7 +28,7 @@ information. However, if the F_SETSIG fcntl(2) call is used to let the kernel know which signal to deliver, a siginfo structure will be passed to the signal handler and the si_fd member of that structure will contain the -file descriptor associated with the direcory in which the event occured. +file descriptor associated with the directory in which the event occurred. Preferably the application will choose one of the real time signals (SIGRTMIN + ) so that the notifications may be queued. This is diff -u --recursive --new-file v2.4.2/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.4.2/linux/Documentation/ioctl-number.txt Wed Feb 21 18:20:09 2001 +++ linux/Documentation/ioctl-number.txt Fri Mar 2 17:50:22 2001 @@ -92,6 +92,7 @@ 'M' all linux/soundcard.h conflict! 'M' 00-1F linux/isicom.h conflict! +'N' 00-1F drivers/usb/scanner.h 'P' all linux/soundcard.h 'Q' all linux/soundcard.h 'R' 00-1F linux/random.h diff -u --recursive --new-file v2.4.2/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE --- v2.4.2/linux/Documentation/isdn/INTERFACE Wed Feb 21 18:20:09 2001 +++ linux/Documentation/isdn/INTERFACE Fri Mar 2 18:38:37 2001 @@ -1,4 +1,4 @@ -$Id: INTERFACE,v 1.15 1999/08/25 20:02:13 werner Exp $ +$Id: INTERFACE,v 1.15.8.1 2001/02/16 16:43:22 kai Exp $ Description of the Interface between Linklevel and Hardwarelevel of isdn4linux: @@ -481,7 +481,7 @@ driver = driver-Id command = ISDN_CMD_PROT_IO arg = The lower 8 Bits define the addressed protocol as defined - in ISDN_PTYPE..., the upper bits are used to differenciate + in ISDN_PTYPE..., the upper bits are used to differentiate the protocol specific CMD. para = protocol and function specific. See isdnif.h for detail. diff -u --recursive --new-file v2.4.2/linux/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon --- v2.4.2/linux/Documentation/isdn/README.eicon Sat Nov 11 18:58:02 2000 +++ linux/Documentation/isdn/README.eicon Fri Mar 2 11:12:12 2001 @@ -100,17 +100,6 @@ the necessary D-Channel traces for isdnlog. -FILECHECK: -A part of the eicon driver source code files are provided -by Eicon Technology. In order to get the best support from Eicon, -these files are tested with a checksum, just to know if the files -were modified. This does *not* mean, you are not allowed to modify the -driver. If you want to improve the driver or you fix a bug, please do -so and let me (or Eicon) know, about the necessary changes. So -every user knows, if the driver he uses is modified or checked with -Eicon files. When the driver has been loaded, in the syslog you will -find something like "verified" or "modified" right after the version. - Thanks to Deutsche Mailbox Saar-Lor-Lux GmbH diff -u --recursive --new-file v2.4.2/linux/Documentation/isdn/README.hysdn linux/Documentation/isdn/README.hysdn --- v2.4.2/linux/Documentation/isdn/README.hysdn Wed Feb 21 18:20:09 2001 +++ linux/Documentation/isdn/README.hysdn Fri Mar 2 11:12:12 2001 @@ -1,4 +1,4 @@ -$Id: README.hysdn,v 1.3 2000/08/06 09:22:51 armin Exp $ +$Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $ The hysdn driver has been written by by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver diff -u --recursive --new-file v2.4.2/linux/Documentation/kernel-doc-nano-HOWTO.txt linux/Documentation/kernel-doc-nano-HOWTO.txt --- v2.4.2/linux/Documentation/kernel-doc-nano-HOWTO.txt Mon Jun 19 12:56:07 2000 +++ linux/Documentation/kernel-doc-nano-HOWTO.txt Fri Mar 2 18:43:11 2001 @@ -57,7 +57,8 @@ If you want to see man pages instead, you can do this: $ cd linux -$ scripts/kernel-doc -man $(find -name '*.c' '*.h') | split-man.pl /tmp/man +$ scripts/kernel-doc -man $(find -name '*.c') | split-man.pl /tmp/man +$ scripts/kernel-doc -man $(find -name '*.h') | split-man.pl /tmp/man Here is split-man.pl: @@ -68,7 +69,7 @@ die "where do I put the results?\n"; } -mkdir $ARGV[0],0777 or die "Can't create $ARGV[0]: $!\n"; +mkdir $ARGV[0],0777; $state = 0; while () { if (/^\.TH \"[^\"]*\" 4 \"([^\"]*)\"/) { diff -u --recursive --new-file v2.4.2/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt --- v2.4.2/linux/Documentation/kernel-parameters.txt Sat Dec 30 11:23:13 2000 +++ linux/Documentation/kernel-parameters.txt Fri Mar 2 11:02:15 2001 @@ -188,8 +188,10 @@ es1371= [HW,SOUND] - ether= [HW,NET] Ethernet cards parameters (iomem, irq, - dev_name). + ether= [HW,NET] Ethernet cards parameters (irq, + base_io_addr, mem_start, mem_end, name. + (mem_start is often overloaded to mean something + different and driver-specific). fd_mcs= [HW,SCSI] @@ -328,7 +330,11 @@ ncr53c8xx= [HW,SCSI] - netdev= [NET] + netdev= [NET] Ethernet cards parameters (irq, + base_io_addr, mem_start, mem_end, name. + (mem_start is often overloaded to mean something + different and driver-specific). + (cf: ether=) nfsaddrs= [NFS] diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.4.2/linux/Documentation/networking/8139too.txt Mon Oct 30 12:54:42 2000 +++ linux/Documentation/networking/8139too.txt Fri Mar 2 11:02:14 2001 @@ -180,6 +180,52 @@ Change History -------------- +Version 0.9.15 - February 20, 2001 + +* Call pci_enable_device to wake up/assign resource to device, + before actually using it. +* Support wacky clone PCI ids (report from Norival Toniato Junior) +* Text spelling corrections +* Make sure tp->phys[] is signed +* Always wake queue after hw restart, in tx_timeout +* Record time of last received packet + + +Version 0.9.14 - January 11, 2001 + +* Merge some changes from Becker version 1.13: + * Add DFE 538TX PCI id + * MII read/write functions updated + * Cfg93[45]6 lock/unlock fix + * RTL-8129 (MII) support +* Clean up spinlocking + + +Version 0.9.13 - December, 2000 + +* Clear blocked signals, avoid buffer overrun setting current->comm +* Remove bogus PCI BAR length assertions +* Remove unused 'debug' module parameter + + +Version 0.9.12 - November 23, 2000 + +* Kill major Tx stop/wake queue race +* Use SET_MODULE_OWNER and fix module unload race +* Fix cable length ("Twister") tuning +* Proper media[] array length checking +* Replace timer with kernel thread for twister tuning state machine + and media checking. Fixes mdio_xxx locking, now mdio_xxx is always + protected by rtnl_lock semaphore. +* Correct some sledgehammer a.k.a. overzealous spin-locks +* Performance: Eliminate atomic_t for Tx counters, we don't need it +* Performance: Don't copy Tx buffer if the rare case occurs where it + is aligned perfectly for us. +* Eliminate needless casting of dev->priv +* PIO mode selection and Twister tuning are now CONFIG_xxx options + (though purposefully not in net/Config.in... yet) + + Version 0.9.11 - October 28, 2000 * Do not fail when PIO and MMIO region lengths do not match. diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/tlan.txt linux/Documentation/networking/tlan.txt --- v2.4.2/linux/Documentation/networking/tlan.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/networking/tlan.txt Tue Mar 6 19:44:34 2001 @@ -1,11 +1,11 @@ (C) 1997-1998 Caldera, Inc. (C) 1998 James Banks -(C) 1999-2000 Torben Mathiasen +(C) 1999-2001 Torben Mathiasen -For driver information/updates visit http://tlan.kernel.dk +For driver information/updates visit http://opensource.compaq.com -TLAN driver for Linux, version 1.8a +TLAN driver for Linux, version 1.14a README @@ -94,6 +94,16 @@ speeds with kernel-parameters. ether=0,0,0x12,0,eth0 will force link to 100Mbps Half-Duplex. + 7. If you have more than one tlan adapter in your system, you can + use the above options on a per adapter basis. To force a 100Mbit/HD + link with your eth1 adapter use: + + insmod tlan speed=0,100 duplex=0,1 + + Now eth0 will use auto-neg and eth1 will be forced to 100Mbit/HD. + Note that the tlan driver supports a maximum of 8 adapters. + + III. Things to try if you have problems. 1. Make sure your card's PCI id is among those listed in section I, above. @@ -103,5 +113,5 @@ There is also a tlan mailing list which you can join by sending "subscribe tlan" in the body of an email to majordomo@vuser.vu.union.edu. -There is also a tlan website at http://tlan.kernel.dk +There is also a tlan website at http://opensource.compaq.com diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/tulip.txt linux/Documentation/networking/tulip.txt --- v2.4.2/linux/Documentation/networking/tulip.txt Tue Nov 7 11:08:09 2000 +++ linux/Documentation/networking/tulip.txt Fri Mar 2 11:02:14 2001 @@ -148,6 +148,17 @@ Version history =============== +0.9.14 (February 20, 2000): +* Fix PNIC problems (Manfred Spraul) +* Add new PCI id for Accton comet +* Support Davicom tulips +* Fix oops in eeprom parsing +* Enable workarounds for early PCI chipsets +* IA64, hppa csr0 support +* Support media types 5, 6 +* Interpret a bit more of the 21142 SROM extended media type 3 +* Add missing delay in eeprom reading + 0.9.11 (November 3, 2000): * Eliminate extra bus accesses when sharing interrupts (prumpf) * Barrier following ownership descriptor bit flip (prumpf) diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt --- v2.4.2/linux/Documentation/networking/vortex.txt Fri Sep 15 16:28:25 2000 +++ linux/Documentation/networking/vortex.txt Tue Mar 6 19:13:51 2001 @@ -6,7 +6,7 @@ This document describes the usage and errata of the 3Com "Vortex" device driver for Linux, 3c59x.c. -The driver was written by Donald Becker +The driver was written by Donald Becker Don is no longer the prime maintainer of this version of the driver. Please report problems to one or more of: @@ -34,6 +34,7 @@ 3c900 Boomerang 10baseT 3c900 Boomerang 10Mbps Combo 3c900 Cyclone 10Mbps TPO + 3c900B Cyclone 10Mbps T 3c900 Cyclone 10Mbps Combo 3c900 Cyclone 10Mbps TPC 3c900B-FL Cyclone 10base-FL @@ -116,7 +117,11 @@ full_duplex=N1,N2,N3... Similar to bit 9 of 'options'. Forces the corresponding card into - full-duplex mode. + full-duplex mode. Please use this in preference to the `options' + parameter. + + In fact, please don't use this at all! You're better off getting + autonegotiation working properly. flow_ctrl=N1,N2,N3... @@ -156,6 +161,33 @@ is exceeded the interrupt service routine gives up and generates a warning message "eth0: Too much work in interrupt". +hw_checksums=N1,N2,N3,... + + Recent 3com NICs are able to generate IPv4, TCP and UDP checksums + in hardware. Linux has used the Rx checksumming for a long time. + The "zero copy" patch which is planned for the 2.4 kernel series + allows you to make use of the NIC's DMA scatter/gather and transmit + checksumming as well. + + The driver is set up so that, when the zerocopy patch is applied, + all Tornado and Cyclone devices will use S/G and Tx checksums. + + This module parameter has been provided so you can override this + decision. If you think that Tx checksums are causing a problem, you + may disable the feature with `hw_checksums=0'. + + If you think your NIC should be performing Tx checksumming and the + driver isn't enabling it, you can force the use of hardware Tx + checksumming with `hw_checksums=1'. + + The driver drops a message in the logfiles to indicate whether or + not it is using hardware scatter/gather and hardware Tx checksums. + + Scatter/gather and hardware checksums provide considerable + performance improvement for the sendfile() system call, but a small + decrease in throughput for send(). There is no effect upon receive + efficiency. + compaq_ioaddr=N compaq_irq=N compaq_device_id=N @@ -168,7 +200,35 @@ decides that the transmitter has become stuck and needs to be reset. This is mainly for debugging purposes, although it may be advantageous to increase this value on LANs which have very high collision rates. - The default value is 400 (0.4 seconds). + The default value is 5000 (5.0 seconds). + +enable_wol=N1,N2,N3,... + + Enable Wake-on-LAN support for the relevant interface. Donald + Becker's `ether-wake' application may be used to wake suspended + machines. + + +Media selection +--------------- + +A number of the older NICs such as the 3c590 and 3c900 series have +10base2 and AUI interfaces. + +Prior to January, 2001 this driver would autoeselect the 10base2 or AUI +port if it didn't detect activity on the 10baseT port. It would then +get stuck on the 10base2 port and a driver reload was necessary to +switch back to 10baseT. This behaviour could not be prevented with a +module option override. + +Later (current) versions of the driver _do_ support locking of the +media type. So if you load the driver module with + + modprobe 3c59x options=0 + +it will permanently select the 10baseT port. Automatic selection of +other media types does not occur. + Additional resources -------------------- @@ -177,31 +237,36 @@ Additional documentation is available at Don Becker's Linux Drivers site: - http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html + http://www.scyld.com/network/vortex.html Donald Becker's driver development site: - http://www.scyld.com - http://cesdis.gsfc.nasa.gov/linux/ + http://www.scyld.com/network -Don's vortex-diag program is useful for inspecting the NIC's state: +Donald's vortex-diag program is useful for inspecting the NIC's state: http://www.scyld.com/diag/#pci-diags - http://cesdis.gsfc.nasa.gov/linux/diag/vortex-diag.c -Don's mii-diag program may be used for inspecting and manipulating the -NIC's Media Independent Interface subsystem: +Donald's mii-diag program may be used for inspecting and manipulating +the NIC's Media Independent Interface subsystem: http://www.scyld.com/diag/#mii-diag - http://cesdis.gsfc.nasa.gov/linux/diag/#mii-diag + +Donald's wake-on-LAN page: + + http://www.scyld.com/expert/wake-on-lan.html 3Com's documentation for many NICs, including the ones supported by this driver is available at http://support.3com.com/partners/developer/developer_form.html -A detailed changelog for the modifications which were made for 2.3 -series kernel is available at +3Com's DOS-based application for setting up the NICs EEPROMs: + + ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe + +Driver updates and a detailed changelog for the modifications which +were made for the 2.3/2,4 series kernel is available at http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 @@ -222,6 +287,21 @@ tree parameter for the port the machine is plugged into to 'portfast' mode. Otherwise, the negotiation fails. This has been an issue we've noticed for a while but haven't had the time to track down. + + Cisco switches (Jeff Busch ) + + My "standard config" for ports to which PC's/servers connect directly: + + interface FastEthernet0/N + description machinename + load-interval 30 + spanning-tree portfast + + If autonegotiation is a problem, you may need to specify "speed + 100" and "duplex full" as well (or "speed 10" and "duplex half"). + + WARNING: DO NOT hook up hubs/switches/bridges to these + specially-configured ports! The switch will become very confused. Reporting and diagnosing problems diff -u --recursive --new-file v2.4.2/linux/Documentation/powerpc/ppc_htab.txt linux/Documentation/powerpc/ppc_htab.txt --- v2.4.2/linux/Documentation/powerpc/ppc_htab.txt Wed Mar 10 21:49:10 1999 +++ linux/Documentation/powerpc/ppc_htab.txt Sat Mar 3 10:52:23 2001 @@ -2,7 +2,7 @@ ===================================================================== This document and the related code was written by me (Cort Dougan), please -email me (cort@cs.nmt.edu) if you have questions, comments or corrections. +email me (cort@fsmlabs.com) if you have questions, comments or corrections. Last Change: 2.16.98 diff -u --recursive --new-file v2.4.2/linux/Documentation/powerpc/smp.txt linux/Documentation/powerpc/smp.txt --- v2.4.2/linux/Documentation/powerpc/smp.txt Thu Apr 29 12:39:07 1999 +++ linux/Documentation/powerpc/smp.txt Sat Mar 3 10:52:27 2001 @@ -2,7 +2,7 @@ ===================================================================== This document and the related code was written by me -(Cort Dougan, cort@cs.nmt.edu) please email me if you have questions, +(Cort Dougan, cort@fsmlabs.com) please email me if you have questions, comments or corrections. Last Change: 3.31.99 diff -u --recursive --new-file v2.4.2/linux/Documentation/powerpc/sound.txt linux/Documentation/powerpc/sound.txt --- v2.4.2/linux/Documentation/powerpc/sound.txt Mon Jun 28 13:40:39 1999 +++ linux/Documentation/powerpc/sound.txt Sat Mar 3 10:52:30 2001 @@ -1,7 +1,7 @@ Information about PowerPC Sound support ===================================================================== -Please mail me (Cort Dougan, cort@cs.nmt.edu) if you have questions, +Please mail me (Cort Dougan, cort@fsmlabs.com) if you have questions, comments or corrections. Last Change: 6.16.99 diff -u --recursive --new-file v2.4.2/linux/Documentation/powerpc/zImage_layout.txt linux/Documentation/powerpc/zImage_layout.txt --- v2.4.2/linux/Documentation/powerpc/zImage_layout.txt Sat Oct 10 09:53:24 1998 +++ linux/Documentation/powerpc/zImage_layout.txt Sat Mar 3 10:52:32 2001 @@ -1,7 +1,7 @@ Information about the Linux/PPC kernel images ===================================================================== -Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions, +Please mail me (Cort Dougan, cort@fsmlabs.com) if you have questions, comments or corrections. This document is meant to answer several questions I've had about how diff -u --recursive --new-file v2.4.2/linux/Documentation/s390/cds.txt linux/Documentation/s390/cds.txt --- v2.4.2/linux/Documentation/s390/cds.txt Wed Feb 21 18:20:09 2001 +++ linux/Documentation/s390/cds.txt Fri Mar 2 11:12:06 2001 @@ -241,7 +241,7 @@ The get_dev_info_by_irq() / get_dev_info_by_devno() functions return: - 0 - sucessful completion + 0 - successful completion -ENODEV - irq or devno don't specify a known subchannel or device number. -EINVAL - invalid devinfo value. @@ -317,7 +317,7 @@ 0 - successful completion -ENODEV - irq doesn't specify a valid subchannel number -EINVAL - an invalid parameter was detected --EBUSY - an irrecoverable I/O error occured or the device is not +-EBUSY - an irrecoverable I/O error occurred or the device is not operational. Usage Notes : @@ -568,7 +568,7 @@ The do_IO() function returns : - 0 - successful completion or request successfuly initiated + 0 - successful completion or request successfully initiated -EBUSY - the do_io() function was caled out of sequence. The device is currently processing a previous I/O request -ENODEV - irq doesn't specify a valid subchannel, the device is @@ -777,7 +777,7 @@ The halt_IO() function returns : - 0 - successful completion or request successfuly initiated + 0 - successful completion or request successfully initiated -EBUSY - the device is currently performing a synchronous I/O operation : do_IO() with flag DOIO_WAIT_FOR_INTERRUPT or an error was encountered and the device is currently diff -u --recursive --new-file v2.4.2/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.2/linux/MAINTAINERS Wed Feb 21 18:20:09 2001 +++ linux/MAINTAINERS Sat Mar 3 10:52:14 2001 @@ -745,7 +745,7 @@ LINUX FOR POWERPC P: Cort Dougan M: cort@fsmlabs.com -W: http://www.ppc.kernel.org/ +W: http://www.fsmlabs.com/linuxppcbk.html S: Maintained LINUX FOR POWER MACINTOSH diff -u --recursive --new-file v2.4.2/linux/Makefile linux/Makefile --- v2.4.2/linux/Makefile Wed Feb 21 18:20:09 2001 +++ linux/Makefile Tue Mar 6 23:06:01 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 2 -EXTRAVERSION = +SUBLEVEL = 3 +EXTRAVERSION =-pre4 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -10,7 +10,7 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) -TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) +TOPDIR := $(shell /bin/pwd) HPATH = $(TOPDIR)/include FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net @@ -144,6 +144,7 @@ DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o +DRIVERS-$(CONFIG_SCSI_AIC7XXX) += drivers/scsi/aic7xxx/aic7xxx_drv.o DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) @@ -440,8 +441,8 @@ find . -type f -print | sort | xargs sum > .SUMS dep-files: scripts/mkdep archdep include/linux/version.h - scripts/mkdep init/*.c > .depend - scripts/mkdep `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend + scripts/mkdep -- init/*.c > .depend + scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" ifdef CONFIG_MODVERSIONS $(MAKE) update-modverfile diff -u --recursive --new-file v2.4.2/linux/Rules.make linux/Rules.make --- v2.4.2/linux/Rules.make Fri Dec 29 14:07:19 2000 +++ linux/Rules.make Tue Mar 6 19:31:01 2001 @@ -123,7 +123,7 @@ # This make dependencies quickly # fastdep: dummy - $(TOPDIR)/scripts/mkdep $(wildcard *.[chS] local.h.master) > .depend + $(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- $(wildcard *.[chS]) > .depend ifdef ALL_SUB_DIRS $(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS)) _FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)" endif @@ -150,7 +150,7 @@ # ALL_MOBJS = $(filter-out $(obj-y), $(obj-m)) ifneq "$(strip $(ALL_MOBJS))" "" -PDWN=$(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh) +MOD_DESTDIR := $(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh) endif unexport MOD_DIRS @@ -172,8 +172,8 @@ .PHONY: _modinst__ _modinst__: dummy ifneq "$(strip $(ALL_MOBJS))" "" - mkdir -p $(MODLIB)/kernel/$(PDWN) - cp $(ALL_MOBJS) $(MODLIB)/kernel/$(PDWN) + mkdir -p $(MODLIB)/kernel/$(MOD_DESTDIR) + cp $(ALL_MOBJS) $(MODLIB)/kernel/$(MOD_DESTDIR)$(MOD_TARGET) endif .PHONY: modules_install @@ -222,9 +222,9 @@ $(MODINCL)/%.ver: %.c @if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \ - echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \ + echo '$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $<'; \ echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \ - $(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \ + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< \ | $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \ if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \ else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \ diff -u --recursive --new-file v2.4.2/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.4.2/linux/arch/alpha/defconfig Mon Oct 16 15:38:41 2000 +++ linux/arch/alpha/defconfig Sun Mar 4 14:30:18 2001 @@ -285,10 +285,8 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y -CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y -CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -CONFIG_AIC7XXX_PROC_STATS=y -CONFIG_AIC7XXX_RESET_DELAY=5 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +CONFIG_AIC7XXX_RESET_DELAY=5000 # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.4.2/linux/arch/alpha/kernel/alpha_ksyms.c Wed Feb 21 18:20:09 2001 +++ linux/arch/alpha/kernel/alpha_ksyms.c Fri Mar 2 11:15:47 2001 @@ -235,3 +235,4 @@ EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL(get_wchan); +EXPORT_SYMBOL(flush_tlb_page); diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/console.c linux/arch/alpha/kernel/console.c --- v2.4.2/linux/arch/alpha/kernel/console.c Mon Jun 19 17:59:32 2000 +++ linux/arch/alpha/kernel/console.c Fri Mar 2 11:12:07 2001 @@ -21,8 +21,8 @@ unsigned long __vga_hose_io_base = 0; /* base for default hose */ unsigned long __vga_hose_mem_base = 0; /* base for default hose */ -static struct pci_controler * __init -default_vga_hose_select(struct pci_controler *h1, struct pci_controler *h2) +static struct pci_controller * __init +default_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2) { if (h2->index < h1->index) return h2; @@ -31,7 +31,7 @@ } void __init -set_vga_hose(struct pci_controler *hose) +set_vga_hose(struct pci_controller *hose) { if (hose) { __vga_hose_io_base = hose->io_space->start; @@ -42,7 +42,7 @@ void __init locate_and_init_vga(void *(*sel_func)(void *, void *)) { - struct pci_controler *hose = NULL; + struct pci_controller *hose = NULL; struct pci_dev *dev = NULL; if (!sel_func) sel_func = (void *)default_vga_hose_select; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c --- v2.4.2/linux/arch/alpha/kernel/core_apecs.c Tue Mar 21 10:46:21 2000 +++ linux/arch/alpha/kernel/core_apecs.c Fri Mar 2 11:12:07 2001 @@ -357,7 +357,7 @@ }; void -apecs_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +apecs_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { wmb(); *(vip)APECS_IOC_TBIA = 0; @@ -367,13 +367,13 @@ void __init apecs_init_arch(void) { - struct pci_controler *hose; + struct pci_controller *hose; /* * Create our single hose. */ - pci_isa_hose = hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controller(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->index = 0; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c --- v2.4.2/linux/arch/alpha/kernel/core_cia.c Mon Dec 11 13:46:26 2000 +++ linux/arch/alpha/kernel/core_cia.c Fri Mar 2 11:12:07 2001 @@ -299,7 +299,7 @@ */ void -cia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +cia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { wmb(); *(vip)CIA_IOC_PCI_TBIA = 3; /* Flush all locked and unlocked. */ @@ -314,7 +314,7 @@ */ static void -cia_pci_tbi_try1(struct pci_controler *hose, +cia_pci_tbi_try1(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { wmb(); @@ -359,7 +359,7 @@ } static void -cia_pci_tbi_try2(struct pci_controler *hose, +cia_pci_tbi_try2(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { unsigned long flags; @@ -595,7 +595,7 @@ static void __init do_init_arch(int is_pyxis) { - struct pci_controler *hose; + struct pci_controller *hose; int temp; int cia_rev; @@ -628,7 +628,7 @@ *(vip)CIA_IOC_HAE_IO = 0; /* For PYXIS, we always use BWX bus and i/o accesses. To that end, - make sure they're enabled on the controler. */ + make sure they're enabled on the controller. */ if (is_pyxis) { temp = *(vip)CIA_IOC_CIA_CNFG; temp |= CIA_CNFG_IOA_BWEN; @@ -643,7 +643,7 @@ * Create our single hose. */ - pci_isa_hose = hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controller(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->index = 0; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_irongate.c linux/arch/alpha/kernel/core_irongate.c --- v2.4.2/linux/arch/alpha/kernel/core_irongate.c Mon Aug 28 21:21:57 2000 +++ linux/arch/alpha/kernel/core_irongate.c Fri Mar 2 11:12:07 2001 @@ -367,7 +367,7 @@ void __init irongate_init_arch(void) { - struct pci_controler *hose; + struct pci_controller *hose; IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100; irongate_pci_clr_err(); @@ -377,7 +377,7 @@ * Create our single hose. */ - pci_isa_hose = hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controller(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->index = 0; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c --- v2.4.2/linux/arch/alpha/kernel/core_lca.c Tue Mar 21 10:46:21 2000 +++ linux/arch/alpha/kernel/core_lca.c Fri Mar 2 11:12:07 2001 @@ -279,7 +279,7 @@ }; void -lca_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +lca_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { wmb(); *(vip)LCA_IOC_TBIA = 0; @@ -289,13 +289,13 @@ void __init lca_init_arch(void) { - struct pci_controler *hose; + struct pci_controller *hose; /* * Create our single hose. */ - pci_isa_hose = hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controller(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->index = 0; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.4.2/linux/arch/alpha/kernel/core_mcpcia.c Wed Jun 21 22:30:59 2000 +++ linux/arch/alpha/kernel/core_mcpcia.c Fri Mar 2 11:12:07 2001 @@ -89,7 +89,7 @@ static unsigned int conf_read(unsigned long addr, unsigned char type1, - struct pci_controler *hose) + struct pci_controller *hose) { unsigned long flags; unsigned long mid = MCPCIA_HOSE2MID(hose->index); @@ -137,7 +137,7 @@ static void conf_write(unsigned long addr, unsigned int value, unsigned char type1, - struct pci_controler *hose) + struct pci_controller *hose) { unsigned long flags; unsigned long mid = MCPCIA_HOSE2MID(hose->index); @@ -171,7 +171,7 @@ } static int -mk_conf_addr(struct pci_dev *dev, int where, struct pci_controler *hose, +mk_conf_addr(struct pci_dev *dev, int where, struct pci_controller *hose, unsigned long *pci_addr, unsigned char *type1) { u8 bus = dev->bus->number; @@ -199,7 +199,7 @@ static int mcpcia_read_config_byte(struct pci_dev *dev, int where, u8 *value) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; unsigned long addr, w; unsigned char type1; @@ -215,7 +215,7 @@ static int mcpcia_read_config_word(struct pci_dev *dev, int where, u16 *value) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; unsigned long addr, w; unsigned char type1; @@ -231,7 +231,7 @@ static int mcpcia_read_config_dword(struct pci_dev *dev, int where, u32 *value) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; unsigned long addr; unsigned char type1; @@ -246,7 +246,7 @@ static int mcpcia_write_config(struct pci_dev *dev, int where, u32 value, long mask) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; unsigned long addr; unsigned char type1; @@ -288,7 +288,7 @@ }; void -mcpcia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +mcpcia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { wmb(); *(vuip)MCPCIA_SG_TBIA(MCPCIA_HOSE2MID(hose->index)) = 0; @@ -333,11 +333,11 @@ static void __init mcpcia_new_hose(int h) { - struct pci_controler *hose; + struct pci_controller *hose; struct resource *io, *mem, *hae_mem; int mid = MCPCIA_HOSE2MID(h); - hose = alloc_pci_controler(); + hose = alloc_pci_controller(); if (h == 0) pci_isa_hose = hose; io = alloc_resource(); @@ -386,7 +386,7 @@ } static void __init -mcpcia_startup_hose(struct pci_controler *hose) +mcpcia_startup_hose(struct pci_controller *hose) { int mid = MCPCIA_HOSE2MID(hose->index); unsigned int tmp; @@ -464,7 +464,7 @@ void __init mcpcia_init_hoses(void) { - struct pci_controler *hose; + struct pci_controller *hose; int hose_count; int h; @@ -561,7 +561,7 @@ mcpcia_print_system_area(unsigned long la_ptr) { struct el_common *frame; - struct pci_controler *hose; + struct pci_controller *hose; struct IOD_subpacket { unsigned long base; @@ -638,7 +638,7 @@ { /* FIXME: how do we figure out which hose the error was on? */ - struct pci_controler *hose; + struct pci_controller *hose; for (hose = hose_head; hose; hose = hose->next) mcpcia_pci_clr_err(MCPCIA_HOSE2MID(hose->index)); break; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_polaris.c linux/arch/alpha/kernel/core_polaris.c --- v2.4.2/linux/arch/alpha/kernel/core_polaris.c Tue Mar 21 10:46:21 2000 +++ linux/arch/alpha/kernel/core_polaris.c Fri Mar 2 11:12:07 2001 @@ -178,7 +178,7 @@ void __init polaris_init_arch(void) { - struct pci_controler *hose; + struct pci_controller *hose; /* May need to initialize error reporting (see PCICTL0/1), but * for now assume that the firmware has done the right thing @@ -192,7 +192,7 @@ * Create our single hose. */ - pci_isa_hose = hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controller(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->index = 0; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c --- v2.4.2/linux/arch/alpha/kernel/core_t2.c Tue Mar 21 10:46:21 2000 +++ linux/arch/alpha/kernel/core_t2.c Fri Mar 2 11:12:07 2001 @@ -324,7 +324,7 @@ void __init t2_init_arch(void) { - struct pci_controler *hose; + struct pci_controller *hose; unsigned int i; for (i = 0; i < NR_CPUS; i++) { @@ -384,7 +384,7 @@ * Create our single hose. */ - pci_isa_hose = hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controller(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->index = 0; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_titan.c linux/arch/alpha/kernel/core_titan.c --- v2.4.2/linux/arch/alpha/kernel/core_titan.c Tue Jul 18 22:58:28 2000 +++ linux/arch/alpha/kernel/core_titan.c Fri Mar 2 11:12:07 2001 @@ -83,7 +83,7 @@ mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; unsigned long addr; u8 bus = dev->bus->number; u8 device_fn = dev->devfn; @@ -200,7 +200,7 @@ void -titan_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +titan_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { titan_pachip *pachip = (hose->index & 1) ? TITAN_pachip1 : TITAN_pachip0; @@ -243,7 +243,7 @@ } static void __init -titan_init_agp(titan_pachip_port *port, struct pci_controler *hose) +titan_init_agp(titan_pachip_port *port, struct pci_controller *hose) { union TPAchipPCTL pctl; @@ -276,9 +276,9 @@ static void __init titan_init_one_pachip_port(titan_pachip_port *port, int index) { - struct pci_controler *hose; + struct pci_controller *hose; - hose = alloc_pci_controler(); + hose = alloc_pci_controller(); if (index == 0) pci_isa_hose = hose; hose->io_space = alloc_resource(); diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.4.2/linux/arch/alpha/kernel/core_tsunami.c Mon Jun 19 17:59:32 2000 +++ linux/arch/alpha/kernel/core_tsunami.c Fri Mar 2 11:12:07 2001 @@ -90,7 +90,7 @@ mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; unsigned long addr; u8 bus = dev->bus->number; u8 device_fn = dev->devfn; @@ -206,7 +206,7 @@ }; void -tsunami_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +tsunami_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { tsunami_pchip *pchip = hose->index ? TSUNAMI_pchip1 : TSUNAMI_pchip0; volatile unsigned long *csr; @@ -280,12 +280,12 @@ static void __init tsunami_init_one_pchip(tsunami_pchip *pchip, int index) { - struct pci_controler *hose; + struct pci_controller *hose; if (tsunami_probe_read(&pchip->pctl.csr) == 0) return; - hose = alloc_pci_controler(); + hose = alloc_pci_controller(); if (index == 0) pci_isa_hose = hose; hose->io_space = alloc_resource(); diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_wildfire.c linux/arch/alpha/kernel/core_wildfire.c --- v2.4.2/linux/arch/alpha/kernel/core_wildfire.c Mon Jun 19 17:59:32 2000 +++ linux/arch/alpha/kernel/core_wildfire.c Fri Mar 2 11:12:07 2001 @@ -64,10 +64,10 @@ void __init wildfire_init_hose(int qbbno, int hoseno) { - struct pci_controler *hose; + struct pci_controller *hose; wildfire_pci *pci; - hose = alloc_pci_controler(); + hose = alloc_pci_controller(); hose->io_space = alloc_resource(); hose->mem_space = alloc_resource(); @@ -346,7 +346,7 @@ } void -wildfire_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) +wildfire_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { int qbbno = hose->index >> 3; int hoseno = hose->index & 7; @@ -360,7 +360,7 @@ mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, unsigned char *type1) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; unsigned long addr; u8 bus = dev->bus->number; u8 device_fn = dev->devfn; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/pci-noop.c linux/arch/alpha/kernel/pci-noop.c --- v2.4.2/linux/arch/alpha/kernel/pci-noop.c Wed Feb 21 18:20:10 2001 +++ linux/arch/alpha/kernel/pci-noop.c Fri Mar 2 11:12:07 2001 @@ -14,17 +14,17 @@ /* - * The PCI controler list. + * The PCI controller list. */ -struct pci_controler *hose_head, **hose_tail = &hose_head; -struct pci_controler *pci_isa_hose; +struct pci_controller *hose_head, **hose_tail = &hose_head; +struct pci_controller *pci_isa_hose; -struct pci_controler * __init -alloc_pci_controler(void) +struct pci_controller * __init +alloc_pci_controller(void) { - struct pci_controler *hose; + struct pci_controller *hose; hose = alloc_bootmem(sizeof(*hose)); @@ -47,7 +47,7 @@ asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) { - struct pci_controler *hose; + struct pci_controller *hose; struct pci_dev *dev; /* from hose or from bus.devfn */ diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.4.2/linux/arch/alpha/kernel/pci.c Mon Dec 11 13:46:26 2000 +++ linux/arch/alpha/kernel/pci.c Fri Mar 2 11:12:07 2001 @@ -43,11 +43,11 @@ /* - * The PCI controler list. + * The PCI controller list. */ -struct pci_controler *hose_head, **hose_tail = &hose_head; -struct pci_controler *pci_isa_hose; +struct pci_controller *hose_head, **hose_tail = &hose_head; +struct pci_controller *pci_isa_hose; /* * Quirks. @@ -136,7 +136,7 @@ pcibios_align_resource(void *data, struct resource *res, unsigned long size) { struct pci_dev *dev = data; - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; unsigned long alignto; unsigned long start = res->start; @@ -224,7 +224,7 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus) { /* Update device resources. */ - struct pci_controler *hose = (struct pci_controler *)bus->sysdata; + struct pci_controller *hose = (struct pci_controller *)bus->sysdata; int i; for (i = 0; i < PCI_NUM_RESOURCES; i++) { @@ -244,7 +244,7 @@ { /* Propogate hose info into the subordinate devices. */ - struct pci_controler *hose = bus->sysdata; + struct pci_controller *hose = bus->sysdata; struct list_head *ln; struct pci_dev *dev = bus->self; @@ -284,7 +284,7 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; int where; u32 reg; @@ -328,7 +328,7 @@ u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; if (dev->bus->number != hose->first_busno) { u8 pin = *pinp; @@ -349,7 +349,7 @@ pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) { - struct pci_controler *hose = (struct pci_controler *)bus->sysdata; + struct pci_controller *hose = (struct pci_controller *)bus->sysdata; ranges->io_start -= hose->io_space->start; ranges->io_end -= hose->io_space->start; @@ -383,11 +383,11 @@ void __init common_init_pci(void) { - struct pci_controler *hose; + struct pci_controller *hose; struct pci_bus *bus; int next_busno; - /* Scan all of the recorded PCI controlers. */ + /* Scan all of the recorded PCI controllers. */ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { hose->first_busno = next_busno; hose->last_busno = 0xff; @@ -402,10 +402,10 @@ } -struct pci_controler * __init -alloc_pci_controler(void) +struct pci_controller * __init +alloc_pci_controller(void) { - struct pci_controler *hose; + struct pci_controller *hose; hose = alloc_bootmem(sizeof(*hose)); @@ -432,7 +432,7 @@ asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) { - struct pci_controler *hose; + struct pci_controller *hose; struct pci_dev *dev; /* from hose or from bus.devfn */ diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h --- v2.4.2/linux/arch/alpha/kernel/pci_impl.h Thu Mar 16 14:08:32 2000 +++ linux/arch/alpha/kernel/pci_impl.h Fri Mar 2 11:12:07 2001 @@ -6,7 +6,7 @@ */ struct pci_dev; -struct pci_controler; +struct pci_controller; struct pci_iommu_arena; /* @@ -133,7 +133,7 @@ struct pci_iommu_arena { spinlock_t lock; - struct pci_controler *hose; + struct pci_controller *hose; unsigned long *ptes; dma_addr_t dma_base; unsigned int size; @@ -143,15 +143,15 @@ /* The hose list. */ -extern struct pci_controler *hose_head, **hose_tail; -extern struct pci_controler *pci_isa_hose; +extern struct pci_controller *hose_head, **hose_tail; +extern struct pci_controller *pci_isa_hose; extern void common_init_pci(void); extern u8 common_swizzle(struct pci_dev *, u8 *); -extern struct pci_controler *alloc_pci_controler(void); +extern struct pci_controller *alloc_pci_controller(void); extern struct resource *alloc_resource(void); -extern struct pci_iommu_arena *iommu_arena_new(struct pci_controler *, +extern struct pci_iommu_arena *iommu_arena_new(struct pci_controller *, dma_addr_t, unsigned long, unsigned long); extern long iommu_arena_alloc(struct pci_iommu_arena *arena, long n); diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- v2.4.2/linux/arch/alpha/kernel/pci_iommu.c Mon Dec 11 13:46:26 2000 +++ linux/arch/alpha/kernel/pci_iommu.c Fri Mar 2 11:12:07 2001 @@ -43,7 +43,7 @@ } struct pci_iommu_arena * -iommu_arena_new(struct pci_controler *hose, dma_addr_t base, +iommu_arena_new(struct pci_controller *hose, dma_addr_t base, unsigned long window_size, unsigned long align) { unsigned long mem_size; @@ -147,7 +147,7 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction) { - struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose; + struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose; dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff; struct pci_iommu_arena *arena; long npages, dma_ofs, i; @@ -215,7 +215,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction) { - struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose; + struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose; struct pci_iommu_arena *arena; long dma_ofs, npages; @@ -454,7 +454,7 @@ int direction) { struct scatterlist *start, *end, *out; - struct pci_controler *hose; + struct pci_controller *hose; struct pci_iommu_arena *arena; dma_addr_t max_dma; @@ -528,7 +528,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) { - struct pci_controler *hose; + struct pci_controller *hose; struct pci_iommu_arena *arena; struct scatterlist *end; dma_addr_t max_dma; @@ -596,7 +596,7 @@ int pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask) { - struct pci_controler *hose; + struct pci_controller *hose; struct pci_iommu_arena *arena; #if !DEBUG_NODIRECT diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.4.2/linux/arch/alpha/kernel/proto.h Mon Jun 19 17:59:32 2000 +++ linux/arch/alpha/kernel/proto.h Fri Mar 2 11:12:07 2001 @@ -10,14 +10,14 @@ struct pt_regs; struct task_struct; struct pci_dev; -struct pci_controler; +struct pci_controller; /* core_apecs.c */ extern struct pci_ops apecs_pci_ops; extern void apecs_init_arch(void); extern void apecs_pci_clr_err(void); extern void apecs_machine_check(u64, u64, struct pt_regs *); -extern void apecs_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +extern void apecs_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_cia.c */ extern struct pci_ops cia_pci_ops; @@ -25,7 +25,7 @@ extern void cia_init_arch(void); extern void pyxis_init_arch(void); extern void cia_machine_check(u64, u64, struct pt_regs *); -extern void cia_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_irongate.c */ extern struct pci_ops irongate_pci_ops; @@ -38,14 +38,14 @@ extern struct pci_ops lca_pci_ops; extern void lca_init_arch(void); extern void lca_machine_check(u64, u64, struct pt_regs *); -extern void lca_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_mcpcia.c */ extern struct pci_ops mcpcia_pci_ops; extern void mcpcia_init_arch(void); extern void mcpcia_init_hoses(void); extern void mcpcia_machine_check(u64, u64, struct pt_regs *); -extern void mcpcia_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +extern void mcpcia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_polaris.c */ extern struct pci_ops polaris_pci_ops; @@ -66,21 +66,21 @@ extern void titan_init_arch(void); extern void titan_kill_arch(int); extern void titan_machine_check(u64, u64, struct pt_regs *); -extern void titan_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +extern void titan_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_tsunami.c */ extern struct pci_ops tsunami_pci_ops; extern void tsunami_init_arch(void); extern void tsunami_kill_arch(int); extern void tsunami_machine_check(u64, u64, struct pt_regs *); -extern void tsunami_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +extern void tsunami_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* core_wildfire.c */ extern struct pci_ops wildfire_pci_ops; extern void wildfire_init_arch(void); extern void wildfire_kill_arch(int); extern void wildfire_machine_check(u64, u64, struct pt_regs *); -extern void wildfire_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t); +extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); /* setup.c */ extern unsigned long srm_hae; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.4.2/linux/arch/alpha/kernel/setup.c Wed Feb 21 18:20:10 2001 +++ linux/arch/alpha/kernel/setup.c Fri Mar 2 11:12:07 2001 @@ -201,7 +201,7 @@ long i; if (hose_head) { - struct pci_controler *hose; + struct pci_controller *hose; for (hose = hose_head; hose; hose = hose->next) if (hose->index == 0) { io = hose->io_space; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c --- v2.4.2/linux/arch/alpha/kernel/sys_dp264.c Fri Oct 27 10:55:01 2000 +++ linux/arch/alpha/kernel/sys_dp264.c Fri Mar 2 11:12:07 2001 @@ -404,13 +404,13 @@ }; const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5; - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; if (irq > 0) { irq += 16 * hose->index; } else { - /* ??? The Contaq IDE controler on the ISA bridge uses + /* ??? The Contaq IDE controller on the ISA bridge uses "legacy" interrupts 14 and 15. I don't know if anything can wind up at the same slot+pin on hose1, so we'll just have to trust whatever value the console might @@ -455,7 +455,7 @@ static u8 __init monet_swizzle(struct pci_dev *dev, u8 *pinp) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; int slot, pin = *pinp; if (hose->first_busno == dev->bus->number) { @@ -521,7 +521,7 @@ }; const long min_idsel = 1, max_idsel = 7, irqs_per_slot = 5; - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; if (irq > 0) diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_eiger.c linux/arch/alpha/kernel/sys_eiger.c --- v2.4.2/linux/arch/alpha/kernel/sys_eiger.c Thu Mar 16 14:07:09 2000 +++ linux/arch/alpha/kernel/sys_eiger.c Fri Mar 2 11:12:07 2001 @@ -177,7 +177,7 @@ static u8 __init eiger_swizzle(struct pci_dev *dev, u8 *pinp) { - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; int slot, pin = *pinp; int bridge_count = 0; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c --- v2.4.2/linux/arch/alpha/kernel/sys_jensen.c Tue Mar 21 10:46:21 2000 +++ linux/arch/alpha/kernel/sys_jensen.c Fri Mar 2 11:12:07 2001 @@ -124,12 +124,12 @@ static void __init jensen_init_arch(void) { - struct pci_controler *hose; + struct pci_controller *hose; /* Create a hose so that we can report i/o base addresses to userland. */ - pci_isa_hose = hose = alloc_pci_controler(); + pci_isa_hose = hose = alloc_pci_controller(); hose->io_space = &ioport_resource; hose->mem_space = &iomem_resource; hose->index = 0; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c --- v2.4.2/linux/arch/alpha/kernel/sys_rawhide.c Fri Oct 27 10:55:01 2000 +++ linux/arch/alpha/kernel/sys_rawhide.c Fri Mar 2 11:12:07 2001 @@ -139,7 +139,7 @@ static void __init rawhide_init_irq(void) { - struct pci_controler *hose; + struct pci_controller *hose; long i; mcpcia_init_hoses(); @@ -204,7 +204,7 @@ }; const long min_idsel = 1, max_idsel = 5, irqs_per_slot = 5; - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; if (irq >= 0) irq += 24 * hose->index; diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_titan.c linux/arch/alpha/kernel/sys_titan.c --- v2.4.2/linux/arch/alpha/kernel/sys_titan.c Mon Jun 19 17:59:32 2000 +++ linux/arch/alpha/kernel/sys_titan.c Fri Mar 2 11:12:07 2001 @@ -321,10 +321,10 @@ } #ifdef CONFIG_VGA_HOSE -static struct pci_controler * __init -privateer_vga_hose_select(struct pci_controler *h1, struct pci_controler *h2) +static struct pci_controller * __init +privateer_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2) { - struct pci_controler *hose = h1; + struct pci_controller *hose = h1; int agp1, agp2; /* which hose(s) are agp? */ diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_wildfire.c linux/arch/alpha/kernel/sys_wildfire.c --- v2.4.2/linux/arch/alpha/kernel/sys_wildfire.c Mon Oct 30 12:24:22 2000 +++ linux/arch/alpha/kernel/sys_wildfire.c Fri Mar 2 11:12:07 2001 @@ -315,7 +315,7 @@ }; const long min_idsel = 0, max_idsel = 7, irqs_per_slot = 5; - struct pci_controler *hose = dev->sysdata; + struct pci_controller *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; if (irq > 0) { diff -u --recursive --new-file v2.4.2/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S --- v2.4.2/linux/arch/arm/kernel/entry-armo.S Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/kernel/entry-armo.S Tue Mar 6 19:44:35 2001 @@ -29,13 +29,12 @@ #include #include +#include #include #include -#include "../lib/constants.h" - .macro zero_fp -#ifdef CONFIG_FRAME_POINTER +#ifndef CONFIG_NO_FRAME_POINTER mov fp, #0 #endif .endm diff -u --recursive --new-file v2.4.2/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.4.2/linux/arch/arm/kernel/entry-armv.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/kernel/entry-armv.S Tue Mar 6 19:44:35 2001 @@ -17,19 +17,19 @@ #include #include +#include #include #include #include #include -#include "../lib/constants.h" #ifndef MODE_SVC #define MODE_SVC 0x13 #endif .macro zero_fp -#ifdef CONFIG_FRAME_POINTER +#ifndef CONFIG_NO_FRAME_POINTER mov fp, #0 #endif .endm @@ -611,9 +611,9 @@ #else wfs_mask_data: .word 0x0e200110 @ WFS/RFS .word 0x0fef0fff - .word 0x0d0d0100 @ LDF [sp]/STF [sp] - .word 0x0d0b0100 @ LDF [fp]/STF [fp] - .word 0x0f0f0f00 + .word 0x0d000100 @ LDF [sp]/STF [sp] + .word 0x0d000100 @ LDF [fp]/STF [fp] + .word 0x0f000f00 /* We get here if an undefined instruction happens and the floating * point emulator is not present. If the offending instruction was diff -u --recursive --new-file v2.4.2/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.4.2/linux/arch/arm/kernel/entry-common.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/entry-common.S Tue Mar 6 19:44:35 2001 @@ -215,7 +215,7 @@ sys_mmap2: #if PAGE_SHIFT > 12 tst r5, #PGOFF_MASK - moveq r5, r5, lsr #PGOFF_SHIFT + moveq r5, r5, lsr #PAGE_SHIFT - 12 streq r5, [sp, #4] beq do_mmap2 mov r0, #-EINVAL diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.4.2/linux/arch/arm/lib/Makefile Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/lib/Makefile Tue Mar 6 19:44:35 2001 @@ -54,9 +54,3 @@ endif include $(TOPDIR)/Rules.make - -constants.h: getconsdata.o extractconstants.pl - $(PERL) extractconstants.pl $(OBJDUMP) > $@ - -getconsdata.o: getconsdata.c - $(CC) $(CFLAGS) -c getconsdata.c diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/copy_page.S linux/arch/arm/lib/copy_page.S --- v2.4.2/linux/arch/arm/lib/copy_page.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/copy_page.S Tue Mar 6 19:44:35 2001 @@ -11,7 +11,7 @@ */ #include #include -#include "constants.h" +#include .text .align 5 diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/csumpartialcopyuser.S linux/arch/arm/lib/csumpartialcopyuser.S --- v2.4.2/linux/arch/arm/lib/csumpartialcopyuser.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/csumpartialcopyuser.S Tue Mar 6 19:44:35 2001 @@ -11,7 +11,7 @@ #include #include #include -#include "constants.h" +#include .text diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/extractconstants.pl linux/arch/arm/lib/extractconstants.pl --- v2.4.2/linux/arch/arm/lib/extractconstants.pl Sat Jul 18 11:55:23 1998 +++ linux/arch/arm/lib/extractconstants.pl Wed Dec 31 16:00:00 1969 @@ -1,46 +0,0 @@ -#!/usr/bin/perl - -$OBJDUMP=$ARGV[0]; - -sub swapdata { - local ($num) = @_; - - return substr($num, 6, 2).substr($num, 4, 2).substr ($num, 2, 2).substr ($num, 0, 2); -} - -open (DATA, $OBJDUMP.' --full-contents --section=.data getconsdata.o | grep \'^ 00\' |') || - die ('Cant objdump!'); -while () { - ($addr, $data0, $data1, $data2, $data3) = split (' '); - $dat[hex($addr)] = hex(&swapdata($data0)); - $dat[hex($addr)+4] = hex(&swapdata($data1)); - $dat[hex($addr)+8] = hex(&swapdata($data2)); - $dat[hex($addr)+12] = hex(&swapdata($data3)); -} -close (DATA); - -open (DATA, $OBJDUMP.' --syms getconsdata.o |') || die ('Cant objdump!'); -while () { - /elf32/ && ( $elf = 1 ); - /a.out/ && ( $aout = 1 ); - next if ($aout && ! / 07 /); - next if ($elf && ! (/^0*0...... g/ && /.data/)); - next if (!$aout && !$elf); - - if ($aout) { - ($addr, $flags, $sect, $a1, $a2, $a3, $name) = split (' '); - $nam[hex($addr)] = substr($name, 1); - } - if ($elf) { - chomp; - $addr = substr ($_, 0, index($_, " ")); - $name = substr ($_, rindex($_, " ") + 1); - $nam[hex($addr)] = $name; - } -} -close (DATA); - -print "/*\n * *** This file is automatically generated from getconsdata.c. Do not edit! ***\n */\n"; -for ($i = 0; $i < hex($addr)+4; $i += 4) { - print "#define $nam[$i] $dat[$i]\n"; -} diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c --- v2.4.2/linux/arch/arm/lib/getconsdata.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/getconsdata.c Wed Dec 31 16:00:00 1969 @@ -1,95 +0,0 @@ -/* - * linux/arch/arm/lib/getconsdata.c - * - * Copyright (C) 1995-2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include - -#include -#include - -/* - * Make sure that the compiler and target are compatible - */ -#if (defined(__APCS_32__) && defined(CONFIG_CPU_26)) -#error Your compiler targets APCS-32 but this kernel requires APCS-26. -#endif -#if (defined(__APCS_26__) && defined(CONFIG_CPU_32)) -#error Your compiler targets APCS-26 but this kernel requires APCS-32. -#endif - -#undef PAGE_READONLY - -#define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) -#define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n) - -unsigned long TSK_SIGPENDING = OFF_TSK(sigpending); -unsigned long TSK_ADDR_LIMIT = OFF_TSK(addr_limit); -unsigned long TSK_NEED_RESCHED = OFF_TSK(need_resched); -unsigned long TSK_PTRACE = OFF_TSK(ptrace); -unsigned long TSK_USED_MATH = OFF_TSK(used_math); - -unsigned long TSS_SAVE = OFF_TSK(thread.save); -unsigned long TSS_FPESAVE = OFF_TSK(thread.fpstate.soft.save); -#ifdef CONFIG_CPU_32 -unsigned long TSS_DOMAIN = OFF_TSK(thread.domain); -#endif - -#ifdef _PAGE_PRESENT -unsigned long PAGE_PRESENT = _PAGE_PRESENT; -#endif -#ifdef _PAGE_RW -unsigned long PAGE_RW = _PAGE_RW; -#endif -#ifdef _PAGE_USER -unsigned long PAGE_USER = _PAGE_USER; -#endif -#ifdef _PAGE_ACCESSED -unsigned long PAGE_ACCESSED = _PAGE_ACCESSED; -#endif -#ifdef _PAGE_DIRTY -unsigned long PAGE_DIRTY = _PAGE_DIRTY; -#endif -#ifdef _PAGE_READONLY -unsigned long PAGE_READONLY = _PAGE_READONLY; -#endif -#ifdef _PAGE_NOT_USER -unsigned long PAGE_NOT_USER = _PAGE_NOT_USER; -#endif -#ifdef _PAGE_OLD -unsigned long PAGE_OLD = _PAGE_OLD; -#endif -#ifdef _PAGE_CLEAN -unsigned long PAGE_CLEAN = _PAGE_CLEAN; -#endif - -#ifdef PTE_TYPE_SMALL -unsigned long HPTE_TYPE_SMALL = PTE_TYPE_SMALL; -unsigned long HPTE_AP_READ = PTE_AP_READ; -unsigned long HPTE_AP_WRITE = PTE_AP_WRITE; -#endif - -#ifdef L_PTE_PRESENT -unsigned long LPTE_PRESENT = L_PTE_PRESENT; -unsigned long LPTE_YOUNG = L_PTE_YOUNG; -unsigned long LPTE_BUFFERABLE = L_PTE_BUFFERABLE; -unsigned long LPTE_CACHEABLE = L_PTE_CACHEABLE; -unsigned long LPTE_USER = L_PTE_USER; -unsigned long LPTE_WRITE = L_PTE_WRITE; -unsigned long LPTE_EXEC = L_PTE_EXEC; -unsigned long LPTE_DIRTY = L_PTE_DIRTY; -#endif - -unsigned long PAGE_SZ = PAGE_SIZE; - -unsigned long KSWI_BASE = 0x900000; -unsigned long KSWI_SYS_BASE = 0x9f0000; -unsigned long SYS_ERROR0 = 0x9f0000; -unsigned long PGOFF_SHIFT = PAGE_SHIFT - 12; -unsigned long PGOFF_MASK = (1 << (PAGE_SHIFT - 12)) - 1; diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S --- v2.4.2/linux/arch/arm/lib/memcpy.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/lib/memcpy.S Tue Mar 6 19:44:35 2001 @@ -11,7 +11,6 @@ */ #include #include -#include "constants.h" .text diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/Makefile linux/arch/arm/mach-integrator/Makefile --- v2.4.2/linux/arch/arm/mach-integrator/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/Makefile Fri Mar 2 18:38:39 2001 @@ -0,0 +1,24 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +USE_STANDARD_AS_RULE := true + +O_TARGET := integrator.o + +# Object file lists. + +obj-y := arch.o irq.o mm.o time.o +obj-m := +obj-n := +obj- := + +export-objs := leds.o + +obj-$(CONFIG_LEDS) += leds.o +obj-$(CONFIG_PCI) += pci_v3.o pci.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/arch.c linux/arch/arm/mach-integrator/arch.c --- v2.4.2/linux/arch/arm/mach-integrator/arch.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/arch.c Fri Mar 2 18:38:39 2001 @@ -0,0 +1,70 @@ +/* + * linux/arch/arm/mach-integrator/arch.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern void integrator_map_io(void); +extern void integrator_init_irq(void); + +#ifdef CONFIG_KMI_KEYB +static struct kmi_info integrator_keyboard __initdata = { + base: IO_ADDRESS(KMI0_BASE), + irq: IRQ_KMIINT0, + divisor: 24 / 8 - 1, + type: KMI_KEYBOARD, +}; + +static struct kmi_info integrator_mouse __initdata = { + base: IO_ADDRESS(KMI1_BASE), + irq: IRQ_KMIINT1, + divisor: 24 / 8 - 1, + type: KMI_MOUSE, +}; +#endif + +static void __init +integrator_fixup(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ +#ifdef CONFIG_KMI_KEYB + register_kmi(&integrator_keyboard); + register_kmi(&integrator_mouse); +#endif +} + +MACHINE_START(INTEGRATOR, "ARM-Integrator") + MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") + BOOT_MEM(0x00000000, 0x16000000, 0xf1600000) + BOOT_PARAMS(0x00000100) + FIXUP(integrator_fixup) + MAPIO(integrator_map_io) + INITIRQ(integrator_init_irq) +MACHINE_END diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/dma.c linux/arch/arm/mach-integrator/dma.c --- v2.4.2/linux/arch/arm/mach-integrator/dma.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/dma.c Fri Mar 2 18:38:39 2001 @@ -0,0 +1,36 @@ +/* + * linux/arch/arm/mach-integrator/dma.c + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +void __init arch_dma_init(dma_t *dma) +{ +} diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/irq.c linux/arch/arm/mach-integrator/irq.c --- v2.4.2/linux/arch/arm/mach-integrator/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/irq.c Fri Mar 2 18:38:39 2001 @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/mach-integrator/irq.c + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + +#include +#include +#include + +#include + +/* + * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx + * is the (PA >> 12). + * + * Setup a VA for the Integrator interrupt controller (for header #0, + * just for now). + */ +#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) +#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET + +#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) ) + +static void sc_mask_irq(unsigned int irq) +{ + __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR); +} + +static void sc_unmask_irq(unsigned int irq) +{ + __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET); +} + +void __init integrator_init_irq(void) +{ + unsigned int i; + + for (i = 0; i < NR_IRQS; i++) { + if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 1; + irq_desc[i].mask_ack = sc_mask_irq; + irq_desc[i].mask = sc_mask_irq; + irq_desc[i].unmask = sc_unmask_irq; + } + } + + /* Disable all interrupts initially. */ + /* Do the core module ones */ + __raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); + + /* do the header card stuff next */ + __raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); + __raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); +} diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/leds.c linux/arch/arm/mach-integrator/leds.c --- v2.4.2/linux/arch/arm/mach-integrator/leds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/leds.c Fri Mar 2 18:38:39 2001 @@ -0,0 +1,94 @@ +/* + * linux/arch/arm/mach-integrator/leds.c + * + * Integrator LED control routines + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#include +#include +#include +#include +#include + +static int saved_leds; + +static void integrator_leds_event(led_event_t ledevt) +{ + unsigned long flags; + const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE); + const unsigned int hdr_ctrl = IO_ADDRESS(INTEGRATOR_HDR_BASE) + + INTEGRATOR_HDR_CTRL_OFFSET; + unsigned int ctrl; + unsigned int update_alpha_leds; + + // yup, change the LEDs + local_irq_save(flags); + update_alpha_leds = 0; + + switch(ledevt) { + case led_idle_start: + ctrl = __raw_readl(hdr_ctrl); + ctrl &= ~INTEGRATOR_HDR_CTRL_LED; + __raw_writel(ctrl, hdr_ctrl); + break; + + case led_idle_end: + ctrl = __raw_readl(hdr_ctrl); + ctrl |= INTEGRATOR_HDR_CTRL_LED; + __raw_writel(ctrl, hdr_ctrl); + break; + + case led_timer: + saved_leds ^= GREEN_LED; + update_alpha_leds = 1; + break; + + case led_red_on: + saved_leds |= RED_LED; + update_alpha_leds = 1; + break; + + case led_red_off: + saved_leds &= ~RED_LED; + update_alpha_leds = 1; + break; + + default: + break; + } + + if (update_alpha_leds) { + while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1); + __raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET); + } + local_irq_restore(flags); +} + +static int __init leds_init(void) +{ + if (machine_is_integrator()) + leds_event = integrator_leds_event; + + return 0; +} + +__initcall(leds_init); diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/mm.c linux/arch/arm/mach-integrator/mm.c --- v2.4.2/linux/arch/arm/mach-integrator/mm.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/mm.c Fri Mar 2 18:38:39 2001 @@ -0,0 +1,78 @@ +/* + * linux/arch/arm/mach-integrator/mm.c + * + * Extra MM routines for the ARM Integrator board + * + * Copyright (C) 1999,2000 Arm Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* + * Logical Physical + * e8000000 40000000 PCI memory + * ec000000 62000000 PCI config space + * ed000000 61000000 PCI V3 regs + * ee000000 60000000 PCI IO + * ef000000 Cache flush + * f1000000 10000000 Core module registers + * f1100000 11000000 System controller registers + * f1200000 12000000 EBI registers + * f1300000 13000000 Counter/Timer + * f1400000 14000000 Interrupt controller + * f1500000 15000000 RTC + * f1600000 16000000 UART 0 + * f1700000 17000000 UART 1 + * f1800000 18000000 Keyboard + * f1900000 19000000 Mouse + * f1a00000 1a000000 Debug LEDs + * f1b00000 1b000000 GPIO + */ + +static struct map_desc integrator_io_desc[] __initdata = { + { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_RTC_BASE), INTEGRATOR_RTC_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_KBD_BASE), INTEGRATOR_KBD_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_MOUSE_BASE), INTEGRATOR_MOUSE_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K , DOMAIN_IO, 0, 1}, + { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M , DOMAIN_IO, 0, 1}, + { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M , DOMAIN_IO, 0, 1}, + { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_512K , DOMAIN_IO, 0, 1}, + { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K , DOMAIN_IO, 0, 1}, + LAST_DESC +}; + +void __init integrator_map_io(void) +{ + iotable_init(integrator_io_desc); +} diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/pci.c linux/arch/arm/mach-integrator/pci.c --- v2.4.2/linux/arch/arm/mach-integrator/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/pci.c Fri Mar 2 18:38:39 2001 @@ -0,0 +1,119 @@ +/* + * linux/arch/arm/mach-integrator/pci-integrator.c + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * PCI functions for Integrator + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * A small note about bridges and interrupts. The DECchip 21050 (and + * later) adheres to the PCI-PCI bridge specification. This says that + * the interrupts on the other side of a bridge are swizzled in the + * following manner: + * + * Dev Interrupt Interrupt + * Pin on Pin on + * Device Connector + * + * 4 A A + * B B + * C C + * D D + * + * 5 A B + * B C + * C D + * D A + * + * 6 A C + * B D + * C A + * D B + * + * 7 A D + * B A + * C B + * D C + * + * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. + * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 + * + * The following code swizzles for exactly one bridge. + */ +static inline int bridge_swizzle(int pin, unsigned int slot) +{ + return (pin + slot) & 3; +} + +/* + * This routine handles multiple bridges. + */ +static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp) +{ + int pin = *pinp; + + if (pin == 0) + pin = 1; + + pin -= 1; + while (dev->bus->self) { + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + /* + * move up the chain of bridges, swizzling as we go. + */ + dev = dev->bus->self; + } + *pinp = pin + 1; + + return PCI_SLOT(dev->devfn); +} + +static int irq_tab[4] __initdata = { + IRQ_PCIINT0, IRQ_PCIINT1, IRQ_PCIINT2, IRQ_PCIINT3 +}; + +/* + * map the specified device/slot/pin to an IRQ. This works out such + * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1. + */ +static int __init integrator_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + int intnr = ((slot - 9) + (pin - 1)) & 3; + + return irq_tab[intnr]; +} + +extern void pci_v3_init(struct arm_pci_sysdata *); + +struct hw_pci integrator_pci __initdata = { + init: pci_v3_init, + swizzle: integrator_swizzle, + map_irq: integrator_map_irq, +}; diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/pci_v3.c linux/arch/arm/mach-integrator/pci_v3.c --- v2.4.2/linux/arch/arm/mach-integrator/pci_v3.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/pci_v3.c Fri Mar 2 18:38:39 2001 @@ -0,0 +1,460 @@ +/* + * linux/arch/arm/mach-integrator/pci_v3.c + * + * PCI functions for V3 host PCI bridge + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* + * The V3 PCI interface chip in Integrator provides several windows from + * local bus memory into the PCI memory areas. Unfortunately, there + * are not really enough windows for our usage, therefore we reuse + * one of the windows for access to PCI configuration space. The + * memory map is as follows: + * + * Local Bus Memory Usage + * + * 40000000 - 4FFFFFFF PCI memory. 256M non-prefetchable + * 50000000 - 5FFFFFFF PCI memory. 256M prefetchable + * 60000000 - 60FFFFFF PCI IO. 16M + * 68000000 - 68FFFFFF PCI Configuration. 16M + * + * There are three V3 windows, each described by a pair of V3 registers. + * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2. + * Base0 and Base1 can be used for any type of PCI memory access. Base2 + * can be used either for PCI I/O or for I20 accesses. By default, uHAL + * uses this only for PCI IO space. + * + * PCI Memory is mapped so that assigned addresses in PCI Memory match + * local bus memory addresses. In other words, if a PCI device is assigned + * address 80200000 then that address is a valid local bus address as well + * as a valid PCI Memory address. PCI IO addresses are mapped to start + * at zero. This means that local bus address 60000000 maps to PCI IO address + * 00000000 and so on. Device driver writers need to be aware of this + * distinction. + * + * Normally these spaces are mapped using the following base registers: + * + * Usage Local Bus Memory Base/Map registers used + * + * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0 + * Mem 50000000 - 5FFFFFFF LB_BASE1/LB_MAP1 + * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2 + * Cfg 68000000 - 68FFFFFF + * + * This means that I20 and PCI configuration space accesses will fail. + * When PCI configuration accesses are needed (via the uHAL PCI + * configuration space primitives) we must remap the spaces as follows: + * + * Usage Local Bus Memory Base/Map registers used + * + * Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0 + * Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0 + * IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2 + * Cfg 68000000 - 68FFFFFF LB_BASE1/LB_MAP1 + * + * To make this work, the code depends on overlapping windows working. + * The V3 chip translates an address by checking its range within + * each of the BASE/MAP pairs in turn (in ascending register number + * order). It will use the first matching pair. So, for example, + * if the same address is mapped by both LB_BASE0/LB_MAP0 and + * LB_BASE1/LB_MAP1, the V3 will use the translation from + * LB_BASE0/LB_MAP0. + * + * To allow PCI Configuration space access, the code enlarges the + * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M. This occludes + * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can + * be remapped for use by configuration cycles. + * + * At the end of the PCI Configuration space accesses, + * LB_BASE1/LB_MAP1 is reset to map PCI Memory. Finally the window + * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to + * reveal the now restored LB_BASE1/LB_MAP1 window. + * + * NOTE: We do not set up I2O mapping. I suspect that this is only + * for an intelligent (target) device. Using I2O disables most of + * the mappings into PCI memory. + */ + +// V3 access routines +#define _V3Write16(o,v) __raw_writew(v, PCI_V3_VADDR + (unsigned int)(o)) +#define _V3Read16(o) (__raw_readw(PCI_V3_VADDR + (unsigned int)(o))) + +#define _V3Write32(o,v) __raw_writel(v, PCI_V3_VADDR + (unsigned int)(o)) +#define _V3Read32(o) (__raw_readl(PCI_V3_VADDR + (unsigned int)(o))) + +/*============================================================================ + * + * routine: uHALir_PCIMakeConfigAddress() + * + * parameters: bus = which bus + * device = which device + * function = which function + * offset = configuration space register we are interested in + * + * description: this routine will generate a platform dependant config + * address. + * + * calls: none + * + * returns: configuration address to play on the PCI bus + * + * To generate the appropriate PCI configuration cycles in the PCI + * configuration address space, you present the V3 with the following pattern + * (which is very nearly a type 1 (except that the lower two bits are 00 and + * not 01). In order for this mapping to work you need to set up one of + * the local to PCI aperatures to 16Mbytes in length translating to + * PCI configuration space starting at 0x0000.0000. + * + * PCI configuration cycles look like this: + * + * Type 0: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:11 Device select bit. + * 10:8 Function number + * 7:2 Register number + * + * Type 1: + * + * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 + * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 31:24 reserved + * 23:16 bus number (8 bits = 128 possible buses) + * 15:11 Device number (5 bits) + * 10:8 function number + * 7:2 register number + * + */ +static spinlock_t v3_lock = SPIN_LOCK_UNLOCKED; + +#define PCI_BUS_NONMEM_START 0x00000000 +#define PCI_BUS_NONMEM_SIZE 0x10000000 + +#define PCI_BUS_PREMEM_START 0x10000000 +#define PCI_BUS_PREMEM_SIZE 0x10000000 + +#if PCI_BUS_NONMEM_START & 0x000fffff +#error PCI_BUS_NONMEM_START must be megabyte aligned +#endif +#if PCI_BUS_PREMEM_START & 0x000fffff +#error PCI_BUS_PREMEM_START must be megabyte aligned +#endif + +static unsigned long v3_open_config_window(struct pci_dev *dev, int offset) +{ + unsigned int address, mapaddress, busnr; + + busnr = dev->bus->number; + + /* + * Trap out illegal values + */ + if (offset > 255) + BUG(); + if (busnr > 255) + BUG(); + if (dev->devfn > 255) + BUG(); + + if (busnr == 0) { + int slot = PCI_SLOT(dev->devfn); + + /* + * local bus segment so need a type 0 config cycle + * + * build the PCI configuration "address" with one-hot in + * A31-A11 + * + * mapaddress: + * 3:1 = config cycle (101) + * 0 = PCI A1 & A0 are 0 (0) + */ + address = PCI_FUNC(dev->devfn) << 8; + mapaddress = 0x0a; + + if (slot > 12) + /* + * high order bits are handled by the MAP register + */ + mapaddress |= 1 << (slot - 4); + else + /* + * low order bits handled directly in the address + */ + address |= 1 << (slot + 11); + } else { + /* + * not the local bus segment so need a type 1 config cycle + * + * address: + * 23:16 = bus number + * 15:11 = slot number (7:3 of devfn) + * 10:8 = func number (2:0 of devfn) + * + * mapaddress: + * 3:1 = config cycle (101) + * 0 = PCI A1 & A0 from host bus (1) + */ + mapaddress = 0x0b; + address = (busnr << 16) | (dev->devfn << 8); + } + + /* + * Set up base0 to see all 512Mbytes of memory space (not prefetchable), this + * frees up base1 for re-use by configuration memory + */ + _V3Write32(V3_LB_BASE0, (PHYS_PCI_MEM_BASE & 0xFFF00000) | 0x90 | V3_LB_BASE_M_ENABLE); + + /* + * Set up base1/map1 to point into configuration space. + */ + _V3Write32(V3_LB_BASE1, (PHYS_PCI_CONFIG_BASE & 0xFFF00000) | 0x40 | V3_LB_BASE_M_ENABLE); + _V3Write16(V3_LB_MAP1, mapaddress); + + return PCI_CONFIG_VADDR + address + offset; +} + +static void v3_close_config_window(void) +{ + /* + * Reassign base1 for use by prefetchable PCI memory + */ + _V3Write32(V3_LB_BASE1, ((PHYS_PCI_MEM_BASE + SZ_256M) & 0xFFF00000) | 0x84 | V3_LB_BASE_M_ENABLE); + _V3Write16(V3_LB_MAP1, ((PCI_BUS_PREMEM_START & 0xFFF00000) >> 16) | 0x0006); + + /* + * And shrink base0 back to a 256M window (NOTE: MAP0 already correct) + */ + _V3Write32(V3_LB_BASE0, (PHYS_PCI_MEM_BASE & 0xFFF00000) | 0x80 | V3_LB_BASE_M_ENABLE); +} + +static int v3_read_config_byte(struct pci_dev *dev, int where, u8 *val) +{ + unsigned long addr; + unsigned long flags; + u8 v; + + spin_lock_irqsave(&v3_lock, flags); + addr = v3_open_config_window(dev, where); + + v = __raw_readb(addr); + + v3_close_config_window(); + spin_unlock_irqrestore(&v3_lock, flags); + + *val = v; + return PCIBIOS_SUCCESSFUL; +} + +static int v3_read_config_word(struct pci_dev *dev, int where, u16 *val) +{ + unsigned long addr; + unsigned long flags; + u16 v; + + spin_lock_irqsave(&v3_lock, flags); + addr = v3_open_config_window(dev, where); + + v = __raw_readw(addr); + + v3_close_config_window(); + spin_unlock_irqrestore(&v3_lock, flags); + + *val = v; + return PCIBIOS_SUCCESSFUL; +} + +static int v3_read_config_dword(struct pci_dev *dev, int where, u32 *val) +{ + unsigned long addr; + unsigned long flags; + u32 v; + + spin_lock_irqsave(&v3_lock, flags); + addr = v3_open_config_window(dev, where); + + v = __raw_readl(addr); + + v3_close_config_window(); + spin_unlock_irqrestore(&v3_lock, flags); + + *val = v; + return PCIBIOS_SUCCESSFUL; +} + +static int v3_write_config_byte(struct pci_dev *dev, int where, u8 val) +{ + unsigned long addr; + unsigned long flags; + + spin_lock_irqsave(&v3_lock, flags); + addr = v3_open_config_window(dev, where); + + __raw_writeb(val, addr); + __raw_readb(addr); + + v3_close_config_window(); + spin_unlock_irqrestore(&v3_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int v3_write_config_word(struct pci_dev *dev, int where, u16 val) +{ + unsigned long addr; + unsigned long flags; + + spin_lock_irqsave(&v3_lock, flags); + addr = v3_open_config_window(dev, where); + + __raw_writew(val, addr); + __raw_readw(addr); + + v3_close_config_window(); + spin_unlock_irqrestore(&v3_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int v3_write_config_dword(struct pci_dev *dev, int where, u32 val) +{ + unsigned long addr; + unsigned long flags; + + spin_lock_irqsave(&v3_lock, flags); + addr = v3_open_config_window(dev, where); + + __raw_writel(val, addr); + __raw_readl(addr); + + v3_close_config_window(); + spin_unlock_irqrestore(&v3_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pci_v3_ops = { + read_byte: v3_read_config_byte, + read_word: v3_read_config_word, + read_dword: v3_read_config_dword, + write_byte: v3_write_config_byte, + write_word: v3_write_config_word, + write_dword: v3_write_config_dword, +}; + +static struct resource non_mem = { + name: "PCI non-prefetchable", + start: PCI_BUS_NONMEM_START, + end: PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1, + flags: IORESOURCE_MEM, +}; + +static struct resource pre_mem = { + name: "PCI prefetchable", + start: PCI_BUS_PREMEM_START, + end: PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1, + flags: IORESOURCE_MEM | IORESOURCE_PREFETCH, +}; + +/* + * V3_LB_BASE? - local bus address + * V3_LB_MAP? - pci bus address + */ +void __init pci_v3_init(struct arm_pci_sysdata *sysdata) +{ + struct pci_bus *bus; + unsigned int pci_cmd; + unsigned long flags; + + spin_lock_irqsave(&v3_lock, flags); + + /* + * Setup window 0 - PCI non-prefetchable memory + * Local: 0x40000000 Bus: 0x00000000 Size: 256MB + */ + _V3Write32(V3_LB_BASE0, (PHYS_PCI_MEM_BASE & 0xfff00000) | 0x80 | V3_LB_BASE_M_ENABLE); + _V3Write16(V3_LB_MAP0, (PCI_BUS_NONMEM_START >> 16) | 0x0006); + + /* + * Setup window 1 - PCI prefetchable memory + * Local: 0x50000000 Bus: 0x10000000 Size: 256MB + */ + _V3Write32(V3_LB_BASE1, ((PHYS_PCI_MEM_BASE + SZ_256M) & 0xFFF00000) | 0x84 | V3_LB_BASE_M_ENABLE); + _V3Write16(V3_LB_MAP1, (PCI_BUS_PREMEM_START >> 16) | 0x0006); + + /* + * Setup window 2 - PCI IO + */ +// _V3Write32(V3_LB_BASE2, (PHYS_PCI_IO_BASE & 0xff000000) | V3_LB_BASE_M_ENABLE); +// _V3Write16(V3_LB_MAP2, 0); + + spin_unlock_irqrestore(&v3_lock, flags); + + bus = pci_scan_bus(0, &pci_v3_ops, sysdata); + + if (request_resource(&iomem_resource, &non_mem)) + printk("PCI: unable to allocate non-prefetchable memory region"); + if (request_resource(&iomem_resource, &pre_mem)) + printk("PCI: unable to allocate prefetchable memory region"); + + /* + * bus->resource[0] is the IO resource for this bus + * bus->resource[1] is the mem resource for this bus + * bus->resource[2] is the prefetch mem resource for this bus + */ + bus->resource[1] = &non_mem; + bus->resource[2] = &pre_mem; + + pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; + + pci_cmd |= sysdata->bus[0].features; + + _V3Write16(V3_PCI_CMD, pci_cmd); + + printk("PCI: Fast back to back transfers %sabled\n", + (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ? + "en" : "dis"); +} diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/time.c linux/arch/arm/mach-integrator/time.c --- v2.4.2/linux/arch/arm/mach-integrator/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-integrator/time.c Fri Mar 2 18:38:39 2001 @@ -0,0 +1,45 @@ +/* + * linux/arch/arm/mach-integrator/time.c + * + * Copyright (C) 2000 Deep Blue Solutions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include + +#define RTC_DR (*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 0)) +#define RTC_MR (*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 4)) +#define RTC_STAT (*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 8)) +#define RTC_EOI (*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 8)) +#define RTC_LR (*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 12)) +#define RTC_CR (*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 16)) + +#define RTC_CR_MIE 0x00000001 + +extern int (*set_rtc)(void); + +static int integrator_set_rtc(void) +{ + RTC_LR = xtime.tv_sec; + return 1; +} + +static int integrator_rtc_init(void) +{ + RTC_CR = 0; + RTC_EOI = 0; + + xtime.tv_sec = RTC_DR; + + set_rtc = integrator_set_rtc; + + return 0; +} + +__initcall(integrator_rtc_init); diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-sa1100/arch.c linux/arch/arm/mach-sa1100/arch.c --- v2.4.2/linux/arch/arm/mach-sa1100/arch.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mach-sa1100/arch.c Fri Mar 2 11:12:06 2001 @@ -54,7 +54,7 @@ if (machine_is_assabet()) { /* * On Assabet, we must probe for the Neponset board *before* - * paging_init() has occured to actually determine the amount + * paging_init() has occurred to actually determine the amount * of RAM available. */ extern void map_sa1100_gpio_regs(void); diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c --- v2.4.2/linux/arch/arm/mm/mm-rpc.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/mm-rpc.c Tue Mar 6 19:44:35 2001 @@ -9,6 +9,7 @@ * * Extra MM routines for RiscPC architecture */ +#include #include #include diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c --- v2.4.2/linux/arch/arm/mm/mm-sa1100.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/mm-sa1100.c Fri Mar 2 11:12:06 2001 @@ -199,7 +199,7 @@ /* * On Assabet, we must probe for the Neponset board *before* paging_init() - * has occured to actually determine the amount of RAM available. To do so, + * has occurred to actually determine the amount of RAM available. To do so, * we map the appropriate IO section in the page table here in order to * access GPIO registers. */ diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-arm2,3.S linux/arch/arm/mm/proc-arm2,3.S --- v2.4.2/linux/arch/arm/mm/proc-arm2,3.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/proc-arm2,3.S Tue Mar 6 19:44:35 2001 @@ -14,8 +14,8 @@ */ #include #include +#include #include -#include "../lib/constants.h" /* * MEMC workhorse code. It's both a horse which things it's a pig. diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.4.2/linux/arch/arm/mm/proc-arm6,7.S Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/mm/proc-arm6,7.S Tue Mar 6 19:44:35 2001 @@ -12,8 +12,8 @@ */ #include #include +#include #include -#include "../lib/constants.h" /* * Function: arm6_7_cache_clean_invalidate_all (void) @@ -29,10 +29,10 @@ ENTRY(cpu_arm7_cache_clean_invalidate_all) ENTRY(cpu_arm6_cache_clean_invalidate_range) ENTRY(cpu_arm7_cache_clean_invalidate_range) -ENTRY(cpu_arm6_invalidate_icache_range) -ENTRY(cpu_arm7_invalidate_icache_range) -ENTRY(cpu_arm6_invalidate_icache_page) -ENTRY(cpu_arm7_invalidate_icache_page) +ENTRY(cpu_arm6_icache_invalidate_range) +ENTRY(cpu_arm7_icache_invalidate_range) +ENTRY(cpu_arm6_icache_invalidate_page) +ENTRY(cpu_arm7_icache_invalidate_page) ENTRY(cpu_arm6_dcache_clean_range) ENTRY(cpu_arm7_dcache_clean_range) ENTRY(cpu_arm6_dcache_invalidate_range) @@ -410,8 +410,8 @@ .word cpu_arm6_dcache_clean_entry /* icache */ - .word cpu_arm6_invalidate_icache_range - .word cpu_arm6_invalidate_icache_page + .word cpu_arm6_icache_invalidate_range + .word cpu_arm6_icache_invalidate_page /* tlb */ .word cpu_arm6_tlb_invalidate_all @@ -449,8 +449,8 @@ .word cpu_arm7_dcache_clean_entry /* icache */ - .word cpu_arm7_invalidate_icache_range - .word cpu_arm7_invalidate_icache_page + .word cpu_arm7_icache_invalidate_range + .word cpu_arm7_icache_invalidate_page /* tlb */ .word cpu_arm7_tlb_invalidate_all diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-arm720.S linux/arch/arm/mm/proc-arm720.S --- v2.4.2/linux/arch/arm/mm/proc-arm720.S Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/mm/proc-arm720.S Tue Mar 6 19:44:35 2001 @@ -32,9 +32,9 @@ */ #include #include +#include #include #include -#include "../lib/constants.h" /* * Function: arm720_cache_clean_invalidate_all (void) diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-arm920.S linux/arch/arm/mm/proc-arm920.S --- v2.4.2/linux/arch/arm/mm/proc-arm920.S Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/mm/proc-arm920.S Tue Mar 6 19:44:35 2001 @@ -25,9 +25,9 @@ #include #include #include +#include #include #include -#include "../lib/constants.h" /* * This is the maximum size of an area which will be invalidated diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.4.2/linux/arch/arm/mm/proc-sa110.S Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/mm/proc-sa110.S Tue Mar 6 19:44:35 2001 @@ -19,9 +19,9 @@ */ #include #include +#include #include #include -#include "../lib/constants.h" /* This is the maximum size of an area which will be flushed. If the area * is larger than this, then we flush the whole cache diff -u --recursive --new-file v2.4.2/linux/arch/arm/nwfpe/entry26.S linux/arch/arm/nwfpe/entry26.S --- v2.4.2/linux/arch/arm/nwfpe/entry26.S Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/nwfpe/entry26.S Tue Mar 6 19:44:35 2001 @@ -20,7 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "../lib/constants.h" +#include /* This is the kernel's entry point into the floating point emulator. It is called from the kernel with code similar to this: diff -u --recursive --new-file v2.4.2/linux/arch/arm/tools/Makefile linux/arch/arm/tools/Makefile --- v2.4.2/linux/arch/arm/tools/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/tools/Makefile Tue Mar 6 19:44:35 2001 @@ -0,0 +1,36 @@ +# +# linux/arch/arm/tools/Makefile +# +# Copyright (C) 2001 Russell King +# + +all: $(TOPDIR)/include/asm-arm/mach-types.h \ + $(TOPDIR)/include/asm-arm/constants.h + +$(TOPDIR)/include/asm-arm/mach-types.h: mach-types gen-mach-types + awk -f gen-mach-types mach-types > $@ + +# Generate the constants.h header file using the compiler. We get +# the compiler to spit out assembly code, and then mundge it into +# what we want. + +$(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c + $(CC) $(CFLAGS) -S -o - getconstants.c | \ + sed 's/^\(#define .* \)#\(.*\)/\1\2/;/^#define/!d' | \ + cat constants-hdr - > $@.tmp + cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@; $(RM) $@.tmp + +# Build our dependencies, and then generate the constants and +# mach-types header files. If we do it now, mkdep will pick +# the dependencies up later on when it runs through the other +# directories + +dep: + $(TOPDIR)/scripts/mkdep getconstants.c | sed s,getconstants.o,$(TOPDIR)/include/asm-arm/constants.h, > .depend + $(MAKE) all + +.PHONY: all dep + +ifneq ($(wildcard .depend),) +include .depend +endif diff -u --recursive --new-file v2.4.2/linux/arch/arm/tools/constants-hdr linux/arch/arm/tools/constants-hdr --- v2.4.2/linux/arch/arm/tools/constants-hdr Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/tools/constants-hdr Tue Mar 6 19:44:35 2001 @@ -0,0 +1,5 @@ +/* + * This file is automatically generated from arch/arm/tools/getconstants.c. + * Do not edit! Only include this file in assembly (.S) files! + */ + diff -u --recursive --new-file v2.4.2/linux/arch/arm/tools/getconstants.c linux/arch/arm/tools/getconstants.c --- v2.4.2/linux/arch/arm/tools/getconstants.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/tools/getconstants.c Tue Mar 6 19:44:35 2001 @@ -0,0 +1,72 @@ +/* + * linux/arch/arm/tools/getconsdata.c + * + * Copyright (C) 1995-2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include + +/* + * Make sure that the compiler and target are compatible + */ +#if (defined(__APCS_32__) && defined(CONFIG_CPU_26)) +#error Your compiler targets APCS-32 but this kernel requires APCS-26. +#endif +#if (defined(__APCS_26__) && defined(CONFIG_CPU_32)) +#error Your compiler targets APCS-26 but this kernel requires APCS-32. +#endif + +#define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) + +#define DEFN(name,off) asm("\n#define "name" %0" :: "I" (off)) + +void func(void) +{ +DEFN("TSK_SIGPENDING", OFF_TSK(sigpending)); +DEFN("TSK_ADDR_LIMIT", OFF_TSK(addr_limit)); +DEFN("TSK_NEED_RESCHED", OFF_TSK(need_resched)); +DEFN("TSK_PTRACE", OFF_TSK(ptrace)); +DEFN("TSK_USED_MATH", OFF_TSK(used_math)); + +DEFN("TSS_SAVE", OFF_TSK(thread.save)); +DEFN("TSS_FPESAVE", OFF_TSK(thread.fpstate.soft.save)); + +#ifdef CONFIG_CPU_32 +DEFN("TSS_DOMAIN", OFF_TSK(thread.domain)); + +DEFN("HPTE_TYPE_SMALL", PTE_TYPE_SMALL); +DEFN("HPTE_AP_READ", PTE_AP_READ); +DEFN("HPTE_AP_WRITE", PTE_AP_WRITE); + +DEFN("LPTE_PRESENT", L_PTE_PRESENT); +DEFN("LPTE_YOUNG", L_PTE_YOUNG); +DEFN("LPTE_BUFFERABLE", L_PTE_BUFFERABLE); +DEFN("LPTE_CACHEABLE", L_PTE_CACHEABLE); +DEFN("LPTE_USER", L_PTE_USER); +DEFN("LPTE_WRITE", L_PTE_WRITE); +DEFN("LPTE_EXEC", L_PTE_EXEC); +DEFN("LPTE_DIRTY", L_PTE_DIRTY); +#endif + +#ifdef CONFIG_CPU_26 +DEFN("PAGE_PRESENT", _PAGE_PRESENT); +DEFN("PAGE_READONLY", _PAGE_READONLY); +DEFN("PAGE_NOT_USER", _PAGE_NOT_USER); +DEFN("PAGE_OLD", _PAGE_OLD); +DEFN("PAGE_CLEAN", _PAGE_CLEAN); +#endif + +DEFN("PAGE_SZ", PAGE_SIZE); + +DEFN("KSWI_BASE", 0x900000); +DEFN("KSWI_SYS_BASE", 0x9f0000); +DEFN("SYS_ERROR0", 0x9f0000); +} diff -u --recursive --new-file v2.4.2/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types --- v2.4.2/linux/arch/arm/tools/mach-types Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/tools/mach-types Tue Mar 6 19:44:35 2001 @@ -4,7 +4,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Mon Nov 20 22:59:11 2000 +# Last update: Fri Feb 9 22:27:32 2001 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -48,13 +48,23 @@ netport SA1100_NETPORT NETPORT 38 pangolin SA1100_PANGOLIN PANGOLIN 39 yopy SA1100_YOPY YOPY 40 -sa1100 SA1100_SA1100 SA1100 41 -huw_webpanel ARCH_HUW_WEBPANEL HUW_WEBPANEL 42 +coolidge SA1100_COOLIDGE coolidge 41 +huw_webpanel SA1100_HUW_WEBPANEL HUW_WEBPANEL 42 spotme ARCH_SPOTME SPOTME 43 freebird ARCH_FREEBIRD FREEBIRD 44 ti925 ARCH_TI925 TI925 45 riscstation ARCH_RISCSTATION RISCSTATION 46 cavy SA1100_CAVY CAVY 47 +jornada720 SA1100_JORNADA720 JORNADA720 48 +omnimeter SA1100_OMNIMETER OMNIMETER 49 +edb7211 ARCH_EDB7211 EDB7211 50 +citygo SA1100_CITYGO CITYGO 51 +pfs168 SA1100_PFS168 PFS168 52 +spot SA1100_SPOT SPOT 53 +flexanet ARCH_FLEXANET FLEXANET 54 +webpal ARCH_WEBPAL WEBPAL 55 +linpda SA1100_LINPDA LINPDA 56 +anakin ARCH_ANAKIN ANAKIN 57 # The following are unallocated empeg SA1100_EMPEG EMPEG diff -u --recursive --new-file v2.4.2/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in --- v2.4.2/linux/arch/arm/vmlinux-armv.lds.in Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/vmlinux-armv.lds.in Tue Mar 6 19:44:35 2001 @@ -45,18 +45,22 @@ *(.glue_7) *(.glue_7t) *(.kstrtab) - . = ALIGN(16); - __start___ex_table = .; /* Exception table */ + *(.got) /* Global offset table */ + + _etext = .; /* End of text section */ + } + + . = ALIGN(16); + __ex_table : { /* Exception table */ + __start___ex_table = .; *(__ex_table) __stop___ex_table = .; + } - __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { /* Kernel symbol table */ + __start___ksymtab = .; *(__ksymtab) __stop___ksymtab = .; - - *(.got) /* Global offset table */ - - _etext = .; /* End of text section */ } . = ALIGN(8192); diff -u --recursive --new-file v2.4.2/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c --- v2.4.2/linux/arch/cris/drivers/serial.c Wed Feb 21 18:20:10 2001 +++ linux/arch/cris/drivers/serial.c Fri Mar 2 18:38:40 2001 @@ -146,7 +146,7 @@ * * Revision 1.24 2000/02/09 18:02:28 bjornw * * Clear serial errors (overrun, framing, parity) correctly. Before, the - * receiver would get stuck if an error occured and we did not restart + * receiver would get stuck if an error occurred and we did not restart * the input DMA. * * Cosmetics (indentation, some code made into inlines) * * Some more debug options @@ -1371,7 +1371,7 @@ } else { /* it was a valid byte, now let the dma do the rest */ #ifdef SERIAL_DEBUG_INTR - printk("** OK, disabling ser_interupts\n"); + printk("** OK, disabling ser_interrupts\n"); #endif e100_disable_serial_data_irq(info); } diff -u --recursive --new-file v2.4.2/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S --- v2.4.2/linux/arch/cris/kernel/entry.S Wed Feb 21 18:20:10 2001 +++ linux/arch/cris/kernel/entry.S Fri Mar 2 18:38:40 2001 @@ -23,7 +23,7 @@ * Revision 1.8 2000/11/17 16:53:35 bjornw * Added detection of frame-type in Rexit, so that mmu_bus_fault can * use ret_from_intr in the return-path to check for signals (like SEGV) - * and other foul things that might have occured during the fault. + * and other foul things that might have occurred during the fault. * * Revision 1.7 2000/10/06 15:04:28 bjornw * Include mof in register savings diff -u --recursive --new-file v2.4.2/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c --- v2.4.2/linux/arch/cris/mm/fault.c Wed Feb 21 18:20:11 2001 +++ linux/arch/cris/mm/fault.c Fri Mar 2 18:38:40 2001 @@ -146,7 +146,7 @@ * routines. * * Notice that the address we're given is aligned to the page the fault - * occured in, since we only get the PFN in R_MMU_CAUSE not the complete + * occurred in, since we only get the PFN in R_MMU_CAUSE not the complete * address. * * error_code: @@ -381,7 +381,7 @@ pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); - if (pmd_present(*pmd) || !pmd_present(*pmd_k)) + if (!pmd_present(*pmd_k)) goto bad_area_nosemaphore; set_pmd(pmd, *pmd_k); return; diff -u --recursive --new-file v2.4.2/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile --- v2.4.2/linux/arch/i386/boot/Makefile Mon Dec 20 14:43:39 1999 +++ linux/arch/i386/boot/Makefile Thu Feb 22 00:25:29 2001 @@ -43,7 +43,7 @@ $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include bootsect: bootsect.o - $(LD) -Ttext 0x0 -s -oformat binary -o $@ $< + $(LD) -Ttext 0x0 -s --oformat binary -o $@ $< bootsect.o: bootsect.s $(AS) -o $@ $< @@ -52,7 +52,7 @@ $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ bbootsect: bbootsect.o - $(LD) -Ttext 0x0 -s -oformat binary $< -o $@ + $(LD) -Ttext 0x0 -s --oformat binary $< -o $@ bbootsect.o: bbootsect.s $(AS) -o $@ $< @@ -61,7 +61,7 @@ $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ setup: setup.o - $(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $< + $(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $< setup.o: setup.s $(AS) -o $@ $< @@ -70,7 +70,7 @@ $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ bsetup: bsetup.o - $(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $< + $(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $< bsetup.o: bsetup.s $(AS) -o $@ $< diff -u --recursive --new-file v2.4.2/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.2/linux/arch/i386/defconfig Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/defconfig Tue Mar 6 20:06:35 2001 @@ -280,6 +280,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -382,7 +383,6 @@ # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139TOO is not set -# CONFIG_RTL8129 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -529,13 +529,11 @@ CONFIG_DRM_RADEON=y # CONFIG_DRM_I810 is not set # CONFIG_DRM_MGA is not set -CONFIG_PCMCIA_SERIAL=y # -# PCMCIA character device support +# PCMCIA character devices # # CONFIG_PCMCIA_SERIAL_CS is not set -# CONFIG_PCMCIA_SERIAL_CB is not set # # Multimedia devices diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.4.2/linux/arch/i386/kernel/i386_ksyms.c Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/kernel/i386_ksyms.c Fri Mar 2 12:03:49 2001 @@ -27,6 +27,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -134,6 +135,9 @@ EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); EXPORT_SYMBOL(smp_call_function); + +/* TLB flushing */ +EXPORT_SYMBOL(flush_tlb_page); #endif #ifdef CONFIG_MCA diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/i387.c linux/arch/i386/kernel/i387.c --- v2.4.2/linux/arch/i386/kernel/i387.c Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/kernel/i387.c Fri Feb 23 10:09:08 2001 @@ -179,7 +179,7 @@ unsigned short get_fpu_mxcsr( struct task_struct *tsk ) { - if ( cpu_has_fxsr ) { + if ( cpu_has_xmm ) { return tsk->thread.i387.fxsave.mxcsr; } else { return 0x1f80; diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.4.2/linux/arch/i386/kernel/pci-pc.c Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/kernel/pci-pc.c Wed Mar 7 10:14:26 2001 @@ -861,6 +861,8 @@ } } +#if 0 +/* Our bus code shouldnt need this fixup any more. Delete once verified */ /* * Compaq host bridges -- Find and scan all secondary buses. * This time registers 0xc8 and 0xc9. @@ -878,6 +880,7 @@ printk("PCI: Compaq host bridge: last bus %02x\n", busno2); } } +#endif static void __init pci_fixup_umc_ide(struct pci_dev *d) { @@ -934,35 +937,75 @@ pcibios_max_latency = 32; } +static void __init pci_fixup_via_acpi(struct pci_dev *d) +{ + /* + * VIA ACPI device: IRQ line in PCI config byte 0x42 + */ + u8 irq; + pci_read_config_byte(d, 0x42, &irq); + irq &= 0x0f; + if (irq && (irq != 2)) + d->irq = irq; +} + +static void __init pci_fixup_piix4_acpi(struct pci_dev *d) +{ + /* + * PIIX4 ACPI device: hardwired IRQ9 + */ + d->irq = 9; +} + static void __init pci_fixup_vt8363(struct pci_dev *d) { /* - * VIA VT8363 host bridge has broken feature 'PCI Master Read - * Caching'. It caches more than is good for it, sometimes - * serving the bus master with stale data. Some BIOSes enable - * it by default, so we disable it. + * The VIA bridge will corrupt disks without these settings. */ u8 tmp; + pci_read_config_byte(d, 0x54, &tmp); + if(tmp & (1<<2)) { + printk("PCI: Bus master Pipeline request disabled\n"); + pci_write_config_byte(d, 0x54, tmp & ~(1<<2)); + } pci_read_config_byte(d, 0x70, &tmp); - if(tmp & 4) { - printk("PCI: Bus master read caching disabled\n"); - pci_write_config_byte(d, 0x70, tmp & ~4); + if(tmp & (1<<3)) { + printk("PCI: Disabled enhanced CPU to PCI writes\n"); + pci_write_config_byte(d, 0x70, tmp & ~(1<<3)); + } + pci_read_config_byte(d, 0x71, &tmp); + if(!(tmp & (1<<3))) { + printk("PCI: Bursting cornercase bug worked around\n"); + pci_write_config_byte(d, 0x71, tmp | (1<<3)); + } + pci_read_config_byte(d, 0x76, &tmp); + if(tmp & (1<<7)) { + printk("PCI: Post Write Fail set to Retry\n"); + pci_write_config_byte(d, 0x76, tmp & ~(1<<7)); } } struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx }, +#if 0 +/* Until we get proper handling pray the BIOS gets it right */ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HE, pci_fixup_serverworks }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, pci_fixup_serverworks }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CMIC_HE, pci_fixup_serverworks }, +#endif +#if 0 +/* Our bus code shouldnt need this fixup any more. Delete once verified */ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_6010, pci_fixup_compaq }, +#endif { PCI_FIXUP_HEADER, PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash }, { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency }, - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_vt8363 }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, pci_fixup_via_acpi }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, pci_fixup_via_acpi }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_vt8363 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi }, { 0 } }; diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.4.2/linux/arch/i386/kernel/ptrace.c Mon Oct 30 14:46:53 2000 +++ linux/arch/i386/kernel/ptrace.c Tue Mar 6 19:44:37 2001 @@ -167,14 +167,16 @@ if (request == PTRACE_ATTACH) { if (child == current) goto out_tsk; - if ((!child->dumpable || - (current->uid != child->euid) || + if(((current->uid != child->euid) || (current->uid != child->suid) || (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || (!cap_issubset(child->cap_permitted, current->cap_permitted)) || (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out_tsk; + rmb(); + if (!child->dumpable && !capable(CAP_SYS_PTRACE)) goto out_tsk; /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.4.2/linux/arch/i386/kernel/traps.c Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/kernel/traps.c Thu Mar 1 16:54:35 2001 @@ -388,7 +388,7 @@ #if CONFIG_X86_IO_APIC -int nmi_watchdog = 1; +int nmi_watchdog = 0; static int __init setup_nmi_watchdog(char *str) { diff -u --recursive --new-file v2.4.2/linux/arch/i386/lib/mmx.c linux/arch/i386/lib/mmx.c --- v2.4.2/linux/arch/i386/lib/mmx.c Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/lib/mmx.c Thu Mar 1 18:04:34 2001 @@ -3,6 +3,7 @@ #include #include +#include /* * MMX 3DNow! library helper functions @@ -25,8 +26,14 @@ void *_mmx_memcpy(void *to, const void *from, size_t len) { - void *p=to; - int i= len >> 6; /* len/64 */ + void *p; + int i; + + if (in_interrupt()) + return __memcpy(to, from, len); + + p = to; + i = len >> 6; /* len/64 */ kernel_fpu_begin(); diff -u --recursive --new-file v2.4.2/linux/arch/i386/mm/extable.c linux/arch/i386/mm/extable.c --- v2.4.2/linux/arch/i386/mm/extable.c Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/mm/extable.c Fri Mar 2 11:12:07 2001 @@ -49,7 +49,7 @@ spin_lock_irqsave(&modlist_lock, flags); for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->ex_table_start == NULL) + if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING))) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); diff -u --recursive --new-file v2.4.2/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S --- v2.4.2/linux/arch/ia64/lib/copy_user.S Wed Feb 21 18:20:11 2001 +++ linux/arch/ia64/lib/copy_user.S Tue Mar 6 19:44:35 2001 @@ -16,7 +16,7 @@ * in2 number of bytes to copy * * Outputs: - * ret0 0 in case of sucess. The number of bytes NOT copied in + * ret0 0 in case of success. The number of bytes NOT copied in * case of error. * * Copyright (C) 2000 Hewlett-Packard Co diff -u --recursive --new-file v2.4.2/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S --- v2.4.2/linux/arch/ia64/lib/strlen.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/strlen.S Tue Mar 6 19:44:35 2001 @@ -198,5 +198,5 @@ ;; sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of sucessful recovery code + br.ret.sptk.few rp // end of successful recovery code END(strlen) diff -u --recursive --new-file v2.4.2/linux/arch/ia64/lib/strlen_user.S linux/arch/ia64/lib/strlen_user.S --- v2.4.2/linux/arch/ia64/lib/strlen_user.S Thu Jun 22 07:09:44 2000 +++ linux/arch/ia64/lib/strlen_user.S Tue Mar 6 19:44:35 2001 @@ -204,7 +204,7 @@ ;; sub ret0=ret0,tmp // length=now - back -1 mov ar.pfs=saved_pfs // because of ar.ec, restore no matter what - br.ret.sptk.few rp // end of sucessful recovery code + br.ret.sptk.few rp // end of successful recovery code // // We failed even on the normal load (called from exception handler) diff -u --recursive --new-file v2.4.2/linux/arch/ia64/sn/io/l1.c linux/arch/ia64/sn/io/l1.c --- v2.4.2/linux/arch/ia64/sn/io/l1.c Wed Feb 21 18:20:12 2001 +++ linux/arch/ia64/sn/io/l1.c Tue Mar 6 19:44:35 2001 @@ -2788,7 +2788,7 @@ while( (r = _elscuart_poll( sc )) == 0 ); if( r < 0 ) { - /* some error occured */ + /* some error occurred */ return r; } diff -u --recursive --new-file v2.4.2/linux/arch/ia64/sn/io/pcibr.c linux/arch/ia64/sn/io/pcibr.c --- v2.4.2/linux/arch/ia64/sn/io/pcibr.c Wed Feb 21 18:20:12 2001 +++ linux/arch/ia64/sn/io/pcibr.c Tue Mar 6 19:44:35 2001 @@ -3925,7 +3925,7 @@ * above. * * Need to set the D_INTR_ISERR flag - * in the dev_desc used for alocating the + * in the dev_desc used for allocating the * error interrupt, so our interrupt will * be properly routed and prioritized. * @@ -5540,7 +5540,7 @@ } else xio_port = pcibr_dmamap->bd_xio_port; - /* If this DMA is to an addres that + /* If this DMA is to an address that * refers back to this Bridge chip, * reduce it back to the correct * PCI MEM address. @@ -8540,7 +8540,7 @@ * * CAUTION: Resetting bit BRIDGE_IRR_PCI_GRP_CLR, acknowledges * a group of interrupts. If while handling this error, - * some other error has occured, that would be + * some other error has occurred, that would be * implicitly cleared by this write. * Need a way to ensure we don't inadvertently clear some * other errors. diff -u --recursive --new-file v2.4.2/linux/arch/m68k/apollo/dn_ints.c linux/arch/m68k/apollo/dn_ints.c --- v2.4.2/linux/arch/m68k/apollo/dn_ints.c Fri Jul 14 12:20:22 2000 +++ linux/arch/m68k/apollo/dn_ints.c Tue Mar 6 19:44:35 2001 @@ -24,7 +24,7 @@ dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp); } else { - printk("spurious irq %d occured\n",irq); + printk("spurious irq %d occurred\n",irq); } *(volatile unsigned char *)(pica)=0x20; diff -u --recursive --new-file v2.4.2/linux/arch/m68k/ifpsp060/src/fpsp.S linux/arch/m68k/ifpsp060/src/fpsp.S --- v2.4.2/linux/arch/m68k/ifpsp060/src/fpsp.S Wed Feb 21 18:20:12 2001 +++ linux/arch/m68k/ifpsp060/src/fpsp.S Tue Mar 6 19:44:35 2001 @@ -23523,7 +23523,7 @@ # in INEX2. # # # # A10. Or in INEX. # -# If INEX is set, round error occured. This is # +# If INEX is set, round error occurred. This is # # compensated for by 'or-ing' in the INEX2 flag to # # the lsb of Y. # # # @@ -23989,7 +23989,7 @@ fmul.x %fp1,%fp0 # calculate X * SCALE -> Y to fp0 # A10. Or in INEX. -# If INEX is set, round error occured. This is compensated +# If INEX is set, round error occurred. This is compensated # for by 'or-ing' in the INEX2 flag to the lsb of Y. # # Register usage: diff -u --recursive --new-file v2.4.2/linux/arch/m68k/ifpsp060/src/ilsp.S linux/arch/m68k/ifpsp060/src/ilsp.S --- v2.4.2/linux/arch/m68k/ifpsp060/src/ilsp.S Fri Dec 29 14:07:20 2000 +++ linux/arch/m68k/ifpsp060/src/ilsp.S Tue Mar 6 19:44:35 2001 @@ -514,7 +514,7 @@ # fmovm.l &0x0,-(%sp) # save no fpregs # PROLOGUE END ########################################################## - mov.w %cc,MUL64_CC(%a6) # save incomming ccodes + mov.w %cc,MUL64_CC(%a6) # save incoming ccodes mov.l 0x8(%a6),%d0 # store multiplier in d0 beq.w mulu64_zero # handle zero separately @@ -625,7 +625,7 @@ # fmovm.l &0x0,-(%sp) # save no fpregs # PROLOGUE END ########################################################## - mov.w %cc,MUL64_CC(%a6) # save incomming ccodes + mov.w %cc,MUL64_CC(%a6) # save incoming ccodes mov.l 0x8(%a6),%d0 # store multiplier in d0 beq.b mulu64_zero # handle zero separately diff -u --recursive --new-file v2.4.2/linux/arch/m68k/ifpsp060/src/isp.S linux/arch/m68k/ifpsp060/src/isp.S --- v2.4.2/linux/arch/m68k/ifpsp060/src/isp.S Wed Feb 21 18:20:12 2001 +++ linux/arch/m68k/ifpsp060/src/isp.S Tue Mar 6 19:44:36 2001 @@ -3835,7 +3835,7 @@ # assert LOCKE* for the final write operation. # # (13)Exit. # # # -# The algorithm is actually implemented slightly diferently # +# The algorithm is actually implemented slightly differently # # depending on the size of the operation and the misalignment of the # # operand. A misaligned operand must be written in aligned chunks or # # else the BUSCR register control gets confused. # diff -u --recursive --new-file v2.4.2/linux/arch/m68k/ifpsp060/src/pfpsp.S linux/arch/m68k/ifpsp060/src/pfpsp.S --- v2.4.2/linux/arch/m68k/ifpsp060/src/pfpsp.S Wed Feb 21 18:20:12 2001 +++ linux/arch/m68k/ifpsp060/src/pfpsp.S Tue Mar 6 19:44:36 2001 @@ -13483,7 +13483,7 @@ # in INEX2. # # # # A10. Or in INEX. # -# If INEX is set, round error occured. This is # +# If INEX is set, round error occurred. This is # # compensated for by 'or-ing' in the INEX2 flag to # # the lsb of Y. # # # @@ -13949,7 +13949,7 @@ fmul.x %fp1,%fp0 # calculate X * SCALE -> Y to fp0 # A10. Or in INEX. -# If INEX is set, round error occured. This is compensated +# If INEX is set, round error occurred. This is compensated # for by 'or-ing' in the INEX2 flag to the lsb of Y. # # Register usage: diff -u --recursive --new-file v2.4.2/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c --- v2.4.2/linux/arch/m68k/kernel/bios32.c Wed Feb 21 18:20:12 2001 +++ linux/arch/m68k/kernel/bios32.c Tue Mar 6 19:44:36 2001 @@ -444,7 +444,7 @@ * dev - device. * i - resource. * - * Result: 0 if successfull. + * Result: 0 if successful. */ int __init pcibios_assign_resource(struct pci_dev *dev, int i) diff -u --recursive --new-file v2.4.2/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S --- v2.4.2/linux/arch/m68k/kernel/head.S Wed Jan 26 12:44:20 2000 +++ linux/arch/m68k/kernel/head.S Tue Mar 6 19:44:36 2001 @@ -840,7 +840,7 @@ #ifdef CONFIG_MVME16x is_not_mvme16x(L(gvtdone)) - /* Need to get the BRD_ID info to diferentiate between 162, 167, + /* Need to get the BRD_ID info to differentiate between 162, 167, * etc. This is available as a BI_VME_BRDINFO tag with later * versions of VMELILO and TFTPLILO, otherwise we call the Bug. */ diff -u --recursive --new-file v2.4.2/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c --- v2.4.2/linux/arch/m68k/kernel/ints.c Mon Nov 27 17:11:26 2000 +++ linux/arch/m68k/kernel/ints.c Tue Mar 6 19:44:36 2001 @@ -184,7 +184,7 @@ /* * Do we need these probe functions on the m68k? * - * ... may be usefull with ISA devices + * ... may be useful with ISA devices */ unsigned long probe_irq_on (void) { diff -u --recursive --new-file v2.4.2/linux/arch/m68k/q40/README linux/arch/m68k/q40/README --- v2.4.2/linux/arch/m68k/q40/README Mon Nov 27 17:11:26 2000 +++ linux/arch/m68k/q40/README Tue Mar 6 19:44:36 2001 @@ -127,7 +127,7 @@ - exact keypress/release sequence - 'showkey -s' run on q40, non-X session - 'showkey -s' run on a PC, non-X session - - AT codes as displayed by the q40 debuging ROM + - AT codes as displayed by the q40 debugging ROM btw if the showkey output from PC and Q40 doesn't differ then you have some classic configuration problem - don't send me anything in this case diff -u --recursive --new-file v2.4.2/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c --- v2.4.2/linux/arch/m68k/q40/config.c Mon Nov 27 17:57:34 2000 +++ linux/arch/m68k/q40/config.c Tue Mar 6 19:44:36 2001 @@ -238,7 +238,7 @@ mach_max_dma_address = 32*1024*1024; /* no DMA at all, but ide-scsi requires it.. */ -/* userfull for early debuging stages writes kernel messages into SRAM */ +/* userfull for early debugging stages writes kernel messages into SRAM */ if (!strncmp( m68k_debug_device,"mem",3 )) { diff -u --recursive --new-file v2.4.2/linux/arch/mips/baget/irq.c linux/arch/mips/baget/irq.c --- v2.4.2/linux/arch/mips/baget/irq.c Wed Feb 21 18:20:13 2001 +++ linux/arch/mips/baget/irq.c Tue Mar 6 19:44:36 2001 @@ -199,7 +199,7 @@ add_interrupt_randomness(irq); __cli(); } else { - printk("do_IRQ: Unregistered IRQ (0x%X) occured\n", irq); + printk("do_IRQ: Unregistered IRQ (0x%X) occurred\n", irq); } unmask_irq(irq); irq_exit(cpu); diff -u --recursive --new-file v2.4.2/linux/arch/mips/boot/elf2ecoff.c linux/arch/mips/boot/elf2ecoff.c --- v2.4.2/linux/arch/mips/boot/elf2ecoff.c Mon Jul 5 20:35:17 1999 +++ linux/arch/mips/boot/elf2ecoff.c Tue Mar 6 19:44:36 2001 @@ -435,7 +435,7 @@ char ibuf [4096]; int remaining, cur, count; - /* Go the the start of the ELF symbol table... */ + /* Go to the start of the ELF symbol table... */ if (lseek (in, offset, SEEK_SET) < 0) { perror ("copy: lseek"); diff -u --recursive --new-file v2.4.2/linux/arch/mips/dec/prom/memory.c linux/arch/mips/dec/prom/memory.c --- v2.4.2/linux/arch/mips/dec/prom/memory.c Mon Aug 7 21:02:27 2000 +++ linux/arch/mips/dec/prom/memory.c Tue Mar 6 19:44:36 2001 @@ -31,7 +31,7 @@ extern int (*prom_printf)(char *, ...); #endif -volatile unsigned long mem_err = 0; /* So we know an error occured */ +volatile unsigned long mem_err = 0; /* So we know an error occurred */ extern char _end; diff -u --recursive --new-file v2.4.2/linux/arch/mips/defconfig linux/arch/mips/defconfig --- v2.4.2/linux/arch/mips/defconfig Thu Jul 27 18:36:54 2000 +++ linux/arch/mips/defconfig Sun Mar 4 14:30:18 2001 @@ -175,6 +175,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -u --recursive --new-file v2.4.2/linux/arch/mips/kernel/mips_ksyms.c linux/arch/mips/kernel/mips_ksyms.c --- v2.4.2/linux/arch/mips/kernel/mips_ksyms.c Fri Aug 4 16:15:37 2000 +++ linux/arch/mips/kernel/mips_ksyms.c Fri Mar 2 11:15:47 2001 @@ -140,3 +140,4 @@ #endif EXPORT_SYMBOL(get_wchan); +EXPORT_SYMBOL(flush_tlb_page); diff -u --recursive --new-file v2.4.2/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c --- v2.4.2/linux/arch/mips/sgi/kernel/indy_sc.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/sgi/kernel/indy_sc.c Tue Mar 6 19:44:36 2001 @@ -1,6 +1,6 @@ /* $Id: indy_sc.c,v 1.14 2000/03/25 22:35:07 ralf Exp $ * - * indy_sc.c: Indy cache managment functions. + * indy_sc.c: Indy cache management functions. * * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org), * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). diff -u --recursive --new-file v2.4.2/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c --- v2.4.2/linux/arch/mips/sgi/kernel/setup.c Wed Aug 9 13:46:02 2000 +++ linux/arch/mips/sgi/kernel/setup.c Tue Mar 6 19:44:36 2001 @@ -165,7 +165,7 @@ *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST); /* Return the difference, this is how far the r4k counter increments - * for every 1/HZ seconds. We round off the the nearest 1 MHz of + * for every 1/HZ seconds. We round off the nearest 1 MHz of * master clock (= 1000000 / 100 / 2 = 5000 count). */ return ((ct1 - ct0) / 5000) * 5000; diff -u --recursive --new-file v2.4.2/linux/arch/mips64/defconfig linux/arch/mips64/defconfig --- v2.4.2/linux/arch/mips64/defconfig Wed Feb 21 18:20:13 2001 +++ linux/arch/mips64/defconfig Sun Mar 4 14:30:18 2001 @@ -165,6 +165,7 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -u --recursive --new-file v2.4.2/linux/arch/mips64/kernel/mips64_ksyms.c linux/arch/mips64/kernel/mips64_ksyms.c --- v2.4.2/linux/arch/mips64/kernel/mips64_ksyms.c Thu Jul 27 18:36:54 2000 +++ linux/arch/mips64/kernel/mips64_ksyms.c Fri Mar 2 11:15:47 2001 @@ -121,3 +121,4 @@ #endif EXPORT_SYMBOL(get_wchan); +EXPORT_SYMBOL(flush_tlb_page); diff -u --recursive --new-file v2.4.2/linux/arch/mips64/mm/fault.c linux/arch/mips64/mm/fault.c --- v2.4.2/linux/arch/mips64/mm/fault.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/mm/fault.c Tue Mar 6 19:44:36 2001 @@ -61,7 +61,7 @@ /* * Unlock any spinlocks which will prevent us from getting the - * message out (timerlist_lock is aquired through the + * message out (timerlist_lock is acquired through the * console unblank code) */ void bust_spinlocks(void) diff -u --recursive --new-file v2.4.2/linux/arch/mips64/sgi-ip22/ip22-sc.c linux/arch/mips64/sgi-ip22/ip22-sc.c --- v2.4.2/linux/arch/mips64/sgi-ip22/ip22-sc.c Sat May 13 08:30:17 2000 +++ linux/arch/mips64/sgi-ip22/ip22-sc.c Tue Mar 6 19:44:36 2001 @@ -1,6 +1,6 @@ /* $Id: ip22-sc.c,v 1.2 1999/12/04 03:59:01 ralf Exp $ * - * indy_sc.c: Indy cache managment functions. + * indy_sc.c: Indy cache management functions. * * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org), * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/Config.in linux/arch/ppc/8xx_io/Config.in --- v2.4.2/linux/arch/ppc/8xx_io/Config.in Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/8xx_io/Config.in Sat Mar 3 10:52:13 2001 @@ -7,24 +7,24 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then bool 'CPM SCC Ethernet' CONFIG_SCC_ENET if [ "$CONFIG_SCC_ENET" = "y" ]; then - bool 'Ethernet on SCC1' CONFIG_SCC1_ENET - if [ "$CONFIG_SCC1_ENET" != "y" ]; then - bool 'Ethernet on SCC2' CONFIG_SCC2_ENET - fi + choice 'SCC used for Ethernet' \ + "SCC1 CONFIG_SCC1_ENET \ + SCC2 CONFIG_SCC2_ENET \ + SCC3 CONFIG_SCC3_ENET" SCC1 fi bool '860T FEC Ethernet' CONFIG_FEC_ENET + if [ "$CONFIG_FEC_ENET" = "y" ]; then + bool 'Use MDIO for PHY configuration' CONFIG_USE_MDIO + fi bool 'Use Big CPM Ethernet Buffers' CONFIG_ENET_BIG_BUFFERS fi bool 'Use SMC2 for UART' CONFIG_8xxSMC2 if [ "$CONFIG_8xxSMC2" = "y" ]; then bool 'Use Alternate SMC2 I/O (823/850)' CONFIG_8xx_ALTSMC2 + bool 'Use SMC2 for Console' CONFIG_8xx_CONS_SMC2 fi bool 'Enable SCC2 and SCC3 for UART' CONFIG_8xxSCC -if [ "$CONFIG_TQM860" = "y" -o "$CONFIG_TQM860L" = "y" -o "$CONFIG_TQM8xxL" = "y" ]; then - bool 'Use SMC2 for Console' TQM_SMC2_CONSOLE -fi - # This doesn't really belong here, but it is convenient to ask # 8xx specific questions. @@ -32,4 +32,7 @@ bool 'Copy-Back Data Cache (else Writethrough)' CONFIG_8xx_COPYBACK bool 'CPU6 Silicon Errata (860 Pre Rev. C)' CONFIG_8xx_CPU6 +if [ "$CONFIG_IDE" = "y" ]; then + bool 'MPC8xx direct IDE support on PCMCIA port' CONFIG_BLK_DEV_MPC8xx_IDE +fi endmenu diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/commproc.c linux/arch/ppc/8xx_io/commproc.c --- v2.4.2/linux/arch/ppc/8xx_io/commproc.c Sat Nov 11 18:14:38 2000 +++ linux/arch/ppc/8xx_io/commproc.c Sat Mar 3 10:52:13 2001 @@ -61,22 +61,6 @@ imp = (immap_t *)IMAP_ADDR; commproc = (cpm8xx_t *)&imp->im_cpm; -#ifdef notdef - /* We can't do this. It seems to blow away the microcode - * patch that EPPC-Bug loaded for us. EPPC-Bug uses SCC1 for - * Ethernet, SMC1 for the console, and I2C for serial EEPROM. - * Our own drivers quickly reset all of these. - */ - - /* Perform a reset. - */ - commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); - - /* Wait for it. - */ - while (commproc->cp_cpcr & CPM_CR_FLG); -#endif - /* Set SDMA Bus Request priority 5. * On 860T, this also enables FEC priority 6. I am not sure * this is what we realy want for some applications, but the @@ -168,6 +152,14 @@ void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id) { + + /* If null handler, assume we are trying to free the IRQ. + */ + if (!handler) { + cpm_free_handler(vec); + return; + } + if (cpm_vecs[vec].handler != 0) printk("CPM interrupt %x replacing %x\n", (uint)handler, (uint)cpm_vecs[vec].handler); @@ -226,8 +218,9 @@ * The internal baud rate clock is the system clock divided by 16. * This assumes the baudrate is 16x oversampled by the uart. */ -#define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) -#define BRG_UART_CLK (BRG_INT_CLK/16) +#define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) +#define BRG_UART_CLK (BRG_INT_CLK/16) +#define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) void m8xx_cpm_setbrg(uint brg, uint rate) @@ -238,6 +231,12 @@ */ bp = (uint *)&cpmp->cp_brgc1; bp += brg; - *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN; + /* The BRG has a 12-bit counter. For really slow baud rates (or + * really fast processors), we may have to further divide by 16. + */ + if (((BRG_UART_CLK / rate) - 1) < 4096) + *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN; + else + *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | + CPM_BRG_EN | CPM_BRG_DIV16; } - diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/commproc.h linux/arch/ppc/8xx_io/commproc.h --- v2.4.2/linux/arch/ppc/8xx_io/commproc.h Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/8xx_io/commproc.h Sat Mar 3 10:52:13 2001 @@ -324,7 +324,7 @@ */ #define SCC_EB ((u_char)0x10) /* Set big endian byte order */ -/* CPM Ethernet through SCC1. +/* CPM Ethernet through SCCx. */ typedef struct scc_enet { sccp_t sen_genscc; @@ -379,6 +379,8 @@ ushort sen_taddrl; /* temp address (LSB) */ } scc_enet_t; +/*** MBX ************************************************************/ + #ifdef CONFIG_MBX /* Bits in parallel I/O port registers that have to be set/cleared * to configure the pins for SCC1 use. The TCLK and RCLK seem unique @@ -399,7 +401,9 @@ */ #define SICR_ENET_MASK ((uint)0x000000ff) #define SICR_ENET_CLKRT ((uint)0x0000003d) -#endif +#endif /* CONFIG_MBX */ + +/*** RPXLITE ********************************************************/ #ifdef CONFIG_RPXLITE /* This ENET stuff is for the MPC850 with ethernet on SCC2. Some of @@ -416,7 +420,9 @@ #define SICR_ENET_MASK ((uint)0x0000ff00) #define SICR_ENET_CLKRT ((uint)0x00003d00) -#endif +#endif /* CONFIG_RPXLITE */ + +/*** BSEIP **********************************************************/ #ifdef CONFIG_BSEIP /* This ENET stuff is for the MPC823 with ethernet on SCC2. @@ -438,7 +444,9 @@ #define SICR_ENET_MASK ((uint)0x0000ff00) #define SICR_ENET_CLKRT ((uint)0x00002c00) -#endif +#endif /* CONFIG_BSEIP */ + +/*** RPXCLASSIC *****************************************************/ #ifdef CONFIG_RPXCLASSIC /* Bits in parallel I/O port registers that have to be set/cleared @@ -457,27 +465,63 @@ */ #define SICR_ENET_MASK ((uint)0x000000ff) #define SICR_ENET_CLKRT ((uint)0x0000003d) -#endif +#endif /* CONFIG_RPXCLASSIC */ + +/*** TQM823L, TQM850L ***********************************************/ + +#if defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L) +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ +#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */ +#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */ +#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ + +#define PB_ENET_TENA ((uint)0x00002000) /* PB 18 */ + +#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */ +#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */ + +/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to + * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero. + */ +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00002600) +#endif /* CONFIG_TQM823L, CONFIG_TQM850L */ + +/*** FPS850L *********************************************************/ + +#ifdef CONFIG_FPS850L +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ +#define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */ +#define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */ +#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ + +#define PC_ENET_TENA ((ushort)0x0002) /* PC 14 */ +#define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */ +#define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */ -#if (defined(CONFIG_TQM860) || defined(CONFIG_TQM860L)) -/* - * TQM860 and TQM860L Configuration: - * - * Signal PAR DIR ODR DAT Function - * Port A, 5 1 0 - - TCLK (CLK3) for Ethernet - * Port A, 7 1 0 - - RCLK (CLK1) for Ethernet - * Port A, 14 1 0 - - TXD for Ethernet (SCC1) - * Port A, 15 1 0 - - RXD for Ethernet (SCC1) - * Port C, 7 0 0 0 - -> ETH-LOOP - * Port C, 10 0 0 1 - CD for Ethernet (SCC1) - * Port C, 11 0 0 1 - CTS for Ethernet (SCC1) - * Port C, 15 * * 0 - TENA/RTS for Ethernet +/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to + * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero. */ +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00002600) +#endif /* CONFIG_FPS850L */ + +/*** TQM860L ********************************************************/ +#ifdef CONFIG_TQM860L +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ #define PA_ENET_RXD ((ushort)0x0001) /* PA 15 */ #define PA_ENET_TXD ((ushort)0x0002) /* PA 14 */ -#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ #define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ #define PC_ENET_TENA ((ushort)0x0001) /* PC 15 */ #define PC_ENET_CLSN ((ushort)0x0010) /* PC 11 */ @@ -488,51 +532,59 @@ */ #define SICR_ENET_MASK ((uint)0x000000ff) #define SICR_ENET_CLKRT ((uint)0x00000026) +#endif /* CONFIG_TQM860L */ -#endif /* CONFIG_TQM860, TQM860L */ +/*** SPD823TS *******************************************************/ -#ifdef CONFIG_TQM8xxL -/* - * TQM8xxL Configuration (except TQM860L): - * - * Signal PAR DIR ODR DAT Function - * Port A, 5 1 0 - - TCLK (CLK3) for Ethernet - * Port A, 7 1 0 - - RCLK (CLK1) for Ethernet - * Port A, 12 1 0 - - TXD for Ethernet (SCC2) - * Port A, 13 1 0 - - RXD for Ethernet (SCC2) - * Port B, 18 1 1 - - TENA/RTS for Ethernet on STK8xx - * Port C, 7 0 0 0 - -> ETH-LOOP - * Port C, 8 0 0 1 - CD for Ethernet (SCC2) - * Port C, 9 0 0 1 - CTS for Ethernet (SCC2) - * Port C, 14 * * 0 - TENA/RTS for Ethernet on FPS850 - * - * Note: Using PC14 as RTS2 (TENA) does not work on the TQM850L when - * used with the starter-kit mainboard; we *must* use PB18 instead. - * For the FPS850 system, we *must* use PC14 :-( +#ifdef CONFIG_SPD823TS +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC2 use. */ - +#define PA_ENET_MDC ((ushort)0x0001) /* PA 15 !!! */ +#define PA_ENET_MDIO ((ushort)0x0002) /* PA 14 !!! */ #define PA_ENET_RXD ((ushort)0x0004) /* PA 13 */ #define PA_ENET_TXD ((ushort)0x0008) /* PA 12 */ -#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_RCLK ((ushort)0x0200) /* PA 6 */ #define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ -#ifndef CONFIG_FPS850 /* not valid on FPS board */ -#define PB_ENET_TENA ((uint)0x00002000) -#endif /* !CONFIG_FPS850 */ +#define PB_ENET_TENA ((uint)0x00002000) /* PB 18 */ -#ifdef CONFIG_FPS850 /* FPS uses default configuration */ -#define PC_ENET_TENA ((ushort)0x0002) /* PC 14 */ -#endif /* CONFIG_FPS850 */ #define PC_ENET_CLSN ((ushort)0x0040) /* PC 9 */ #define PC_ENET_RENA ((ushort)0x0080) /* PC 8 */ +#define PC_ENET_RESET ((ushort)0x0100) /* PC 7 !!! */ -/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to +/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK2) to * SCC2. Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero. */ #define SICR_ENET_MASK ((uint)0x0000ff00) -#define SICR_ENET_CLKRT ((uint)0x00002600) +#define SICR_ENET_CLKRT ((uint)0x00002E00) +#endif /* CONFIG_SPD823TS */ + + +/*** SM850 *********************************************************/ -#endif /* CONFIG_TQM8xxL */ +/* The SM850 Service Module uses SCC2 for IrDA and SCC3 for Ethernet */ + +#ifdef CONFIG_SM850 +#define PB_ENET_RXD ((uint)0x00000004) /* PB 29 */ +#define PB_ENET_TXD ((uint)0x00000002) /* PB 30 */ +#define PA_ENET_RCLK ((ushort)0x0100) /* PA 7 */ +#define PA_ENET_TCLK ((ushort)0x0400) /* PA 5 */ + +#define PC_ENET_LBK ((ushort)0x0008) /* PC 12 */ +#define PC_ENET_TENA ((ushort)0x0004) /* PC 13 */ + +#define PC_ENET_RENA ((ushort)0x0800) /* PC 4 */ +#define PC_ENET_CLSN ((ushort)0x0400) /* PC 5 */ + +/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to + * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero. + */ +#define SICR_ENET_MASK ((uint)0x00FF0000) +#define SICR_ENET_CLKRT ((uint)0x00260000) +#endif /* CONFIG_SM850 */ + +/*********************************************************************/ /* SCC Event register as used by Ethernet. */ @@ -723,8 +775,6 @@ #define CPMVEC_PIO_PC4 ((ushort)0x01) #define CPMVEC_ERROR ((ushort)0x00) -extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); - /* CPM interrupt configuration vector. */ #define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */ @@ -735,4 +785,8 @@ #define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */ #define CICR_IEN ((uint)0x00000080) /* Int. enable */ #define CICR_SPS ((uint)0x00000001) /* SCC Spread */ + +extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); +extern void cpm_free_handler(int vec); + #endif /* __CPM_8XX__ */ diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c --- v2.4.2/linux/arch/ppc/8xx_io/enet.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/8xx_io/enet.c Sat Mar 3 10:52:13 2001 @@ -154,20 +154,26 @@ /*static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/ /* Typically, 860(T) boards use SCC1 for Ethernet, and other 8xx boards - * use SCC2. This is easily extended if necessary. + * use SCC2. Some even may use SCC3. + * This is easily extended if necessary. */ -#ifdef CONFIG_SCC2_ENET +#if defined(CONFIG_SCC3_ENET) +#define CPM_CR_ENET CPM_CR_CH_SCC3 +#define PROFF_ENET PROFF_SCC3 +#define SCC_ENET 2 /* Index, not number! */ +#define CPMVEC_ENET CPMVEC_SCC3 +#elif defined(CONFIG_SCC2_ENET) #define CPM_CR_ENET CPM_CR_CH_SCC2 #define PROFF_ENET PROFF_SCC2 #define SCC_ENET 1 /* Index, not number! */ #define CPMVEC_ENET CPMVEC_SCC2 -#endif - -#ifdef CONFIG_SCC1_ENET -#define CPM_CR_ENET CPM_CR_CH_SCC1 +#elif defined(CONFIG_SCC1_ENET) +#define CPM_CR_ENET CPM_CR_CH_SCC1 #define PROFF_ENET PROFF_SCC1 -#define SCC_ENET 0 +#define SCC_ENET 0 /* Index, not number! */ #define CPMVEC_ENET CPMVEC_SCC1 +#else +#error CONFIG_SCCx_ENET not defined #endif static int @@ -642,10 +648,11 @@ volatile scc_t *sccp; volatile scc_enet_t *ep; volatile immap_t *immap; + extern unsigned long _get_IMMR(void); cp = cpmp; /* Get pointer to Communication Processor */ - immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ + immap = (immap_t *)(_get_IMMR() & 0xFFFF0000); /* and to internal registers */ bd = (bd_t *)__res; @@ -683,28 +690,47 @@ * It can't last though...... */ +#if (defined(PA_ENET_RXD) && defined(PA_ENET_TXD)) /* Configure port A pins for Txd and Rxd. */ - immap->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD); + immap->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD); immap->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD); - immap->im_ioport.iop_paodr &= ~PA_ENET_TXD; + immap->im_ioport.iop_paodr &= ~PA_ENET_TXD; +#elif (defined(PB_ENET_RXD) && defined(PB_ENET_TXD)) + /* Configure port B pins for Txd and Rxd. + */ + immap->im_cpm.cp_pbpar |= (PB_ENET_RXD | PB_ENET_TXD); + immap->im_cpm.cp_pbdir &= ~(PB_ENET_RXD | PB_ENET_TXD); + immap->im_cpm.cp_pbodr &= ~PB_ENET_TXD; +#else +#error Exactly ONE pair of PA_ENET_[RT]XD, PB_ENET_[RT]XD must be defined +#endif + +#if defined(PC_ENET_LBK) + /* Configure port C pins to disable External Loopback + */ + immap->im_ioport.iop_pcpar &= ~PC_ENET_LBK; + immap->im_ioport.iop_pcdir |= PC_ENET_LBK; + immap->im_ioport.iop_pcso &= ~PC_ENET_LBK; + immap->im_ioport.iop_pcdat &= ~PC_ENET_LBK; /* Disable Loopback */ +#endif /* PC_ENET_LBK */ /* Configure port C pins to enable CLSN and RENA. */ immap->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA); immap->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA); - immap->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA); + immap->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA); /* Configure port A for TCLK and RCLK. */ - immap->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK); + immap->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK); immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK); /* Configure Serial Interface clock routing. * First, clear all SCC bits to zero, then set the ones we want. */ cp->cp_sicr &= ~SICR_ENET_MASK; - cp->cp_sicr |= SICR_ENET_CLKRT; + cp->cp_sicr |= SICR_ENET_CLKRT; /* Manual says set SDDR, but I can't find anything with that * name. I think it is a misprint, and should be SDCR. This @@ -884,20 +910,17 @@ /* It is now OK to enable the Ethernet transmitter. * Unfortunately, there are board implementation differences here. */ -#if (defined(CONFIG_MBX) || defined(CONFIG_TQM860) || defined(CONFIG_TQM860L) || defined(CONFIG_FPS850)) - immap->im_ioport.iop_pcpar |= PC_ENET_TENA; +#if (!defined (PB_ENET_TENA) && defined (PC_ENET_TENA)) + immap->im_ioport.iop_pcpar |= PC_ENET_TENA; immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA; -#endif - -#if (defined(CONFIG_TQM8xxL) && !defined(CONFIG_FPS850)) +#elif ( defined (PB_ENET_TENA) && !defined (PC_ENET_TENA)) cp->cp_pbpar |= PB_ENET_TENA; cp->cp_pbdir |= PB_ENET_TENA; +#else +#error Configuration Error: define exactly ONE of PB_ENET_TENA, PC_ENET_TENA #endif #if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC) - cp->cp_pbpar |= PB_ENET_TENA; - cp->cp_pbdir |= PB_ENET_TENA; - /* And while we are here, set the configuration to enable ethernet. */ *((volatile uint *)RPX_CSR_ADDR) &= ~BCSR0_ETHLPBK; @@ -906,9 +929,6 @@ #endif #ifdef CONFIG_BSEIP - cp->cp_pbpar |= PB_ENET_TENA; - cp->cp_pbdir |= PB_ENET_TENA; - /* BSE uses port B and C for PHY control. */ cp->cp_pbpar &= ~(PB_BSE_POWERUP | PB_BSE_FDXDIS); @@ -941,11 +961,12 @@ */ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - printk("%s: CPM ENET Version 0.2, ", dev->name); + printk("%s: CPM ENET Version 0.2 on SCC%d, ", dev->name, SCC_ENET+1); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); printk("%02x\n", dev->dev_addr[5]); return 0; } + diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c --- v2.4.2/linux/arch/ppc/8xx_io/fec.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/8xx_io/fec.c Sat Mar 3 10:52:13 2001 @@ -8,7 +8,9 @@ * describes connections using the internal parallel port I/O, which * is basically all of Port D. * - * Right now, I am very watseful with the buffers. I allocate memory + * Includes support for the following PHYs: QS6612, LXT970, LXT971/2. + * + * Right now, I am very wasteful with the buffers. I allocate memory * pages and then divide them into 2K frame buffers. This way I know I * have buffers large enough to hold one frame within one buffer descriptor. * Once I get this working, I will use 64 or 128 byte CPM buffers, which @@ -18,13 +20,16 @@ * Much better multiple PHY support by Magnus Damm. * Copyright (c) 2000 Ericsson Radio Systems AB. * + * Make use of MII for PHY control configurable. + * Some fixes. + * Copyright (c) 2000 Wolfgang Denk, DENX Software Engineering. */ /* List of PHYs we wish to support. */ -#define CONFIG_FEC_LXT970 -#define CONFIG_FEC_LXT971 -#define CONFIG_FEC_QS6612 +#undef CONFIG_FEC_LXT970 +#define CONFIG_FEC_LXT971 +#undef CONFIG_FEC_QS6612 #include #include @@ -54,6 +59,7 @@ #include #include "commproc.h" +#ifdef CONFIG_USE_MDIO /* Forward declarations of some structures to support different PHYs */ @@ -71,6 +77,7 @@ const phy_cmd_t *ack_int; const phy_cmd_t *shutdown; } phy_info_t; +#endif /* CONFIG_USE_MDIO */ /* The number of Tx and Rx buffers. These are allocated from the page * pool. The code may assume these are power of two, so it is best @@ -78,20 +85,20 @@ * We don't need to allocate pages for the transmitter. We just use * the skbuffer directly. */ -#if 1 -#define FEC_ENET_RX_PAGES 4 +#ifdef CONFIG_ENET_BIG_BUFFERS +#define FEC_ENET_RX_PAGES 16 #define FEC_ENET_RX_FRSIZE 2048 #define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) #define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) -#define TX_RING_SIZE 8 /* Must be power of two */ -#define TX_RING_MOD_MASK 7 /* for this to work */ +#define TX_RING_SIZE 16 /* Must be power of two */ +#define TX_RING_MOD_MASK 15 /* for this to work */ #else -#define FEC_ENET_RX_PAGES 16 +#define FEC_ENET_RX_PAGES 4 #define FEC_ENET_RX_FRSIZE 2048 #define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) #define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) -#define TX_RING_SIZE 16 /* Must be power of two */ -#define TX_RING_MOD_MASK 15 /* for this to work */ +#define TX_RING_SIZE 8 /* Must be power of two */ +#define TX_RING_MOD_MASK 7 /* for this to work */ #endif /* Interrupt events/masks. @@ -107,6 +114,26 @@ #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ +/* +*/ +#define FEC_ECNTRL_PINMUX 0x00000004 +#define FEC_ECNTRL_ETHER_EN 0x00000002 +#define FEC_ECNTRL_RESET 0x00000001 + +#define FEC_RCNTRL_BC_REJ 0x00000010 +#define FEC_RCNTRL_PROM 0x00000008 +#define FEC_RCNTRL_MII_MODE 0x00000004 +#define FEC_RCNTRL_DRT 0x00000002 +#define FEC_RCNTRL_LOOP 0x00000001 + +#define FEC_TCNTRL_FDEN 0x00000004 +#define FEC_TCNTRL_HBC 0x00000002 +#define FEC_TCNTRL_GTS 0x00000001 + +/* Delay to wait for FEC reset command to complete (in us) +*/ +#define FEC_RESET_DELAY 50 + /* The FEC stores dest/src/type, data, and checksum for receive packets. */ #define PKT_MAXBUF_SIZE 1518 @@ -138,6 +165,7 @@ uint tx_full; spinlock_t lock; +#ifdef CONFIG_USE_MDIO uint phy_id; uint phy_id_done; uint phy_status; @@ -148,6 +176,7 @@ uint sequence_done; uint phy_addr; +#endif /* CONFIG_USE_MDIO */ int link; int old_link; @@ -165,7 +194,9 @@ static int fec_enet_open(struct net_device *dev); static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +#ifdef CONFIG_USE_MDIO static void fec_enet_mii(struct net_device *dev); +#endif /* CONFIG_USE_MDIO */ static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); #ifdef CONFIG_FEC_PACKETHOOK static void fec_enet_tx(struct net_device *dev, __u32 regval); @@ -181,6 +212,7 @@ static void fec_stop(struct net_device *dev); static ushort my_enet_addr[3]; +#ifdef CONFIG_USE_MDIO /* MII processing. We keep this as simple as possible. Requests are * placed on the list (if there is room). When the request is finished * by the MII, an optional function may be called. @@ -197,7 +229,7 @@ mii_list_t *mii_head; mii_list_t *mii_tail; -static int mii_queue(struct net_device *dev, int request, +static int mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *)); /* Make MII read/write commands for the FEC. @@ -206,11 +238,13 @@ #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \ (VAL & 0xffff)) #define mk_mii_end 0 +#endif /* CONFIG_USE_MDIO */ /* Transmitter timeout. */ #define TX_TIMEOUT (2*HZ) +#ifdef CONFIG_USE_MDIO /* Register definitions for the PHY. */ @@ -218,7 +252,7 @@ #define MII_REG_SR 1 /* Status Register */ #define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */ #define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */ -#define MII_REG_ANAR 4 /* A-N Advertisement Register */ +#define MII_REG_ANAR 4 /* A-N Advertisement Register */ #define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */ #define MII_REG_ANER 6 /* A-N Expansion Register */ #define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */ @@ -230,18 +264,19 @@ #define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ #define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ #define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ -#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ +#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ #define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ -#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ +#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ #define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ #define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ #define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ #define PHY_STAT_SPMASK 0xf000 /* mask for speed */ #define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ -#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ +#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ #define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ -#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ +#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ +#endif /* CONFIG_USE_MDIO */ #ifdef CONFIG_FEC_PACKETHOOK int @@ -291,7 +326,7 @@ fep->ph_proto = 0; fep->ph_regaddr = NULL; fep->ph_priv = NULL; - + fep->ph_lock = 0; return retval; @@ -345,7 +380,7 @@ fep->stats.tx_bytes += skb->len; fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; - + /* Push the data cache so the CPM does not get stale memory * data. */ @@ -404,7 +439,7 @@ bdp = fep->tx_bd_base; printk(" tx: %u buffers\n", TX_RING_SIZE); for (i = 0 ; i < TX_RING_SIZE; i++) { - printk(" %08x: %04x %04x %08x\n", + printk(" %08x: %04x %04x %08x\n", (uint) bdp, bdp->cbd_sc, bdp->cbd_datlen, @@ -443,7 +478,6 @@ if (fep->ph_regaddr) regval = *fep->ph_regaddr; #endif - fecp = (volatile fec_t*)dev->base_addr; /* Get the interrupt events that caused us to be here. @@ -478,9 +512,13 @@ } if (int_events & FEC_ENET_MII) { +#ifdef CONFIG_USE_MDIO fec_enet_mii(dev); +#else +printk("%s[%d] %s: unexpected FEC_ENET_MII event\n", __FILE__,__LINE__,__FUNCTION__); +#endif /* CONFIG_USE_MDIO */ } - + } } @@ -541,23 +579,23 @@ */ if (bdp->cbd_sc & BD_ENET_TX_DEF) fep->stats.collisions++; - + /* Free the sk buffer associated with this last transmit. */ #if 0 printk("TXI: %x %x %x\n", bdp, skb, fep->skb_dirty); #endif - dev_kfree_skb(skb/*, FREE_WRITE*/); + dev_kfree_skb_irq (skb/*, FREE_WRITE*/); fep->tx_skbuff[fep->skb_dirty] = NULL; fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; - + /* Update pointer to next buffer descriptor to be transmitted. */ if (bdp->cbd_sc & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; else bdp++; - + /* Since we have freed up a buffer, the ring is no longer * full. */ @@ -617,7 +655,7 @@ /* Check for errors. */ if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { - fep->stats.rx_errors++; + fep->stats.rx_errors++; if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { /* Frame too long or too short. */ fep->stats.rx_length_errors++; @@ -703,7 +741,7 @@ bdp = fep->rx_bd_base; else bdp++; - + #if 1 /* Doing this here will keep the FEC running while we process * incoming frames. On a heavily loaded network, we should be @@ -732,6 +770,7 @@ } +#ifdef CONFIG_USE_MDIO static void fec_enet_mii(struct net_device *dev) { @@ -743,7 +782,7 @@ fep = (struct fec_enet_private *)dev->priv; ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); mii_reg = ep->fec_mii_data; - + if ((mip = mii_head) == NULL) { printk("MII and no head!\n"); return; @@ -756,8 +795,9 @@ mip->mii_next = mii_free; mii_free = mip; - if ((mip = mii_head) != NULL) + if ((mip = mii_head) != NULL) { ep->fec_mii_data = mip->mii_regval; + } } static int @@ -786,13 +826,11 @@ if (mii_head) { mii_tail->mii_next = mip; mii_tail = mip; - } - else { + } else { mii_head = mii_tail = mip; (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval; } - } - else { + } else { retval = 1; } @@ -808,7 +846,7 @@ if(!c) return; - for(k = 0; (c+k)->mii_data != mk_mii_end; k++) + for(k = 0; (c+k)->mii_data != mk_mii_end; k++) mii_queue(dev, (c+k)->mii_data, (c+k)->funct); } @@ -896,7 +934,7 @@ } static phy_info_t phy_info_lxt970 = { - 0x07810000, + 0x07810000, "LXT970", (const phy_cmd_t []) { /* config */ @@ -919,12 +957,12 @@ }, (const phy_cmd_t []) { /* ack_int */ /* read SR and ISR to acknowledge */ - + { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT970_ISR), NULL }, /* find out the current status */ - + { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, { mk_mii_end, } }, @@ -933,7 +971,7 @@ { mk_mii_end, } }, }; - + #endif /* CONFIG_FEC_LXT970 */ /* ------------------------------------------------------------------------- */ @@ -950,7 +988,7 @@ #define MII_LXT971_LCR 20 /* LED Control Register */ #define MII_LXT971_TCR 30 /* Transmit Control Register */ -/* +/* * I had some nice ideas of running the MDIO faster... * The 971 should support 8MHz and I tried it, but things acted really * weird, so 2.5 MHz ought to be enough for anyone... @@ -980,14 +1018,11 @@ } static phy_info_t phy_info_lxt971 = { - 0x0001378e, + 0x0001378e, "LXT971", - - (const phy_cmd_t []) { /* config */ - /* limit to 10MBit because my protorype board - * doesn't work with 100. */ - { mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */ + (const phy_cmd_t []) { /* config */ +// { mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10 Mbps, HD */ { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } @@ -995,12 +1030,12 @@ (const phy_cmd_t []) { /* startup - enable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ - + /* Somehow does the 971 tell me that the link is down * the first read after power-up. * read here to get a valid value in ack_int */ - { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ @@ -1008,9 +1043,9 @@ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, - + /* we only need to read ISR to acknowledge */ - + { mk_mii_read(MII_LXT971_ISR), NULL }, { mk_mii_end, } }, @@ -1053,13 +1088,13 @@ } static phy_info_t phy_info_qs6612 = { - 0x00181440, + 0x00181440, "QS6612", - - (const phy_cmd_t []) { /* config */ -// { mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */ - /* The PHY powers up isolated on the RPX, + (const phy_cmd_t []) { /* config */ +// { mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 Mbps */ + + /* The PHY powers up isolated on the RPX, * so send a command to allow operation. */ @@ -1077,9 +1112,9 @@ { mk_mii_end, } }, (const phy_cmd_t []) { /* ack_int */ - + /* we need to read ISR, SR and ANER to acknowledge */ - + { mk_mii_read(MII_QS6612_ISR), NULL }, { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_REG_ANER), NULL }, @@ -1134,10 +1169,10 @@ printk("link up"); switch(*s & PHY_STAT_SPMASK) { - case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break; - case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break; - case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break; - case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break; + case PHY_STAT_100FDX: printk(", 100 Mbps Full Duplex"); break; + case PHY_STAT_100HDX: printk(", 100 Mbps Half Duplex"); break; + case PHY_STAT_10FDX: printk(", 10 Mbps Full Duplex"); break; + case PHY_STAT_10HDX: printk(", 10 Mbps Half Duplex"); break; default: printk(", Unknown speed/duplex"); } @@ -1177,7 +1212,7 @@ if (*s & PHY_CONF_LOOP) printk(", loopback enabled"); - + printk(".\n"); fep->sequence_done = 1; @@ -1194,7 +1229,7 @@ if (fep->link) { duplex = 0; - if (fep->phy_status + if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) duplex = 1; fec_restart(dev, duplex); @@ -1245,18 +1280,20 @@ fep = dev->priv; fep->phy_id |= (mii_reg & 0xffff); - printk("fec: Phy @ 0x%x, type 0x%08x\n", fep->phy_addr, fep->phy_id); for(i = 0; phy_info[i]; i++) if(phy_info[i]->id == (fep->phy_id >> 4)) break; if(!phy_info[i]) - panic("%s: PHY id 0x%08x is not supported!\n", + panic("%s: PHY id 0x%08x is not supported!\n", dev->name, fep->phy_id); - + fep->phy = phy_info[i]; fep->phy_id_done = 1; + + printk("%s: Phy @ 0x%x, type %s (0x%08x)\n", + dev->name, fep->phy_addr, fep->phy->name, fep->phy_id); } /* Scan all of the MII PHY addresses looking for someone to respond @@ -1270,25 +1307,23 @@ fep = dev->priv; - if (fep->phy_addr < 32) { - if ((phytype = (mii_reg & 0xffff)) != 0xffff) { - - /* Got first part of ID, now get remainder. - */ - fep->phy_id = phytype << 16; - mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), - mii_discover_phy3); - } - else { - fep->phy_addr++; + if ((phytype = (mii_reg & 0xffff)) != 0xffff) { + + /* Got first part of ID, now get remainder. + */ + fep->phy_id = phytype << 16; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3); + } else { + fep->phy_addr++; + if (fep->phy_addr < 32) { mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); + } else { + printk("fec: No PHY device found.\n"); } } - else { - printk("FEC: No PHY device found.\n"); - } } +#endif /* CONFIG_USE_MDIO */ /* This interrupt occurs when the PHY detects a link change. */ @@ -1299,16 +1334,36 @@ mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) #endif { +#ifdef CONFIG_USE_MDIO struct net_device *dev = dev_id; struct fec_enet_private *fep = dev->priv; + volatile immap_t *immap = (immap_t *)IMAP_ADDR; + volatile fec_t *fecp = &(immap->im_cpm.cp_fec); + unsigned int ecntrl = fecp->fec_ecntrl; + + /* We need the FEC enabled to access the MII + */ + if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) { + fecp->fec_ecntrl |= FEC_ECNTRL_ETHER_EN; + } +#endif /* CONFIG_USE_MDIO */ #if 0 disable_irq(fep->mii_irq); /* disable now, enable later */ #endif + +#ifdef CONFIG_USE_MDIO mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ + if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) { + fecp->fec_ecntrl = ecntrl; /* restore old settings */ + } +#else +printk("%s[%d] %s: unexpected Link interrupt\n", __FILE__,__LINE__,__FUNCTION__); +#endif /* CONFIG_USE_MDIO */ + } static int @@ -1320,6 +1375,7 @@ * a simple way to do that. */ +#ifdef CONFIG_USE_MDIO fep->sequence_done = 0; fep->link = 0; @@ -1327,7 +1383,6 @@ mii_do_cmd(dev, fep->phy->ack_int); mii_do_cmd(dev, fep->phy->config); mii_do_cmd(dev, phy_cmd_config); /* display configuration */ - while(!fep->sequence_done) schedule(); @@ -1335,8 +1390,12 @@ netif_start_queue(dev); return 0; /* Success */ } - return -ENODEV; /* No PHY we understand */ +#else + fep->link = 1; + netif_start_queue(dev); + return 0; /* Success */ +#endif /* CONFIG_USE_MDIO */ } @@ -1377,13 +1436,13 @@ ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); if (dev->flags&IFF_PROMISC) { - + /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); - ep->fec_r_cntrl |= 0x0008; + ep->fec_r_cntrl |= FEC_RCNTRL_PROM; } else { - ep->fec_r_cntrl &= ~0x0008; + ep->fec_r_cntrl &= ~FEC_RCNTRL_PROM; if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the @@ -1404,7 +1463,7 @@ dmi = dev->mc_list; for (i=0; imc_count; i++) { - + /* Only support group multicast for now. */ if (!(dmi->dmi_addr[0] & 1)) @@ -1448,7 +1507,7 @@ volatile fec_t *fecp; bd_t *bd; extern uint _get_IMMR(void); -#ifdef CONFIG_RPXCLASSIC +#ifdef CONFIG_SCC_ENET unsigned char tmpaddr[6]; #endif @@ -1472,8 +1531,15 @@ /* Whack a reset. We should wait for this. */ - fecp->fec_ecntrl = 1; - udelay(10); + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; + for (i = 0; + (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); + ++i) { + udelay(1); + } + if (i == FEC_RESET_DELAY) { + printk ("FEC Reset timeout!\n"); + } /* Set the Ethernet address. If using multiple Enets on the 8xx, * this needs some work to get unique addresses. @@ -1481,12 +1547,13 @@ eap = (unsigned char *)my_enet_addr; iap = bd->bi_enetaddr; -#ifdef CONFIG_RPXCLASSIC - /* The Embedded Planet boards have only one MAC address in - * the EEPROM, but can have two Ethernet ports. For the - * FEC port, we create another address by setting one of - * the address bits above something that would have (up to - * now) been allocated. +#ifdef CONFIG_SCC_ENET + /* + * If a board has Ethernet configured both on a SCC and the + * FEC, it needs (at least) 2 MAC addresses (we know that Sun + * disagrees, but anyway). For the FEC port, we create + * another address by setting one of the address bits above + * something that would have (up to now) been allocated. */ for (i=0; i<6; i++) tmpaddr[i] = *iap++; @@ -1494,8 +1561,9 @@ iap = tmpaddr; #endif - for (i=0; i<6; i++) + for (i=0; i<6; i++) { dev->dev_addr[i] = *eap++ = *iap++; + } /* Allocate memory for buffer descriptors. */ @@ -1518,9 +1586,6 @@ fep->rx_bd_base = cbd_base; fep->tx_bd_base = cbd_base + RX_RING_SIZE; - fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; - fep->cur_rx = fep->rx_bd_base; - fep->skb_cur = fep->skb_dirty = 0; /* Initialize the receive buffer descriptors. @@ -1565,22 +1630,27 @@ */ if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) panic("Could not allocate FEC IRQ!"); + #ifdef CONFIG_RPXCLASSIC /* Make Port C, bit 15 an input that causes interrupts. */ immap->im_ioport.iop_pcpar &= ~0x0001; immap->im_ioport.iop_pcdir &= ~0x0001; - immap->im_ioport.iop_pcso &= ~0x0001; - immap->im_ioport.iop_pcint |= 0x0001; + immap->im_ioport.iop_pcso &= ~0x0001; + immap->im_ioport.iop_pcint |= 0x0001; cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev); /* Make LEDS reflect Link status. */ *((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE; #endif -#ifdef CONFIG_FADS - if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0) + +#ifdef PHY_INTERRUPT + if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0) panic("Could not allocate MII IRQ!"); + + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |= + (0x80000000 >> PHY_INTERRUPT); #endif dev->base_addr = (unsigned long)fecp; @@ -1595,9 +1665,11 @@ dev->get_stats = fec_enet_get_stats; dev->set_multicast_list = set_multicast_list; +#ifdef CONFIG_USE_MDIO for (i=0; iim_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ else immap->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ - + +#ifdef CONFIG_USE_MDIO /* Set MII speed to 2.5 MHz */ - fecp->fec_mii_speed = fep->phy_speed = - ((bd->bi_busfreq * 1000000) / 2500000) & 0x7e; + fecp->fec_mii_speed = fep->phy_speed = + ( + ( ((bd->bi_intfreq * 1000000) + 500000) / 2500000 / 2 ) + & 0x3F + ) << 1; +#else + fecp->fec_mii_speed = 0; /* turn off MDIO */ +#endif /* CONFIG_USE_MDIO */ - printk("%s: FEC ENET Version 0.2, ", dev->name); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); + printk ("%s: FEC ENET Version 0.2, FEC irq %d" +#ifdef PHY_INTERRUPT + ", MII irq %d" +#endif + ", addr ", + dev->name, FEC_INTERRUPT +#ifdef PHY_INTERRUPT + , PHY_INTERRUPT +#endif + ); + for (i=0; i<6; i++) + printk("%02x%c", dev->dev_addr[i], (i==5) ? '\n' : ':'); +#ifdef CONFIG_USE_MDIO /* start in full duplex mode, and negotiate speed */ + fec_restart (dev, 1); +#else /* always use half duplex mode only */ + fec_restart (dev, 0); +#endif + +#ifdef CONFIG_USE_MDIO /* Queue up command to detect the PHY and initialize the * remainder of the interface. */ fep->phy_id_done = 0; fep->phy_addr = 0; mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); +#endif /* CONFIG_USE_MDIO */ return 0; } @@ -1639,7 +1734,6 @@ { struct fec_enet_private *fep; int i; - unsigned char *eap; volatile cbd_t *bdp; volatile immap_t *immap; volatile fec_t *fecp; @@ -1652,33 +1746,25 @@ /* Whack a reset. We should wait for this. */ - fecp->fec_ecntrl = 1; - udelay(10); - - /* Enable interrupts we wish to service. - */ - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); - - /* Clear any outstanding interrupt. - */ - fecp->fec_ievent = 0xffc0; - - fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; + for (i = 0; + (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); + ++i) { + udelay(1); + } + if (i == FEC_RESET_DELAY) { + printk ("FEC Reset timeout!\n"); + } /* Set station address. */ - fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1]; - fecp->fec_addr_high = my_enet_addr[2]; - - eap = (unsigned char *)&my_enet_addr[0]; - for (i=0; i<6; i++) - dev->dev_addr[i] = *eap++; + fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1]; + fecp->fec_addr_high = my_enet_addr[2]; /* Reset all multicast. */ fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; + fecp->fec_hash_table_low = 0; /* Set maximum receive buffer size. */ @@ -1739,12 +1825,12 @@ /* Enable MII mode. */ if (duplex) { - fecp->fec_r_cntrl = 0x04; /* MII enable */ - fecp->fec_x_cntrl = 0x04; /* FD enable */ + fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE; /* MII enable */ + fecp->fec_x_cntrl = FEC_TCNTRL_FDEN; /* FD enable */ } else { - fecp->fec_r_cntrl = 0x06; /* MII enable|No Rcv on Xmit */ - fecp->fec_x_cntrl = 0x00; + fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT; + fecp->fec_x_cntrl = 0; } fep->full_duplex = duplex; @@ -1752,13 +1838,26 @@ */ fecp->fec_fun_code = 0x78000000; +#ifdef CONFIG_USE_MDIO /* Set MII speed. */ fecp->fec_mii_speed = fep->phy_speed; +#endif /* CONFIG_USE_MDIO */ + + /* Clear any outstanding interrupt. + */ + fecp->fec_ievent = 0xffc0; + + fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; + + /* Enable interrupts we wish to service. + */ + fecp->fec_imask = ( FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII ); /* And last, enable the transmit and receive processing. */ - fecp->fec_ecntrl = 6; + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; fecp->fec_r_des_active = 0x01000000; } @@ -1768,33 +1867,45 @@ volatile immap_t *immap; volatile fec_t *fecp; struct fec_enet_private *fep; + int i; immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ - + fecp = &(immap->im_cpm.cp_fec); - + + if ((fecp->fec_ecntrl & FEC_ECNTRL_ETHER_EN) == 0) + return; /* already down */ + fep = dev->priv; fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ - while(!(fecp->fec_ievent & 0x10000000)); - - /* Whack a reset. We should wait for this. - */ - fecp->fec_ecntrl = 1; - udelay(10); + for (i = 0; + ((fecp->fec_ievent & 0x10000000) == 0) && (i < FEC_RESET_DELAY); + ++i) { + udelay(1); + } + if (i == FEC_RESET_DELAY) { + printk ("FEC timeout on graceful transmit stop\n"); + } /* Clear outstanding MII command interrupts. */ fecp->fec_ievent = FEC_ENET_MII; - /* Enable MII command finihed interrupt + /* Enable MII command finished interrupt */ fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; fecp->fec_imask = FEC_ENET_MII; +#ifdef CONFIG_USE_MDIO /* Set MII speed. */ fecp->fec_mii_speed = fep->phy_speed; +#endif /* CONFIG_USE_MDIO */ + + /* Disable FEC + */ + fecp->fec_ecntrl &= ~(FEC_ECNTRL_ETHER_EN); } diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c --- v2.4.2/linux/arch/ppc/8xx_io/uart.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/8xx_io/uart.c Sat Mar 3 10:52:13 2001 @@ -53,10 +53,22 @@ /* this defines the index into rs_table for the port to use */ -#ifndef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 0 -#endif -#endif +# ifndef CONFIG_SERIAL_CONSOLE_PORT +# ifdef CONFIG_SCC3_ENET +# ifdef CONFIG_8xx_CONS_SMC2 +# define CONFIG_SERIAL_CONSOLE_PORT 0 /* Console on SMC2 is 1st port */ +# else +# error "Can't use SMC1 for console with Ethernet on SCC3" +# endif +# else /* ! CONFIG_SCC3_ENET */ +# ifdef CONFIG_8xx_CONS_SMC2 /* Console on SMC2 */ +# define CONFIG_SERIAL_CONSOLE_PORT 1 +# else /* Console on SMC1 */ +# define CONFIG_SERIAL_CONSOLE_PORT 0 +# endif /* CONFIG_8xx_CONS_SMC2 */ +# endif /* CONFIG_SCC3_ENET */ +# endif /* CONFIG_SERIAL_CONSOLE_PORT */ +#endif /* CONFIG_SERIAL_CONSOLE */ #if 0 /* SCC2 for console @@ -118,14 +130,22 @@ */ static struct serial_state rs_table[] = { /* UART CLK PORT IRQ FLAGS NUM */ - { 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */ -#ifdef CONFIG_8xxSMC2 - { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC2 ttyS1 */ -#endif -#ifdef CONFIG_8xxSCC - { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) }, /* SCC2 ttyS2 */ - { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */ +#ifndef CONFIG_SCC3_ENET /* SMC1 not usable with Ethernet on SCC3 */ + { 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */ #endif +#if !defined(CONFIG_USB_MPC8xx) && !defined(CONFIG_USB_CLIENT_MPC8xx) +# ifdef CONFIG_8xxSMC2 + { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC2 ttyS1 */ +# endif +# ifdef CONFIG_8xxSCC + { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) }, /* SCC2 ttyS2 */ + { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */ +# endif + #else /* CONFIG_USB_xxx */ +# ifdef CONFIG_8xxSCC + { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) }, /* SCC3 ttyS3 */ +# endif +#endif /* CONFIG_USB_xxx */ }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) @@ -2733,10 +2753,10 @@ cp->cp_pbdir &= ~iobits; cp->cp_pbodr &= ~iobits; #else + iobits = 0xc0; if (idx == 0) { /* SMC1 on Port B, like all 8xx. */ - iobits = 0xc0; cp->cp_pbpar |= iobits; cp->cp_pbdir &= ~iobits; cp->cp_pbodr &= ~iobits; @@ -2744,7 +2764,6 @@ else { /* SMC2 is on Port A. */ - iobits = 0x300; immap->im_ioport.iop_papar |= iobits; immap->im_ioport.iop_padir &= ~iobits; immap->im_ioport.iop_paodr &= ~iobits; @@ -2836,6 +2855,9 @@ for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++) if (bd->bi_baudrate == baud_table[bidx]) break; + /* make sure we have a useful value */ + if (bidx == (sizeof(baud_table) / sizeof(int))) + bidx = 13; /* B9600 */ co->cflag = CREAD|CLOCAL|bidx|CS8; baud_idx = bidx; @@ -2958,7 +2980,7 @@ */ chan = smc_chan_map[idx]; cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - printk(""); + printk("%s", ""); while (cp->cp_cpcr & CPM_CR_FLG); /* Set UART mode, 8 bit, no parity, one stop. diff -u --recursive --new-file v2.4.2/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.4.2/linux/arch/ppc/config.in Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/config.in Sat Mar 3 10:52:13 2001 @@ -57,14 +57,25 @@ "RPX-Lite CONFIG_RPXLITE \ RPX-Classic CONFIG_RPXCLASSIC \ BSE-IP CONFIG_BSEIP \ - TQM8xxL CONFIG_TQM8xxL \ - TQM860L CONFIG_TQM860L \ - TQM860 CONFIG_TQM860 \ + TQM823L CONFIG_TQM823L \ + TQM850L CONFIG_TQM850L \ + TQM855L CONFIG_TQM855L \ + TQM860L CONFIG_TQM860L \ + FPS850L CONFIG_FPS850L \ + TQM860 CONFIG_TQM860 \ + SPD823TS CONFIG_SPD823TS \ + IVMS8 CONFIG_IVMS8 \ + SM850 CONFIG_SM850 \ MBX CONFIG_MBX \ WinCept CONFIG_WINCEPT" RPX-Lite - - if [ "$CONFIG_TQM8xxL" = "y" ]; then - bool 'FPS850 Mainboard' CONFIG_FPS850 + + if [ "$CONFIG_TQM823L" = "y" -o \ + "$CONFIG_TQM850L" = "y" -o \ + "$CONFIG_FPS850L" = "y" -o \ + "$CONFIG_TQM855L" = "y" -o \ + "$CONFIG_TQM860L" = "y" -o \ + "$CONFIG_SM850" = "y" ]; then + define_bool CONFIG_TQM8xxL y fi fi @@ -298,6 +309,11 @@ else bool ' Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD fi + fi + # This is for drivers/macintosh/mac_hid.o, which is needed if the input + # layer is used. + if [ "$CONFIG_INPUT" != "n" ]; then + define_bool CONFIG_MAC_HID y fi fi endmenu diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/IVMS8_defconfig linux/arch/ppc/configs/IVMS8_defconfig --- v2.4.2/linux/arch/ppc/configs/IVMS8_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/IVMS8_defconfig Sat Mar 3 10:52:13 2001 @@ -0,0 +1,452 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_RPXLITE is not set +# CONFIG_RPXCLASSIC is not set +# CONFIG_BSEIP is not set +# CONFIG_TQM823L is not set +# CONFIG_TQM850L is not set +# CONFIG_TQM855L is not set +# CONFIG_TQM860L is not set +# CONFIG_FPS850L is not set +# CONFIG_TQM860 is not set +# CONFIG_SPD823TS is not set +CONFIG_IVMS8=y +# CONFIG_SM850 is not set +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y +CONFIG_SASH=y +CONFIG_SASH_PATH="/bin/sash" + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_MPC8xx_IDE=y +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_FLASH is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +# CONFIG_SCC_ENET is not set +CONFIG_FEC_ENET=y +CONFIG_USE_MDIO=y +CONFIG_ENET_BIG_BUFFERS=y +# CONFIG_8xxSMC2 is not set +# CONFIG_8xxSCC is not set + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/SM850_defconfig linux/arch/ppc/configs/SM850_defconfig --- v2.4.2/linux/arch/ppc/configs/SM850_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/SM850_defconfig Sat Mar 3 10:52:13 2001 @@ -0,0 +1,420 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_RPXLITE is not set +# CONFIG_RPXCLASSIC is not set +# CONFIG_BSEIP is not set +# CONFIG_TQM823L is not set +# CONFIG_TQM850L is not set +# CONFIG_TQM855L is not set +# CONFIG_TQM860L is not set +# CONFIG_FPS850L is not set +# CONFIG_TQM860 is not set +# CONFIG_SPD823TS is not set +CONFIG_SM850=y +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +CONFIG_TQM8xxL=y +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y +CONFIG_SASH=y +CONFIG_SASH_PATH="/bin/sash" + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_FLASH=y +CONFIG_AMD_FLASH=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +CONFIG_SCC_ENET=y +# CONFIG_SCC1_ENET is not set +# CONFIG_SCC2_ENET is not set +CONFIG_SCC3_ENET=y +# CONFIG_FEC_ENET is not set +CONFIG_ENET_BIG_BUFFERS=y +CONFIG_8xxSMC2=y +CONFIG_8xx_ALTSMC2=y +CONFIG_8xx_CONS_SMC2=y +# CONFIG_8xxSCC is not set + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +CONFIG_8xx_CPU6=y + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/SPD823TS_defconfig linux/arch/ppc/configs/SPD823TS_defconfig --- v2.4.2/linux/arch/ppc/configs/SPD823TS_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/SPD823TS_defconfig Sat Mar 3 10:52:13 2001 @@ -0,0 +1,416 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_RPXLITE is not set +# CONFIG_RPXCLASSIC is not set +# CONFIG_BSEIP is not set +# CONFIG_TQM823L is not set +# CONFIG_TQM850L is not set +# CONFIG_TQM855L is not set +# CONFIG_TQM860L is not set +# CONFIG_FPS850L is not set +# CONFIG_TQM860 is not set +CONFIG_SPD823TS=y +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y +CONFIG_SASH=y +CONFIG_SASH_PATH="/bin/sash" + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_FLASH is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +CONFIG_SCC_ENET=y +# CONFIG_SCC1_ENET is not set +CONFIG_SCC2_ENET=y +# CONFIG_FEC_ENET is not set +CONFIG_ENET_BIG_BUFFERS=y +CONFIG_8xxSMC2=y +CONFIG_8xx_ALTSMC2=y +# CONFIG_8xx_CONS_SMC2 is not set +# CONFIG_8xxSCC is not set + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/TQM823L_defconfig linux/arch/ppc/configs/TQM823L_defconfig --- v2.4.2/linux/arch/ppc/configs/TQM823L_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/TQM823L_defconfig Sat Mar 3 10:52:13 2001 @@ -0,0 +1,419 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_RPXLITE is not set +# CONFIG_RPXCLASSIC is not set +# CONFIG_BSEIP is not set +CONFIG_TQM823L=y +# CONFIG_TQM850L is not set +# CONFIG_TQM855L is not set +# CONFIG_TQM860L is not set +# CONFIG_FPS850L is not set +# CONFIG_TQM860 is not set +# CONFIG_SPD823TS is not set +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +CONFIG_TQM8xxL=y +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y +CONFIG_SASH=y +CONFIG_SASH_PATH="/bin/sash" + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_FLASH=y +CONFIG_AMD_FLASH=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +CONFIG_SCC_ENET=y +# CONFIG_SCC1_ENET is not set +CONFIG_SCC2_ENET=y +# CONFIG_SCC3_ENET is not set +# CONFIG_FEC_ENET is not set +CONFIG_ENET_BIG_BUFFERS=y +CONFIG_8xxSMC2=y +CONFIG_8xx_ALTSMC2=y +# CONFIG_8xx_CONS_SMC2 is not set +# CONFIG_8xxSCC is not set + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/TQM850L_defconfig linux/arch/ppc/configs/TQM850L_defconfig --- v2.4.2/linux/arch/ppc/configs/TQM850L_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/TQM850L_defconfig Sat Mar 3 10:52:13 2001 @@ -0,0 +1,419 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_RPXLITE is not set +# CONFIG_RPXCLASSIC is not set +# CONFIG_BSEIP is not set +# CONFIG_TQM823L is not set +CONFIG_TQM850L=y +# CONFIG_TQM855L is not set +# CONFIG_TQM860L is not set +# CONFIG_FPS850L is not set +# CONFIG_TQM860 is not set +# CONFIG_SPD823TS is not set +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +CONFIG_TQM8xxL=y +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y +CONFIG_SASH=y +CONFIG_SASH_PATH="/bin/sash" + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_FLASH=y +CONFIG_AMD_FLASH=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +CONFIG_SCC_ENET=y +# CONFIG_SCC1_ENET is not set +CONFIG_SCC2_ENET=y +# CONFIG_SCC3_ENET is not set +# CONFIG_FEC_ENET is not set +CONFIG_ENET_BIG_BUFFERS=y +CONFIG_8xxSMC2=y +CONFIG_8xx_ALTSMC2=y +# CONFIG_8xx_CONS_SMC2 is not set +# CONFIG_8xxSCC is not set + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +CONFIG_8xx_CPU6=y + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/TQM860L_defconfig linux/arch/ppc/configs/TQM860L_defconfig --- v2.4.2/linux/arch/ppc/configs/TQM860L_defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/configs/TQM860L_defconfig Sat Mar 3 10:52:13 2001 @@ -0,0 +1,419 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +# CONFIG_6xx is not set +# CONFIG_4xx is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8260 is not set +CONFIG_8xx=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_RPXLITE is not set +# CONFIG_RPXCLASSIC is not set +# CONFIG_BSEIP is not set +# CONFIG_TQM823L is not set +# CONFIG_TQM850L is not set +# CONFIG_TQM855L is not set +CONFIG_TQM860L=y +# CONFIG_FPS850L is not set +# CONFIG_TQM860 is not set +# CONFIG_SPD823TS is not set +# CONFIG_MBX is not set +# CONFIG_WINCEPT is not set +CONFIG_TQM8xxL=y +# CONFIG_ALL_PPC is not set +# CONFIG_SMP is not set +CONFIG_MACH_SPECIFIC=y +CONFIG_MATH_EMULATION=y +CONFIG_SASH=y +CONFIG_SASH_PATH="/bin/sash" + +# +# General setup +# +# CONFIG_ISA is not set +# CONFIG_SBUS is not set +# CONFIG_PCI is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_NCR885E is not set +# CONFIG_OAKNET is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_FLASH=y +CONFIG_AMD_FLASH=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8xx CPM Options +# +CONFIG_SCC_ENET=y +CONFIG_SCC1_ENET=y +# CONFIG_SCC2_ENET is not set +# CONFIG_SCC3_ENET is not set +# CONFIG_FEC_ENET is not set +CONFIG_ENET_BIG_BUFFERS=y +CONFIG_8xxSMC2=y +# CONFIG_8xx_ALTSMC2 is not set +# CONFIG_8xx_CONS_SMC2 is not set +# CONFIG_8xxSCC is not set + +# +# Generic MPC8xx Options +# +CONFIG_8xx_COPYBACK=y +# CONFIG_8xx_CPU6 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_KGDB is not set +# CONFIG_XMON is not set diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.4.2/linux/arch/ppc/configs/common_defconfig Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/configs/common_defconfig Sun Mar 4 14:30:18 2001 @@ -295,11 +295,11 @@ # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -CONFIG_SCSI_AIC7XXX=y -# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set -CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -CONFIG_AIC7XXX_PROC_STATS=y -CONFIG_AIC7XXX_RESET_DELAY=15 +CONFIG_SCSI_AIC7XXX=m +CONFIG_SCSI_AIC7XXX_OLD=m +# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set +CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_OLD_PROC_STATS=y # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -u --recursive --new-file v2.4.2/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.4.2/linux/arch/ppc/defconfig Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/defconfig Sun Mar 4 14:30:18 2001 @@ -296,10 +296,9 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set CONFIG_SCSI_AIC7XXX=y -# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set -CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -CONFIG_AIC7XXX_PROC_STATS=y -CONFIG_AIC7XXX_RESET_DELAY=15 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +CONFIG_AIC7XXX_RESET_DELAY=15000 +# CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.4.2/linux/arch/ppc/kernel/Makefile Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/Makefile Sat Mar 3 10:52:13 2001 @@ -70,6 +70,7 @@ include $(TOPDIR)/Rules.make +entry.o: entry.S ppc_defs.h head.o: head.S ppc_defs.h head_4xx.o: head_4xx.S ppc_defs.h head_8xx.o: head_8xx.S ppc_defs.h diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.4.2/linux/arch/ppc/kernel/chrp_pci.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/chrp_pci.c Sat Mar 3 10:52:13 2001 @@ -298,8 +298,9 @@ bus->resource[1] = &gg2_resources.pci_mem; } -static void process_bridge_ranges(struct pci_controller *hose, - struct device_node *dev, int index) +/* this is used by the pmac_pci code too... - paulus */ +void process_bridge_ranges(struct pci_controller *hose, + struct device_node *dev, int primary) { unsigned int *ranges; int rlen = 0; @@ -316,31 +317,34 @@ break; hose->io_base_phys = ranges[3]; hose->io_base_virt = ioremap(ranges[3], ranges[5]); - if (index == 0) { + if (primary) isa_io_base = (unsigned long) hose->io_base_virt; - printk("isa_io_base=%lx\n", isa_io_base); - } res = &hose->io_resource; res->flags = IORESOURCE_IO; + res->start = ranges[2]; break; case 2: /* memory space */ - if (index == 0 && ranges[1] == 0 && ranges[2] == 0){ - isa_mem_base = ranges[3]; - printk("isa_mem_base=%lx\n", isa_mem_base); + memno = 0; + if (ranges[1] == 0 && ranges[2] == 0 + && ranges[5] <= (16 << 20)) { + /* 1st 16MB, i.e. ISA memory area */ + if (primary) + isa_mem_base = ranges[3]; + memno = 1; } - if (memno == 0) { + while (memno < 3 && hose->mem_resources[memno].flags) + ++memno; + if (memno == 0) hose->pci_mem_offset = ranges[3] - ranges[2]; - printk("pci_mem_offset=%lx for this bridge\n", - hose->pci_mem_offset); + if (memno < 3) { + res = &hose->mem_resources[memno]; + res->flags = IORESOURCE_MEM; + res->start = ranges[3]; } - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - ++memno; break; } if (res != NULL) { res->name = dev->full_name; - res->start = ranges[3]; res->end = res->start + ranges[5] - 1; res->parent = NULL; res->sibling = NULL; @@ -401,7 +405,7 @@ hose->cfg_addr = (volatile unsigned int *) cfg; hose->cfg_data = cfg + 0x10; - process_bridge_ranges(hose, dev, index); + process_bridge_ranges(hose, dev, index == 0); #ifdef CONFIG_POWER3 openpic_setup_ISU(index, opprop[index+1]); diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.4.2/linux/arch/ppc/kernel/chrp_setup.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/chrp_setup.c Tue Mar 6 19:28:35 2001 @@ -84,7 +84,7 @@ extern void mackbd_init_hw(void); extern unsigned char mackbd_sysrq_xlate[128]; -kdev_t boot_dev; +extern kdev_t boot_dev; extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; @@ -237,7 +237,6 @@ void __init chrp_setup_arch(void) { - extern char cmd_line[]; struct device_node *device; /* init to some ~sane value until calibrate_delay() runs */ @@ -252,7 +251,6 @@ else #endif ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ - printk("Boot arguments: %s\n", cmd_line); /* Lookup PCI host bridges */ chrp_find_bridges(); diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.4.2/linux/arch/ppc/kernel/head.S Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/head.S Sat Mar 3 10:52:13 2001 @@ -1135,7 +1135,7 @@ #ifdef CONFIG_APUS /* * On APUS the physical base address of the kernel is not known at compile - * time, which means the __pa/__va constants used are incorect. In the + * time, which means the __pa/__va constants used are incorrect. In the * __init section is recorded the virtual addresses of instructions using * these constants, so all that has to be done is fix these before * continuing the kernel boot. diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S --- v2.4.2/linux/arch/ppc/kernel/head_8xx.S Sun Sep 17 09:48:06 2000 +++ linux/arch/ppc/kernel/head_8xx.S Sat Mar 3 10:52:14 2001 @@ -968,26 +968,6 @@ SYNC blr -/* Jump into the system reset for the rom. - * We first disable the MMU, and then jump to the ROM reset address. - * - * r3 is the board info structure, r4 is the location for starting. - * I use this for building a small kernel that can load other kernels, - * rather than trying to write or rely on a rom monitor that can tftp load. - */ - .globl m8xx_gorom -m8xx_gorom: - li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) - lis r6,2f@h - addis r6,r6,-KERNELBASE@h - ori r6,r6,2f@l - mtspr SRR0,r6 - mtspr SRR1,r5 - rfi -2: - mtlr r4 - blr - #ifdef CONFIG_8xx_CPU6 /* It's here because it is unique to the 8xx. * It is important we get called with interrupts disabled. I used to diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.4.2/linux/arch/ppc/kernel/irq.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/irq.c Sat Mar 3 10:52:14 2001 @@ -7,8 +7,8 @@ * Copyright (C) 1992 Linus Torvalds * Adapted from arch/i386 by Gary Thomas * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * Updated and modified by Cort Dougan (cort@cs.nmt.edu) - * Copyright (C) 1996 Cort Dougan + * Updated and modified by Cort Dougan + * Copyright (C) 1996-2001 Cort Dougan * Adapted for Power Macintosh by Paul Mackerras * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). @@ -258,7 +258,10 @@ retval = setup_irq(irq, action); if (retval) + { kfree(action); + return retval; + } return 0; } @@ -464,13 +467,11 @@ ppc_spurious_interrupts++; printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq); /* We can't call disable_irq here, it would deadlock */ - if (!desc->depth) - desc->depth = 1; + ++desc->depth; desc->status |= IRQ_DISABLED; - /* This is not a real spurrious interrupt, we - * have to eoi it, so we jump to out - */ mask_irq(irq); + /* This is a real interrupt, we have to eoi it, + so we jump to out */ goto out; } status &= ~IRQ_PENDING; /* we commit to handling */ diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c --- v2.4.2/linux/arch/ppc/kernel/m8260_setup.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/m8260_setup.c Sat Mar 3 10:52:14 2001 @@ -85,10 +85,6 @@ void __init m8260_setup_arch(void) { - extern char cmd_line[]; - - printk("Boot arguments: %s\n", cmd_line); - /* Reset the Communication Processor Module. */ m8260_cpm_reset(); diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c --- v2.4.2/linux/arch/ppc/kernel/m8xx_setup.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/m8xx_setup.c Sat Mar 3 10:52:14 2001 @@ -32,6 +32,7 @@ #include #include #include +#include /* Before ide.h to avoid warning: `MAX_HWIFS' redefined */ #include #include @@ -41,7 +42,6 @@ #include #include #include -#include #include #include @@ -52,19 +52,65 @@ unsigned long m8xx_get_rtc_time(void); void m8xx_calibrate_decr(void); -#if 0 -extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int mackbd_getkeycode(unsigned int scancode); -extern int mackbd_pretranslate(unsigned char scancode, char raw_mode); -extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char mackbd_unexpected_up(unsigned char keycode); -extern void mackbd_leds(unsigned char leds); -extern void mackbd_init_hw(void); -#endif - unsigned char __res[sizeof(bd_t)]; unsigned long empty_zero_page[1024]; +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE +#include "../../../drivers/ide/ide_modes.h" + +static void m8xx_ide_tuneproc(ide_drive_t *drive, byte pio); + +typedef struct ide_ioport_desc { + unsigned long base_off; /* Offset to PCMCIA memory */ + ide_ioreg_t reg_off[IDE_NR_PORTS]; /* controller reg. offsets */ + int irq; /* IRQ */ +} ide_ioport_desc_t; + +ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = { +#ifdef IDE0_BASE_OFFSET + { IDE0_BASE_OFFSET, + { + IDE0_DATA_REG_OFFSET, + IDE0_ERROR_REG_OFFSET, + IDE0_NSECTOR_REG_OFFSET, + IDE0_SECTOR_REG_OFFSET, + IDE0_LCYL_REG_OFFSET, + IDE0_HCYL_REG_OFFSET, + IDE0_SELECT_REG_OFFSET, + IDE0_STATUS_REG_OFFSET, + IDE0_CONTROL_REG_OFFSET, + IDE0_IRQ_REG_OFFSET, + }, + IDE0_INTERRUPT, + }, +# ifdef IDE1_BASE_OFFSET + { IDE1_BASE_OFFSET, + { + IDE1_DATA_REG_OFFSET, + IDE1_ERROR_REG_OFFSET, + IDE1_NSECTOR_REG_OFFSET, + IDE1_SECTOR_REG_OFFSET, + IDE1_LCYL_REG_OFFSET, + IDE1_HCYL_REG_OFFSET, + IDE1_SELECT_REG_OFFSET, + IDE1_STATUS_REG_OFFSET, + IDE1_CONTROL_REG_OFFSET, + IDE1_IRQ_REG_OFFSET, + }, + IDE1_INTERRUPT, + }, +# endif /* IDE1_BASE_OFFSET */ +#endif /* IDE0_BASE_OFFSET */ +}; + +ide_pio_timings_t ide_pio_clocks[6]; + +/* Make clock cycles and always round up */ +#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U ) + +#endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ +#endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ @@ -77,6 +123,8 @@ extern unsigned long find_available_memory(void); extern void m8xx_cpm_reset(uint); +static void ide_interrupt_handler(void* dev_id); + void __init adbdev_init(void) { } @@ -85,12 +133,9 @@ m8xx_setup_arch(void) { int cpm_page; - extern char cmd_line[]; cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE); - printk("Boot arguments: %s\n", cmd_line); - /* Reset the Communication Processor Module. */ m8xx_cpm_reset(cpm_page); @@ -137,7 +182,7 @@ */ void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) { - printk("timebase_interrupt()\n"); + printk ("timebase_interrupt()\n"); } /* The decrementer counts at the system (internal) clock frequency divided by @@ -164,7 +209,7 @@ fp = (binfo->bi_intfreq * 1000000) / 16; freq = fp*60; /* try to make freq/1e6 an integer */ divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); + printk("Decrementer Frequency = %d/%d\n", freq, divisor); tb_ticks_per_jiffy = freq / HZ / divisor; tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); @@ -232,9 +277,21 @@ void m8xx_restart(char *cmd) { - extern void m8xx_gorom(void); + __volatile__ unsigned char dummy; + uint msr; - m8xx_gorom(); + cli(); + ((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080; + + /* Clear the ME bit in MSR to cause checkstop on machine check + */ + __asm__("mfmsr %0" : "=r" (msr) ); + msr &= ~0x1000; + __asm__("mtmsr %0" : : "r" (msr) ); + + dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0]; + printk("Restart failed\n"); + while(1); } void @@ -257,8 +314,8 @@ bp = (bd_t *)__res; - len += sprintf(len+buffer,"clock\t\t: %dMHz\n" - "bus clock\t: %dMHz\n", + len += sprintf(len+buffer,"clock\t\t: %ldMHz\n" + "bus clock\t: %ldMHz\n", bp->bi_intfreq /*/ 1000000*/, bp->bi_busfreq /*/ 1000000*/); @@ -298,17 +355,13 @@ #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -/* Define this to make a PCMCIA ATA Flash card work. -*/ -#define ATA_FLASH 1 - /* * IDE stuff. */ void m8xx_ide_insw(ide_ioreg_t port, void *buf, int ns) { -#ifdef ATA_FLASH +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE ide_insw(port, buf, ns); #else ide_insw(port+_IO_BASE, buf, ns); @@ -318,7 +371,7 @@ void m8xx_ide_outsw(ide_ioreg_t port, void *buf, int ns) { -#ifdef ATA_FLASH +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE ide_outsw(port, buf, ns); #else ide_outsw(port+_IO_BASE, buf, ns); @@ -328,8 +381,11 @@ int m8xx_ide_default_irq(ide_ioreg_t base) { -#ifdef ATA_FLASH - return PCMCIA_INTERRUPT; +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE + if (base >= MAX_HWIFS) + return 0; + + return (ioport_dsc[base].irq); #else return 14; #endif @@ -348,60 +404,105 @@ const char *device, void *dev_id) { -#ifdef ATA_FLASH +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE return request_8xxirq(irq, handler, flags, device, dev_id); #else return request_irq(irq, handler, flags, device, dev_id); #endif } -/* We can use an external IDE controller or wire the IDE interface to - * the internal PCMCIA controller. +/* We can use an external IDE controller + * or wire the IDE interface to the internal PCMCIA controller. + * + * See include/linux/ide.h for definition of hw_regs_t (p, base) */ -void __init m8xx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq) +void m8xx_ide_init_hwif_ports(hw_regs_t *hw, + ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { - ide_ioreg_t port = base; + ide_ioreg_t *p = hw->io_ports; int i; -#ifdef ATA_FLASH +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE volatile pcmconf8xx_t *pcmp; + + static unsigned long pcmcia_base = 0; +#else + ide_ioreg_t port = data_port; /* ??? XXX ??? XXX */ #endif + unsigned long base; -#ifdef ATA_FLASH +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE *p = 0; - *irq = 0; + if (irq) + *irq = 0; + + pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia)); - if (base != 0) /* Only map the first ATA flash drive */ + if (!pcmcia_base) { + /* relies PCMCIA registers being set up by firmware */ + pcmcia_base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, + PCMCIA_MEM_SIZE); + + /* Compute clock cycles for PIO timings */ + for (i=0; i<6; ++i) { + bd_t *binfo = (bd_t *)__res; + + ide_pio_clocks[i].hold_time = + PCMCIA_MK_CLKS (ide_pio_timings[i].hold_time, + binfo->bi_busfreq); + ide_pio_clocks[i].setup_time = + PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time, + binfo->bi_busfreq); + ide_pio_clocks[i].active_time = + PCMCIA_MK_CLKS (ide_pio_timings[i].active_time, + binfo->bi_busfreq); + ide_pio_clocks[i].cycle_time = + PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time, + binfo->bi_busfreq); +#if 0 + printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n", + i, + ide_pio_clocks[i].setup_time, + ide_pio_clocks[i].active_time, + ide_pio_clocks[i].hold_time, + ide_pio_clocks[i].cycle_time, + ide_pio_timings[i].setup_time, + ide_pio_timings[i].active_time, + ide_pio_timings[i].hold_time, + ide_pio_timings[i].cycle_time); +#endif + } + } + + if (data_port >= MAX_HWIFS) return; - pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia)); + base = pcmcia_base + ioport_dsc[data_port].base_off; + +# if (!defined(CONFIG_SPD823TS) && !defined(CONFIG_IVMS8)) + /* SPD823TS and IVMS8 have a direct connection */ if (pcmp->pcmc_pipr & 0x18000000) return; /* No card in slot */ +# endif /* CONFIG_SPD823TS, CONFIG_IVMS8 */ - base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200); + for (i = 0; i < IDE_NR_PORTS; ++i) { + *p++ = base + ioport_dsc[data_port].reg_off[i]; + } - /* For the M-Systems ATA card, the first 8 registers map 1:1. - * The following register, control/Altstatus, is located at 0x0e. - * Following that, the irq offset, is not used, so we place it in - * an unused location, 0x0a. - */ - *p++ = base + 8; - for (i = 1; i < 8; ++i) - *p++ = base + i; - *p++ = base + 0x0e; /* control/altstatus */ - *p = base + 0x0a; /* IRQ, not used */ - if (irq) - *irq = PCMCIA_INTERRUPT; + if (irq) { + *irq = ioport_dsc[data_port].irq; + } - /* Configure the interface for this interrupt. - */ - pcmp->pcmc_pgcra = (mk_int_int_mask(PCMCIA_INTERRUPT) << 24) | - (mk_int_int_mask(PCMCIA_INTERRUPT) << 16); + /* register routine to tune PIO mode */ + ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; - /* Enable status change interrupt from slot A. - */ - pcmp->pcmc_per = 0xff100000; - pcmp->pcmc_pscr = ~0; -#else + /* Enable Harddisk Interrupt, + * and make it edge sensitive + */ + hw->ack_intr = (ide_ack_intr_t *)ide_interrupt_handler; + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |= + (0x80000000 >> ioport_dsc[data_port].irq); + +#else /* ! CONFIG_BLK_DEV_MPC8xx_IDE */ /* Just a regular IDE drive on some I/O port. */ @@ -411,10 +512,84 @@ *p++ = base + 0x206; if (irq != NULL) *irq = 0; -#endif +#endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ } +#endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ + + +/* -------------------------------------------------------------------- */ + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +#ifdef CONFIG_BLK_DEV_MPC8xx_IDE + +/* PCMCIA Timing */ +#ifndef PCMCIA_SHT +#define PCMCIA_SHT(t) ((t & 0x0F)<<16) /* Strobe Hold Time */ +#define PCMCIA_SST(t) ((t & 0x0F)<<12) /* Strobe Setup Time */ +#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */ #endif + +/* Calculate PIO timings */ +static void +m8xx_ide_tuneproc(ide_drive_t *drive, byte pio) +{ + volatile pcmconf8xx_t *pcmp; + ide_pio_data_t d; + ulong timing, mask, reg; + + pio = ide_get_best_pio_mode(drive, pio, 4, &d); + +#if 1 + printk("%s[%d] %s: best PIO mode: %d\n", + __FILE__,__LINE__,__FUNCTION__, pio); +#endif + pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia)); + + mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF)); + + timing = PCMCIA_SHT(ide_pio_clocks[pio].hold_time ) + | PCMCIA_SST(ide_pio_clocks[pio].setup_time ) + | PCMCIA_SL (ide_pio_clocks[pio].active_time) + ; + +#if 1 + printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing); +#endif + if ((reg = pcmp->pcmc_por0 & mask) != 0) + pcmp->pcmc_por0 = reg | timing; + + if ((reg = pcmp->pcmc_por1 & mask) != 0) + pcmp->pcmc_por1 = reg | timing; + + if ((reg = pcmp->pcmc_por2 & mask) != 0) + pcmp->pcmc_por2 = reg | timing; + + if ((reg = pcmp->pcmc_por3 & mask) != 0) + pcmp->pcmc_por3 = reg | timing; + + if ((reg = pcmp->pcmc_por4 & mask) != 0) + pcmp->pcmc_por4 = reg | timing; + + if ((reg = pcmp->pcmc_por5 & mask) != 0) + pcmp->pcmc_por5 = reg | timing; + + if ((reg = pcmp->pcmc_por6 & mask) != 0) + pcmp->pcmc_por6 = reg | timing; + + if ((reg = pcmp->pcmc_por7 & mask) != 0) + pcmp->pcmc_por7 = reg | timing; +} + +void ide_interrupt_handler (void *dev) +{ +} + +#endif /* CONFIG_BLK_DEV_MPC8xx_IDE */ +#endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ + +/* -------------------------------------------------------------------- */ + void __init m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) @@ -490,7 +665,6 @@ ppc_ide_md.default_io_base = m8xx_ide_default_io_base; ppc_ide_md.fix_driveid = ppc_generic_ide_fix_driveid; ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports; - ppc_ide_md.ide_request_irq = m8xx_ide_request_irq; ppc_ide_md.io_base = _IO_BASE; #endif diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.4.2/linux/arch/ppc/kernel/open_pic.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/open_pic.c Sat Mar 3 10:52:14 2001 @@ -42,6 +42,45 @@ OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU]; +/* Global Operations */ +static void openpic_disable_8259_pass_through(void); +static u_int openpic_irq(void); +static void openpic_eoi(void); +static void openpic_set_priority(u_int pri); +static void openpic_set_spurious(u_int vector); + +#ifdef CONFIG_SMP +/* Interprocessor Interrupts */ +static void openpic_initipi(u_int ipi, u_int pri, u_int vector); +static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); +#endif + +/* Timer Interrupts */ +static void openpic_inittimer(u_int timer, u_int pri, u_int vector); +static void openpic_maptimer(u_int timer, u_int cpumask); + +/* Interrupt Sources */ +static void openpic_enable_irq(u_int irq); +static void openpic_disable_irq(u_int irq); +static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity, + int is_level); +static void openpic_mapirq(u_int irq, u_int cpumask); + +/* + * These functions are not used but the code is kept here + * for completeness and future reference. + */ +#ifdef notused +static void openpic_reset(void); +static void openpic_enable_8259_pass_through(void); +static u_int openpic_get_priority(void); +static u_int openpic_get_spurious(void); +static void openpic_set_sense(u_int irq, int sense); +#endif /* notused */ + +/* + * Description of the openpic for the higher-level irq code + */ static void openpic_end_irq(unsigned int irq_nr); static void openpic_ack_irq(unsigned int irq_nr); static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask); @@ -370,17 +409,19 @@ #endif } -static inline void openpic_reset(void) +#ifdef notused +static void openpic_reset(void) { openpic_setfield(&OpenPIC->Global.Global_Configuration0, OPENPIC_CONFIG_RESET); } -static inline void openpic_enable_8259_pass_through(void) +static void openpic_enable_8259_pass_through(void) { openpic_clearfield(&OpenPIC->Global.Global_Configuration0, OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE); } +#endif /* notused */ static void openpic_disable_8259_pass_through(void) { @@ -412,8 +453,8 @@ (void)openpic_read(&OpenPIC->THIS_CPU.EOI); } - -static inline u_int openpic_get_priority(void) +#ifdef notused +static u_int openpic_get_priority(void) { DECL_THIS_CPU; @@ -421,6 +462,7 @@ return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority, OPENPIC_CURRENT_TASK_PRIORITY_MASK); } +#endif /* notused */ static void openpic_set_priority(u_int pri) { @@ -435,11 +477,13 @@ /* * Get/set the spurious vector */ -static inline u_int openpic_get_spurious(void) +#ifdef notused +static u_int openpic_get_spurious(void) { return openpic_readfield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK); } +#endif /* notused */ static void openpic_set_spurious(u_int vec) { @@ -604,21 +648,6 @@ static void openpic_enable_irq(u_int irq) { check_arg_irq(irq); - - /* - * Never want to disable a timer or ipi irq - * (only want to disable irqs within an ISU). - */ - if (((irq >= OPENPIC_VEC_IPI+open_pic_irq_offset) && - (irq < OPENPIC_VEC_IPI+open_pic_irq_offset+OPENPIC_NUM_IPI)) || - ((irq >= OPENPIC_VEC_TIMER+open_pic_irq_offset) && - (irq < OPENPIC_VEC_TIMER+open_pic_irq_offset+OPENPIC_NUM_TIMERS))) - { - /* silently ignore the enable of the timer or ipi irq. */ - return; - } - - openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { @@ -632,19 +661,6 @@ u32 vp; check_arg_irq(irq); - /* - * Never want to disable a timer or ipi irq - * (only want to disable irqs within an ISU). - */ - if (((irq >= OPENPIC_VEC_IPI+open_pic_irq_offset) && - (irq < OPENPIC_VEC_IPI+open_pic_irq_offset+OPENPIC_NUM_IPI)) || - ((irq >= OPENPIC_VEC_TIMER+open_pic_irq_offset) && - (irq < OPENPIC_VEC_TIMER+open_pic_irq_offset+OPENPIC_NUM_TIMERS))) - { - panic("openpic_disable_irq - disabling non-ISU irq"); - } - - openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { @@ -667,11 +683,13 @@ openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK); } + void openpic_disable_ipi(u_int irq) { - /* NEVER disable an IPI... that's just plain wrong! */ + irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset); + check_arg_ipi(irq); + openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK); } - #endif /* @@ -702,39 +720,33 @@ openpic_write(&GET_ISU(irq).Destination, physmask); } +#ifdef notused /* * Set the sense for an interrupt source (and disable it!) * * sense: 1 for level, 0 for edge */ -static inline void openpic_set_sense(u_int irq, int sense) +static void openpic_set_sense(u_int irq, int sense) { openpic_safe_writefield(&GET_ISU(irq).Vector_Priority, OPENPIC_SENSE_LEVEL, (sense ? OPENPIC_SENSE_LEVEL : 0)); } +#endif /* notused */ /* No spinlocks, should not be necessary with the OpenPIC * (1 register = 1 interrupt and we have the desc lock). */ static void openpic_ack_irq(unsigned int irq_nr) { -#if 1 /* masking should be unnecessary, but I still get spurrious */ openpic_disable_irq(irq_nr); -#endif - if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) - openpic_eoi(); + openpic_eoi(); } static void openpic_end_irq(unsigned int irq_nr) { - if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0) - openpic_eoi(); - -#if 1 /* masking should be unnecessary, but I still get spurrious */ if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) openpic_enable_irq(irq_nr); -#endif } static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask) @@ -745,23 +757,11 @@ #ifdef CONFIG_SMP static void openpic_ack_ipi(unsigned int irq_nr) { + openpic_eoi(); } static void openpic_end_ipi(unsigned int irq_nr) { - /* IPIs are marked IRQ_PER_CPU. This has the side effect of - * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from - * applying to them. We EOI them late to avoid re-entering. - * however, I'm wondering if we could simply let them have the - * SA_INTERRUPT flag and let them execute with all interrupts OFF. - * This would have the side effect of either running cross-CPU - * functions with interrupts off, or we can re-enable them explicitely - * with a __sti() in smp_call_function_interrupt(), since - * smp_call_function() is protected by a spinlock. - * Or maybe we shouldn't set the IRQ_PER_CPU flag on cross-CPU - * function calls IPI at all but that would make a special case. - */ - openpic_eoi(); } static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) @@ -791,8 +791,11 @@ irq = i8259_irq( smp_processor_id() ); openpic_eoi(); } - if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) + if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) { irq = -1; + /* That's not SMP safe ... but who cares ? */ + ppc_spurious_interrupts++; + } return irq; } diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/open_pic_defs.h linux/arch/ppc/kernel/open_pic_defs.h --- v2.4.2/linux/arch/ppc/kernel/open_pic_defs.h Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/open_pic_defs.h Sat Mar 3 10:52:14 2001 @@ -28,8 +28,6 @@ #ifdef __KERNEL__ -#include - /* * OpenPIC supports up to 2048 interrupt sources and up to 32 processors */ @@ -288,40 +286,6 @@ /* Interrupt Source Registers */ #define Vector_Priority _Vector_Priority.Reg #define Destination _Destination.Reg - - /* - * Local (static) OpenPIC Operations - */ - - -/* Global Operations */ -static void openpic_reset(void); -static void openpic_enable_8259_pass_through(void); -static void openpic_disable_8259_pass_through(void); -static u_int openpic_irq(void); -static void openpic_eoi(void); -static u_int openpic_get_priority(void); -static void openpic_set_priority(u_int pri); -static u_int openpic_get_spurious(void); -static void openpic_set_spurious(u_int vector); - -#ifdef CONFIG_SMP -/* Interprocessor Interrupts */ -static void openpic_initipi(u_int ipi, u_int pri, u_int vector); -static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); -#endif - -/* Timer Interrupts */ -static void openpic_inittimer(u_int timer, u_int pri, u_int vector); -static void openpic_maptimer(u_int timer, u_int cpumask); - -/* Interrupt Sources */ -static void openpic_enable_irq(u_int irq); -static void openpic_disable_irq(u_int irq); -static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity, - int is_level); -static void openpic_mapirq(u_int irq, u_int cpumask); -static void openpic_set_sense(u_int irq, int sense); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.4.2/linux/arch/ppc/kernel/pci.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/pci.c Sat Mar 3 10:52:14 2001 @@ -109,7 +109,7 @@ struct resource *res = dev->resource + i; if (!res->start) continue; - if (res->flags & IORESOURCE_MEM) { + if ((res->flags & IORESOURCE_MEM) && hose->pci_mem_offset) { res->start += hose->pci_mem_offset; res->end += hose->pci_mem_offset; #ifdef DEBUG @@ -121,7 +121,9 @@ if ((res->flags & IORESOURCE_IO) && (unsigned long) hose->io_base_virt != isa_io_base) { - unsigned long offs = (unsigned long) hose->io_base_virt - isa_io_base; + unsigned long offs; + + offs = (unsigned long)hose->io_base_virt - isa_io_base; res->start += offs; res->end += offs; printk("Fixup IO res, dev: %x.%x, res_start: %lx->%lx\n", @@ -245,13 +247,30 @@ } } +static inline void alloc_resource(struct pci_dev *dev, int idx) +{ + struct resource *pr, *r = &dev->resource[idx]; + + DBG("PCI:%x:%x:%x: Resource %08lx-%08lx (f=%lx)\n", + dev->bus->number, dev->devfn >> 3, dev->devfn & 7, + r->start, r->end, r->flags); + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + printk(KERN_ERR "PCI: Cannot allocate resource region %d" + " of device %s\n", idx, dev->slot_name); + /* We'll assign a new address later */ + r->end -= r->start; + r->start = 0; + } +} + static void __init pcibios_allocate_resources(int pass) { struct pci_dev *dev; int idx, disabled; u16 command; - struct resource *r, *pr; + struct resource *r; pci_for_each_dev(dev) { pci_read_config_word(dev, PCI_COMMAND, &command); @@ -259,7 +278,7 @@ r = &dev->resource[idx]; if (r->parent) /* Already allocated */ continue; - if (!r->start) /* Address not assigned at all */ + if (!r->start) /* Not assigned at all */ continue; if (r->end == 0xffffffff) { /* LongTrail OF quirk: unassigned */ @@ -273,28 +292,19 @@ disabled = !(command & PCI_COMMAND_IO); else disabled = !(command & PCI_COMMAND_MEMORY); - if (pass == disabled) { - DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", - r->start, r->end, r->flags, disabled, pass); - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { - printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name); - /* We'll assign a new address later */ - r->end -= r->start; - r->start = 0; - } - } + if (pass == disabled) + alloc_resource(dev, idx); } - if (!pass) { - r = &dev->resource[PCI_ROM_RESOURCE]; - if (r->flags & PCI_ROM_ADDRESS_ENABLE) { - /* Turn the ROM off, leave the resource region, but keep it unregistered. */ - u32 reg; - DBG("PCI: Switching off ROM of %s\n", dev->slot_name); - r->flags &= ~PCI_ROM_ADDRESS_ENABLE; - pci_read_config_dword(dev, dev->rom_base_reg, ®); - pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); - } + if (pass) + continue; + r = &dev->resource[PCI_ROM_RESOURCE]; + if (r->flags & PCI_ROM_ADDRESS_ENABLE) { + /* Turn the ROM off, leave the resource region, but keep it unregistered. */ + u32 reg; + DBG("PCI: Switching off ROM of %s\n", dev->slot_name); + r->flags &= ~PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, dev->rom_base_reg, ®); + pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); } } } @@ -315,17 +325,18 @@ for(idx=0; idx<6; idx++) { r = &dev->resource[idx]; - +#if 0 /* we don't need this PC-ism */ /* * Don't touch IDE controllers and I/O ports of video cards! */ if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) continue; +#endif /* * We shall assign a new address to this resource, either because - * the BIOS forgot to do so or because we have decided the old + * the BIOS (sic) forgot to do so or because we have decided the old * address was unusable for some reason. */ if (!r->start && r->end && @@ -572,7 +583,7 @@ { struct pci_controller *hose; struct pci_bus *bus; - int next_busno; + int next_busno, i; printk("PCI: Probing PCI hardware\n"); @@ -582,6 +593,17 @@ hose->first_busno = next_busno; hose->last_busno = 0xff; bus = pci_scan_bus(hose->first_busno, hose->ops, hose); + if (hose->io_resource.flags) { + unsigned long offs; + + offs = (unsigned long)hose->io_base_virt - isa_io_base; + hose->io_resource.start += offs; + hose->io_resource.end += offs; + bus->resource[0] = &hose->io_resource; + } + for (i = 0; i < 3; ++i) + if (hose->mem_resources[i].flags) + bus->resource[i+1] = &hose->mem_resources[i]; hose->bus = bus; hose->last_busno = bus->subordinate; if (pci_assign_all_busses || next_busno <= hose->last_busno) @@ -654,8 +676,20 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) { + struct pci_controller *hose; + pci_read_bridge_bases(bus); - + + hose = pci_bus_to_hose(bus->number); + + /* Apply pci_mem_offset to bridge mem resource */ + if (hose->first_busno != bus->number) + if (bus->resource[1]->start && (bus->resource[1]->end != -1)) + { + bus->resource[1]->start += hose->pci_mem_offset; + bus->resource[1]->end += hose->pci_mem_offset; + } + if ( ppc_md.pcibios_fixup_bus ) ppc_md.pcibios_fixup_bus(bus); } @@ -773,6 +807,32 @@ /* Obsolete functions. Should be removed once the symbios driver * is fixed */ +unsigned long +phys_to_bus(unsigned long pa) +{ + struct pci_controller *hose; + int i; + + for (hose = hose_head; hose; hose = hose->next) { + for (i = 0; i < 3; ++i) { + if (pa >= hose->mem_resources[i].start + && pa <= hose->mem_resources[i].end) { + /* + * XXX the hose->pci_mem_offset really + * only applies to mem_resources[0]. + * We need a way to store an offset for + * the others. -- paulus + */ + if (i == 0) + pa -= hose->pci_mem_offset; + return pa; + } + } + } + /* hmmm, didn't find it */ + return 0; +} + unsigned long pci_phys_to_bus(unsigned long pa, int busnr) { diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.4.2/linux/arch/ppc/kernel/pmac_pci.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/pmac_pci.c Sat Mar 3 10:52:14 2001 @@ -29,6 +29,8 @@ #undef DEBUG +extern void process_bridge_ranges(struct pci_controller *hose, + struct device_node *dev, int primary); static void add_bridges(struct device_node *dev); /* XXX Could be per-controller, but I don't think we risk anything by @@ -372,7 +374,7 @@ (void)in_le32((volatile unsigned int *)bp->cfg_data); } -static void __init +static int __init setup_uninorth(struct pci_controller* hose, struct reg_property* addr) { pci_assign_all_busses = 1; @@ -380,6 +382,7 @@ hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); +#if 0 /* done in process_bridge_ranges now - paulus */ hose->io_base_phys = addr->address; /* is 0x10000 enough for io space ? */ hose->io_base_virt = (void *)ioremap(addr->address, 0x10000); @@ -389,6 +392,9 @@ */ if (addr->address == 0xf2000000) isa_io_base = (unsigned long)hose->io_base_virt; +#endif + /* We "know" that the bridge at f2000000 has the PCI slots. */ + return addr->address == 0xf2000000; } static void __init @@ -399,8 +405,10 @@ ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); +#if 0 /* done in process_bridge_ranges now - paulus */ hose->io_base_phys = addr->address; hose->io_base_virt = (void *) ioremap(addr->address, 0x10000); +#endif init_bandit(hose); } @@ -413,19 +421,23 @@ ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); +#if 0 /* done in process_bridge_ranges now - paulus */ hose->io_base_phys = addr->address; hose->io_base_virt = (void *) ioremap(addr->address, 0x10000); +#endif } void __init setup_grackle(struct pci_controller *hose, unsigned io_space_size) { setup_indirect_pci(hose, 0xfec00000, 0xfee00000); +#if 0 /* done in process_bridge_ranges now - paulus */ hose->io_base_phys = 0xfe000000; hose->io_base_virt = (void *) ioremap(0xfe000000, io_space_size); pci_dram_offset = 0; isa_mem_base = 0xfd000000; isa_io_base = (unsigned long) hose->io_base_virt; +#endif if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(hose, 1); #if 0 /* Disabled for now, HW problems ??? */ @@ -445,6 +457,7 @@ struct reg_property *addr; char* disp_name; int *bus_range; + int first = 1, primary; for (; dev != NULL; dev = dev->next) { addr = (struct reg_property *) get_property(dev, "reg", &len); @@ -467,8 +480,9 @@ hose->last_busno = bus_range ? bus_range[1] : 0xff; disp_name = NULL; + primary = first; if (device_is_compatible(dev, "uni-north")) { - setup_uninorth(hose, addr); + primary = setup_uninorth(hose, addr); disp_name = "UniNorth"; } else if (strcmp(dev->name, "pci") == 0) { /* XXX assume this is a mpc106 (grackle) */ @@ -480,6 +494,7 @@ } else if (strcmp(dev->name, "chaos") == 0) { setup_chaos(hose, addr); disp_name = "Chaos"; + primary = 0; } printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n", disp_name, addr->address, hose->first_busno, hose->last_busno); @@ -488,12 +503,14 @@ hose, hose->cfg_addr, hose->cfg_data); #endif - /* Setup a default isa_io_base */ - if (isa_io_base == 0) - isa_io_base = (unsigned long)hose->io_base_virt; + /* Interpret the "ranges" property */ + /* This also maps the I/O region and sets isa_io/mem_base */ + process_bridge_ranges(hose, dev, primary); /* Fixup "bus-range" OF property */ fixup_bus_range(dev); + + first &= !primary; } } diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.4.2/linux/arch/ppc/kernel/pmac_setup.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/pmac_setup.c Tue Mar 6 19:28:35 2001 @@ -81,7 +81,7 @@ extern int mackbd_getkeycode(unsigned int scancode); extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode); -extern int mackbd_unexpected_up(unsigned char keycode); +extern char mackbd_unexpected_up(unsigned char keycode); extern void mackbd_leds(unsigned char leds); extern void __init mackbd_init_hw(void); extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, @@ -253,6 +253,7 @@ #endif +#ifdef CONFIG_VT /* * Dummy mksound function that does nothing. * The real one is in the dmasound driver. @@ -262,6 +263,7 @@ pmac_mksound(unsigned int hz, unsigned int ticks) { } +#endif /* CONFIG_VT */ static volatile u32 *sysctrl_regs; @@ -345,9 +347,9 @@ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif - +#ifdef CONFIG_VT kd_mksound = pmac_mksound; - +#endif #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); @@ -380,7 +382,7 @@ void *boot_host; int boot_target; int boot_part; -kdev_t boot_dev; +extern kdev_t boot_dev; void __init pmac_init2(void) diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c --- v2.4.2/linux/arch/ppc/kernel/ppc8xx_pic.c Tue May 2 13:05:40 2000 +++ linux/arch/ppc/kernel/ppc8xx_pic.c Sat Mar 3 10:52:14 2001 @@ -153,6 +153,20 @@ irq += i8259_pic.irq_offset; return (request_8xxirq(irq, handler, irqflags, devname, dev_id)); #else - panic("request_irq"); + /* + * Handle other "well-known" interrupts, but panic on unknown ones. + */ + switch (irq) { +#ifdef IDE0_INTERRUPT + case IDE0_INTERRUPT: /* fall through */ +#endif +#ifdef IDE1_INTERRUPT + case IDE1_INTERRUPT: /* fall through */ +#endif + return (request_8xxirq(irq, handler, irqflags, devname, dev_id)); + + default: /* unknown IRQ -> panic */ + panic("request_irq"); + } #endif } diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.4.2/linux/arch/ppc/kernel/ppc_ksyms.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/ppc_ksyms.c Sat Mar 3 10:52:14 2001 @@ -46,6 +46,10 @@ #endif /* CONFIG_SMP */ #include +#ifdef CONFIG_8xx +#include "../8xx_io/commproc.h" +#endif + /* Tell string.h we don't want memcpy etc. as cpp defines */ #define EXPORT_SYMTAB_STROPS @@ -94,7 +98,7 @@ EXPORT_SYMBOL_NOVERS(pci_dram_offset); #endif EXPORT_SYMBOL(ISA_DMA_THRESHOLD); -EXPORT_SYMBOL(DMA_MODE_READ); +EXPORT_SYMBOL_NOVERS(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); #ifndef CONFIG_8xx #if defined(CONFIG_ALL_PPC) @@ -192,6 +196,9 @@ EXPORT_SYMBOL(giveup_altivec); #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SMP +EXPORT_SYMBOL(global_irq_lock); +EXPORT_SYMBOL(global_irq_count); +EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); @@ -242,11 +249,11 @@ EXPORT_SYMBOL(set_backlight_enable); EXPORT_SYMBOL(register_backlight_controller); #endif /* CONFIG_PMAC_BACKLIGHT */ -EXPORT_SYMBOL_NOVERS(sys_ctrler); #ifndef CONFIG_MACH_SPECIFIC EXPORT_SYMBOL_NOVERS(have_of); #endif /* CONFIG_MACH_SPECIFIC */ #if defined(CONFIG_ALL_PPC) +EXPORT_SYMBOL_NOVERS(sys_ctrler); EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -280,7 +287,9 @@ #if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(note_scsi_host); #endif +#ifdef CONFIG_VT EXPORT_SYMBOL(kd_mksound); +#endif #ifdef CONFIG_NVRAM EXPORT_SYMBOL(nvram_read_byte); EXPORT_SYMBOL(nvram_write_byte); @@ -342,11 +351,18 @@ EXPORT_SYMBOL(debugger_fault_handler); #endif +#ifdef CONFIG_8xx +EXPORT_SYMBOL(request_8xxirq); +EXPORT_SYMBOL(cpm_install_handler); +EXPORT_SYMBOL(cpm_free_handler); +#endif /* CONFIG_8xx */ + EXPORT_SYMBOL(ret_to_user_hook); EXPORT_SYMBOL(do_softirq); EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(mmu_context_overflow); +EXPORT_SYMBOL_NOVERS(disarm_decr); #if !defined(CONFIG_8xx) && !defined(CONFIG_4xx) extern long *intercept_table; EXPORT_SYMBOL(intercept_table); diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c --- v2.4.2/linux/arch/ppc/kernel/prep_pci.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/prep_pci.c Sat Mar 3 10:52:14 2001 @@ -37,6 +37,10 @@ /* How is the 82378 PIRQ mapping setup? */ unsigned char *Motherboard_routes; +void (*Motherboard_non0)(struct pci_dev *); + +void Powerplus_Map_Non0(struct pci_dev *); + /* Used for Motorola to store system config register */ static unsigned long *ProcInfo; @@ -505,6 +509,52 @@ 13 /* Line 4 */ }; +/* Motorola PowerPlus architecture PCI IRQ tables */ +/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */ + +struct powerplus_irq_list +{ + unsigned char primary[4]; /* INT A-D */ + unsigned char secondary[4]; /* INT A-D */ +}; + +/* + * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to + * OpenPIC inputs 9-12. PCI INTs A-D from the on board P2P bridge + * are routed to OpenPIC inputs 5-8. These values are offset by + * 16 in the table to reflect the Linux kernel interrupt value. + */ +struct powerplus_irq_list Powerplus_pci_IRQ_list = +{ + {25, 26, 27, 28}, + {21, 22, 23, 24} +}; + +/* + * For the MCP750 (system slot board), cPCI INTs A-D are routed to + * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC + * input 3. On a hot swap MCP750, the companion card PCI INTs A-D + * are routed to OpenPIC inputs 12-15. These values are offset by + * 16 in the table to reflect the Linux kernel interrupt value. + */ +struct powerplus_irq_list Mesquite_pci_IRQ_list = +{ + {24, 25, 26, 27}, + {28, 29, 30, 31} +}; + +/* + * This table represents the standard PCI swizzle defined in the + * PCI bus specification. + */ +static unsigned char prep_pci_intpins[4][4] = +{ + { 1, 2, 3, 4}, /* Buses 0, 4, 8, ... */ + { 2, 3, 4, 1}, /* Buses 1, 5, 9, ... */ + { 3, 4, 1, 2}, /* Buses 2, 6, 10 ... */ + { 4, 1, 2, 3}, /* Buses 3, 7, 11 ... */ +}; + /* We have to turn on LEVEL mode for changed IRQ's */ /* All PCI IRQ's need to be level mode, so this should be something * other than hard-coded as well... IRQ's are individually mappable @@ -599,6 +649,7 @@ #define MOT_RAVEN_PRESENT 0x1 #define MOT_HAWK_PRESENT 0x2 +int mot_entry = -1; int prep_keybd_present = 1; int MotMPIC; int mot_multi; @@ -682,33 +733,36 @@ const char *name; unsigned char *map; unsigned char *routes; + void (*map_non0_bus)(struct pci_dev *); /* For boards with more than bus 0 devices. */ + struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */ + unsigned char secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */ } mot_info[] = { - {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes}, - {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes}, - {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes}, - {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes}, - {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes}, - {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes}, - {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes}, - {0x000, 0x00, 0x00, "", NULL, NULL} + {0x300, 0x00, 0x00, "MVME 2400", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x010, 0x00, 0x00, "Genesis", Genesis_pci_IRQ_map, Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x020, 0x00, 0x00, "Powerstack (Series E)", Comet_pci_IRQ_map, Comet_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x040, 0x00, 0x00, "Blackhawk (Powerstack)", Blackhawk_pci_IRQ_map, Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)", Omaha_pci_IRQ_map, Omaha_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)", Utah_pci_IRQ_map, Utah_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x0A0, 0x00, 0x00, "Powerstack (Series EX)", Comet2_pci_IRQ_map, Comet2_pci_IRQ_routes, NULL, NULL, 0x00}, + {0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF}, + {0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", Sitka_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", Mesquite_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0}, + {0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0}, + {0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0}, + {0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00}, + {0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011", Genesis2_pci_IRQ_map, Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF}, + {0x000, 0x00, 0x00, "", NULL, NULL, NULL, NULL, 0x00} }; unsigned long __init prep_route_pci_interrupts(void) @@ -723,7 +777,6 @@ unsigned char cpu_type; unsigned char base_mod; int entry; - int mot_entry = -1; cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0; base_mod = inb(MOTOROLA_BASETYPE_REG); @@ -769,6 +822,7 @@ Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name; Motherboard_map = mot_info[mot_entry].map; Motherboard_routes = mot_info[mot_entry].routes; + Motherboard_non0 = mot_info[mot_entry].map_non0_bus; if (!(mot_info[entry].cpu_type & 0x100)) { /* AJF adjust level/edge control according to routes */ @@ -836,6 +890,157 @@ } void __init +prep_pib_init(void) +{ +unsigned char reg; +unsigned short short_reg; + +struct pci_dev *dev = NULL; + + if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) { + /* + * Perform specific configuration for the Via Tech or + * or Winbond PCI-ISA-Bridge part. + */ + if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_1, dev))) { + /* + * PPCBUG does not set the enable bits + * for the IDE device. Force them on here. + */ + pcibios_read_config_byte(dev->bus->number, + dev->devfn, 0x40, ®); + + reg |= 0x03; /* IDE: Chip Enable Bits */ + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x40, reg); + + /* Force correct IDE function interrupt */ + dev->irq = 14; + pcibios_write_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_LINE, + dev->irq); + + } else if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_83C553, dev))) { + /* + * Clear the PCI Interrupt Routing Control Register. + */ + short_reg = 0x0000; + pci_write_config_word(dev, 0x44, short_reg); + if (OpenPIC_Addr){ + /* + * Route both IDE interrupts to IRQ 14 + */ + reg = 0xEE; + pci_write_config_byte(dev, 0x44, reg); + } + } + if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_2, + dev))) + { + /* Force correct USB function interrupt */ + dev->irq = 11; + pcibios_write_config_byte(dev->bus->number, + dev->devfn, + PCI_INTERRUPT_LINE, + dev->irq); + } + } + if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, dev))){ + if (OpenPIC_Addr){ + /* Disable LEGIRQ mode so PCI INTs are routed to + the 8259 */ + printk("Set winbond IDE to native mode\n"); + pci_write_config_dword(dev, 0x40, 0x10ff00a1); + }else{ + /* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */ + pci_write_config_dword(dev, 0x40, 0x10ff08a1); + } + } +} + +void +Powerplus_Map_Non0(struct pci_dev *dev) +{ + struct pci_bus *pbus; /* Parent bus structure pointer */ + struct pci_dev *tdev = dev; /* Temporary device structure */ + unsigned int devnum; /* Accumulated device number */ + unsigned char intline; /* Linux interrupt value */ + unsigned char intpin; /* PCI interrupt pin */ + + /* Check for valid PCI dev pointer */ + if (dev == NULL) return; + + /* Initialize bridge IDSEL variable */ + devnum = PCI_SLOT(tdev->devfn); + + /* Read the interrupt pin of the device and adjust for indexing */ + pcibios_read_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_PIN, &intpin); + + /* If device doesn't request an interrupt, return */ + if ( (intpin < 1) || (intpin > 4) ) + return; + + intpin--; + + /* + * Walk up to bus 0, adjusting the interrupt pin for the standard + * PCI bus swizzle. + */ + do { + intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1; + pbus = tdev->bus; /* up one level */ + tdev = pbus->self; + devnum = PCI_SLOT(tdev->devfn); + } while(tdev->bus->number); + + /* Use the primary interrupt inputs by default */ + intline = mot_info[mot_entry].pci_irq_list->primary[intpin]; + + /* + * If the board has secondary interrupt inputs, walk the bus and + * note the devfn of the bridge from bus 0. If it is the same as + * the devfn of the bus bridge with secondary inputs, use those. + * Otherwise, assume it's a PMC site and get the interrupt line + * value from the interrupt routing table. + */ + if (mot_info[mot_entry].secondary_bridge_devfn) + { + pbus = dev->bus; + + while (pbus->primary != 0) + pbus = pbus->parent; + + if ((pbus->self)->devfn != 0xA0) + { + if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn) + intline = mot_info[mot_entry].pci_irq_list->secondary[intpin]; + else + { + if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map) + intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16; + else + { + int i; + for (i=0;i<3;i++) + intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1; + intline = mot_info[mot_entry].pci_irq_list->primary[intpin]; + } + } + } + } + + /* Write calculated interrupt value to header and device list */ + dev->irq = intline; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq); +} + +void __init prep_pcibios_fixup(void) { struct pci_dev *dev; @@ -849,11 +1054,21 @@ if (OpenPIC_Addr) { /* PCI interrupts are controlled by the OpenPIC */ pci_for_each_dev(dev) { - if (dev->bus->number == 0) { + if (dev->bus->number == 0) + { dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]); - pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq); + pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq); + } + else + { + if (Motherboard_non0 != NULL) + Motherboard_non0(dev); } } + + /* Setup the Winbond or Via PIB */ + prep_pib_init(); + return; } @@ -912,6 +1127,7 @@ hose->first_busno = 0; hose->last_busno = 0xff; hose->pci_mem_offset = PREP_ISA_MEM_BASE; + hose->io_base_virt = (void *)PREP_ISA_IO_BASE; printk("PReP architecture\n"); { diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.4.2/linux/arch/ppc/kernel/prep_setup.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/prep_setup.c Sat Mar 3 10:52:14 2001 @@ -215,7 +215,6 @@ void __init prep_setup_arch(void) { - extern char cmd_line[]; unsigned char reg; #if 0 /* unused?? */ unsigned char ucMothMemType; @@ -272,8 +271,6 @@ } } - printk("Boot arguments: %s\n", cmd_line); - #ifdef CONFIG_SOUND_CS4232 /* * setup proper values for the cs4232 driver so we don't have diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.4.2/linux/arch/ppc/kernel/prom.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/prom.c Sat Mar 3 10:52:14 2001 @@ -757,8 +757,11 @@ setup_disp_fake_bi(RELOC(prom_disp_node)); #endif - /* If OpenFirmware version >= 3, then use quiesce call */ - if (prom_version >= 3) { + /* If pmac, then use quiesce call. We can't rely on prom_version + * since some old iMacs appear to have an incorrect /openprom/model + * entry in the device tree + */ + if (!chrp) { prom_print(RELOC("Calling quiesce ...\n")); call_prom(RELOC("quiesce"), 0, 0); } diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.4.2/linux/arch/ppc/kernel/setup.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/setup.c Sat Mar 3 10:52:14 2001 @@ -386,8 +386,8 @@ if ( i ) len += sprintf(buffer+len, "\n"); len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n", - (bogosum+2500)/500000, - (bogosum+2500)/5000 % 100); + (bogosum+2500)/(500000/HZ), + (bogosum+2500)/(5000/HZ) % 100); #endif /* CONFIG_SMP */ /* diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.4.2/linux/arch/ppc/kernel/smp.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/smp.c Sat Mar 3 10:52:14 2001 @@ -100,14 +100,14 @@ #define PSURGE_QUAD_CKSTOP_RDBK 8 #define PSURGE_QUAD_RESET_CTL 11 -#define PSURGE_QUAD_OUT(r, v) (out_8((u8 *)(quad_base+((r)<<2)+1), (v))) -#define PSURGE_QUAD_IN(r) (in_8((u8 *)(quad_base+((r)<<2)+1)) & 0x0f) +#define PSURGE_QUAD_OUT(r, v) (out_8(quad_base + ((r) << 4) + 4, (v))) +#define PSURGE_QUAD_IN(r) (in_8(quad_base + ((r) << 4) + 4) & 0x0f) #define PSURGE_QUAD_BIS(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v))) #define PSURGE_QUAD_BIC(r, v) (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v))) /* virtual addresses for the above */ static volatile u8 *hhead_base; -static volatile u32 *quad_base; +static volatile u8 *quad_base; static volatile u32 *psurge_pri_intr; static volatile u8 *psurge_sec_intr; static volatile u32 *psurge_start; @@ -216,7 +216,7 @@ /* * Determine a quad card presence. We read the board ID register, we - * for the data bus to change to something else, and we read it again. + * force the data bus to change to something else, and we read it again. * It it's stable, then the register probably exist (ugh !) */ static int __init psurge_quad_probe(void) @@ -303,11 +303,7 @@ psurge_type = psurge_quad_probe(); if (psurge_type != PSURGE_DUAL) { psurge_quad_init(); - /* I believe we could "count" CPUs by counting 1 bits - * in procbits on a quad board. For now, we assume 4, - * non-present CPUs will just be seen as "stuck". - * (hope they are the higher-numbered ones -- paulus) - */ + /* All released cards using this HW design have 4 CPUs */ ncpus = 4; } else { iounmap((void *) quad_base); @@ -424,11 +420,10 @@ break; case MSG_ALL_BUT_SELF: openpic_cause_IPI(msg, - 0xffffffff & ~(1 << smp_hw_index[smp_processor_id()])); - + 0xffffffff & ~(1 << smp_processor_id())); break; default: - openpic_cause_IPI(msg, smp_hw_index[1< */ - cpus = find_type_devices("cpu"); - if (cpus){ - for ( ncpus = 1; cpus->next; cpus = cpus->next ){ - ncpus++; - } - } -#endif - printk("smp_core99_probe: OF reports %d cpus\n", ncpus); + if (cpus) + while ((cpus = cpus->next) != NULL) + ++ncpus; + printk("smp_core99_probe: found %d cpus\n", ncpus); if (ncpus > 1) { openpic_request_IPIs(); for (i = 1; i < ncpus; ++i) @@ -1010,6 +992,9 @@ /* Setup CPU 0 last (important) */ smp_ops->setup_cpu(0); + + if (smp_num_cpus < 2) + smp_tb_synchronized = 1; } void __init smp_software_tb_sync(int cpu) @@ -1027,17 +1012,6 @@ register unsigned long start = 0; register unsigned long stop = 0; register unsigned long temp = 0; - - if (smp_num_cpus < 2) { - smp_tb_synchronized = 1; - return; - } - - /* This code need fixing on >2 CPUs --BenH/paulus */ - if (smp_num_cpus > 2) { - smp_tb_synchronized = 0; - return; - } set_tb(0, 0); @@ -1107,6 +1081,7 @@ if (ppc_md.progress) ppc_md.progress("smp_commence", 0x370); wmb(); smp_commenced = 1; + /* if the smp_ops->setup_cpu function has not already synched the * timebases with a nicer hardware-based method, do so now * @@ -1117,9 +1092,9 @@ * since if this code runs pretty early and needs all cpus that * reported in in smp_callin_map to be working * - * NOTE2: this code doesn't seem to work on > 2 cpus. -- paulus + * NOTE2: this code doesn't seem to work on > 2 cpus. -- paulus/BenH */ - if (!smp_tb_synchronized) { + if (!smp_tb_synchronized && smp_num_cpus == 2) { unsigned long flags; __save_and_cli(flags); smp_software_tb_sync(0); @@ -1142,7 +1117,7 @@ while(!smp_commenced) barrier(); /* see smp_commence for more info */ - if (!smp_tb_synchronized){ + if (!smp_tb_synchronized && smp_num_cpus == 2) { smp_software_tb_sync(cpu); } __sti(); diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/softemu8xx.c linux/arch/ppc/kernel/softemu8xx.c --- v2.4.2/linux/arch/ppc/kernel/softemu8xx.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/softemu8xx.c Sat Mar 3 10:52:14 2001 @@ -75,12 +75,12 @@ sdisp = (instword & 0xffff); ea = (uint *)(regs->gpr[idxreg] + sdisp); if (copy_from_user(ip, ea, sizeof(double))) - retval = EFAULT; + retval = -EFAULT; break; case LFDU: if (copy_from_user(ip, ea, sizeof(double))) - retval = EFAULT; + retval = -EFAULT; else regs->gpr[idxreg] = (uint)ea; break; @@ -88,7 +88,7 @@ sdisp = (instword & 0xffff); ea = (uint *)(regs->gpr[idxreg] + sdisp); if (copy_from_user(ip, ea, sizeof(float))) - retval = EFAULT; + retval = -EFAULT; break; case STFD: /* this is a 16 bit quantity that is sign extended @@ -97,12 +97,12 @@ sdisp = (instword & 0xffff); ea = (uint *)(regs->gpr[idxreg] + sdisp); if (copy_to_user(ea, ip, sizeof(double))) - retval = EFAULT; + retval = -EFAULT; break; case STFDU: if (copy_to_user(ea, ip, sizeof(double))) - retval = EFAULT; + retval = -EFAULT; else regs->gpr[idxreg] = (uint)ea; break; diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.4.2/linux/arch/ppc/kernel/time.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/time.c Sat Mar 3 10:52:14 2001 @@ -67,6 +67,8 @@ #include +unsigned long disarm_decr[NR_CPUS]; + #ifdef CONFIG_SMP extern void smp_local_timer_interrupt(struct pt_regs *); extern int smp_tb_synchronized; @@ -147,7 +149,6 @@ if (!user_mode(regs)) ppc_do_profile(instruction_pointer(regs)); - do { jiffy_stamp += tb_ticks_per_jiffy; if (smp_processor_id()) continue; @@ -184,7 +185,8 @@ } write_unlock(&xtime_lock); } while((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0); - set_dec(next_dec); + if ( !disarm_decr[smp_processor_id()] ) + set_dec(next_dec); last_jiffy_stamp(cpu) = jiffy_stamp; #ifdef CONFIG_SMP diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.4.2/linux/arch/ppc/kernel/traps.c Wed Feb 21 18:20:14 2001 +++ linux/arch/ppc/kernel/traps.c Sat Mar 3 10:52:14 2001 @@ -237,7 +237,7 @@ return retval; if (get_user(instword, (uint *)(regs->nip))) - return EFAULT; + return -EFAULT; /* Emulate the mfspr rD, PVR. */ @@ -281,7 +281,7 @@ /* Try to emulate it if we should. */ int errcode; if ((errcode = emulate_instruction(regs))) { - if (errcode == EFAULT) + if (errcode == -EFAULT) _exception(SIGBUS, regs); else _exception(SIGILL, regs); diff -u --recursive --new-file v2.4.2/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.4.2/linux/arch/ppc/mm/fault.c Sat Feb 3 19:51:24 2001 +++ linux/arch/ppc/mm/fault.c Sat Mar 3 10:52:14 2001 @@ -276,7 +276,7 @@ pte = va_to_pte(address); if (pte) - return(((unsigned long)(pte_val(*pte)) & PAGE_MASK) | (address & ~(PAGE_MASK-1))); + return(((unsigned long)(pte_val(*pte)) & PAGE_MASK) | (address & ~(PAGE_MASK))); return (0); } diff -u --recursive --new-file v2.4.2/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.4.2/linux/arch/ppc/mm/init.c Sat Feb 3 19:51:24 2001 +++ linux/arch/ppc/mm/init.c Sat Mar 3 10:52:14 2001 @@ -889,13 +889,14 @@ #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { + printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); set_page_count(virt_to_page(start), 1); free_page(start); totalram_pages++; } - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); } #endif diff -u --recursive --new-file v2.4.2/linux/arch/ppc/treeboot/mkevimg linux/arch/ppc/treeboot/mkevimg --- v2.4.2/linux/arch/ppc/treeboot/mkevimg Mon May 15 14:53:30 2000 +++ linux/arch/ppc/treeboot/mkevimg Sat Mar 3 10:52:14 2001 @@ -431,7 +431,7 @@ close(BOOT); - print("\nBoot image file \"$ofile\" built successfuly.\n\n"); + print("\nBoot image file \"$ofile\" built successfully.\n\n"); exit(0); } diff -u --recursive --new-file v2.4.2/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.4.2/linux/arch/s390/kernel/entry.S Wed Feb 21 18:20:14 2001 +++ linux/arch/s390/kernel/entry.S Fri Mar 2 11:12:06 2001 @@ -687,7 +687,7 @@ lr %r3,%r8 la %r0,0x7f nr %r3,%r0 # clear per-event-bit - be BASED(pgm_dn) # none of Martins exceptions occured bypass + be BASED(pgm_dn) # none of Martins exceptions occurred bypass l %r9,BASED(.Ljump_table) sll %r3,2 l %r9,0(%r3,%r9) # load address of handler routine diff -u --recursive --new-file v2.4.2/linux/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c --- v2.4.2/linux/arch/s390/tools/dasdfmt/dasdfmt.c Wed Feb 21 18:20:14 2001 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.c Fri Mar 2 11:12:06 2001 @@ -477,7 +477,7 @@ rc=stat(dev_name,&stat_buf); if (rc) { - ERRMSG_EXIT(EXIT_FAILURE,"%s: error occured during stat: " \ + ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \ "%s\n",prog_name,strerror(errno)); } else { if (!S_ISBLK(stat_buf.st_mode)) diff -u --recursive --new-file v2.4.2/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S --- v2.4.2/linux/arch/s390x/kernel/entry.S Wed Feb 21 18:20:14 2001 +++ linux/arch/s390x/kernel/entry.S Fri Mar 2 11:12:06 2001 @@ -724,7 +724,7 @@ stosm 48(%r15),0x03 # reenable interrupts lghi %r3,0x7f nr %r3,%r8 # clear per-event-bit & move to r3 - je pgm_dn # none of Martins exceptions occured bypass + je pgm_dn # none of Martins exceptions occurred bypass sll %r3,3 larl %r9,pgm_check_table lg %r9,0(%r3,%r9) # load address of handler routine diff -u --recursive --new-file v2.4.2/linux/arch/s390x/tools/dasdfmt/dasdfmt.c linux/arch/s390x/tools/dasdfmt/dasdfmt.c --- v2.4.2/linux/arch/s390x/tools/dasdfmt/dasdfmt.c Wed Feb 21 18:20:15 2001 +++ linux/arch/s390x/tools/dasdfmt/dasdfmt.c Fri Mar 2 11:12:06 2001 @@ -477,7 +477,7 @@ rc=stat(dev_name,&stat_buf); if (rc) { - ERRMSG_EXIT(EXIT_FAILURE,"%s: error occured during stat: " \ + ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \ "%s\n",prog_name,strerror(errno)); } else { if (!S_ISBLK(stat_buf.st_mode)) diff -u --recursive --new-file v2.4.2/linux/arch/sh/kernel/sh_ksyms.c linux/arch/sh/kernel/sh_ksyms.c --- v2.4.2/linux/arch/sh/kernel/sh_ksyms.c Sat Feb 3 19:51:24 2001 +++ linux/arch/sh/kernel/sh_ksyms.c Fri Mar 2 11:15:47 2001 @@ -77,3 +77,4 @@ /* needed by some modules */ EXPORT_SYMBOL(flush_dcache_page); #endif +EXPORT_SYMBOL(flush_tlb_page); diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.4.2/linux/arch/sparc64/config.in Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/config.in Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.130 2001/01/18 04:47:44 davem Exp $ +# $Id: config.in,v 1.133 2001/03/07 00:44:36 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -165,12 +165,14 @@ dep_tristate 'PTI Qlogic, ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI if [ "$CONFIG_PCI" != "n" ]; then - dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI - if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then - bool ' Enable tagged command queueing (TCQ) by default' CONFIG_AIC7XXX_TAGGED_QUEUEING - int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8 - bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS - int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 + source drivers/scsi/aic7xxx/Config.in + if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then + dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI + if [ "$CONFIG_SCSI_AIC7XXX_OLD" != "n" ]; then + bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT + int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE 8 + bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_OLD_PROC_STATS + fi fi dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI @@ -196,8 +198,6 @@ endmenu fi endmenu - -source drivers/message/fusion/Config.in source drivers/fc4/Config.in diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.4.2/linux/arch/sparc64/defconfig Sat Feb 3 19:51:24 2001 +++ linux/arch/sparc64/defconfig Tue Mar 6 22:44:16 2001 @@ -151,7 +151,6 @@ # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set # CONFIG_BLK_DEV_LVM is not set -# CONFIG_LVM_PROC_FS is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set @@ -305,10 +304,12 @@ CONFIG_SCSI_SUNESP=y CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_AIC7XXX=m -CONFIG_AIC7XXX_TAGGED_QUEUEING=y -CONFIG_AIC7XXX_CMDS_PER_DEVICE=8 -CONFIG_AIC7XXX_PROC_STATS=y -CONFIG_AIC7XXX_RESET_DELAY=5 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 +CONFIG_AIC7XXX_RESET_DELAY=5000 +CONFIG_SCSI_AIC7XXX_OLD=m +CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y +CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8 +CONFIG_AIC7XXX_OLD_PROC_STATS=y CONFIG_SCSI_NCR53C8XX=m CONFIG_SCSI_SYM53C8XX=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.4.2/linux/arch/sparc64/kernel/Makefile Fri Dec 29 14:07:21 2000 +++ linux/arch/sparc64/kernel/Makefile Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.63 2000/12/14 22:57:25 davem Exp $ +# $Id: Makefile,v 1.64 2001/02/28 05:59:45 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -27,7 +27,7 @@ power.o sbus.o iommu_common.o sparc64_ksyms.o obj-$(CONFIG_PCI) += ebus.o pci_common.o pci_iommu.o \ - pci_psycho.o pci_sabre.o + pci_psycho.o pci_sabre.o pci_schizo.o obj-$(CONFIG_SMP) += smp.o trampoline.o obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o ioctl32.o obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c --- v2.4.2/linux/arch/sparc64/kernel/cpu.c Mon May 8 22:00:01 2000 +++ linux/arch/sparc64/kernel/cpu.c Tue Mar 6 22:44:16 2001 @@ -34,6 +34,7 @@ { 0x22, 0x10, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x11, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"}, + { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"}, { 0x17, 0x14, 0, "UltraSparc III integrated FPU"}, }; @@ -44,7 +45,8 @@ { 0x22, 0x10, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x11, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x12, "TI UltraSparc IIi"}, - { 0x17, 0x14, "TI UltraSparc III (Cheetah)"}, /* A guess... */ + { 0x17, 0x13, "TI UltraSparc IIe"}, + { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"}, }; #define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c --- v2.4.2/linux/arch/sparc64/kernel/ebus.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/ebus.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.54 2001/02/13 01:16:44 davem Exp $ +/* $Id: ebus.c,v 1.57 2001/02/28 03:28:55 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -159,7 +159,7 @@ struct pci_controller_info *p = pbm->parent; if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) { - dev->irqs[i] = p->irq_build(p, + dev->irqs[i] = p->irq_build(pbm, dev->bus->self, irqs[i]); } else { @@ -222,7 +222,7 @@ struct pci_controller_info *p = pbm->parent; if (ebus_intmap_match(dev->bus, ®s[0], &irqs[i]) != -1) { - dev->irqs[i] = p->irq_build(p, + dev->irqs[i] = p->irq_build(pbm, dev->bus->self, irqs[i]); } else { diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S --- v2.4.2/linux/arch/sparc64/kernel/head.S Mon May 22 09:50:54 2000 +++ linux/arch/sparc64/kernel/head.S Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.65 2000/05/09 17:40:13 davem Exp $ +/* $Id: head.S,v 1.67 2001/03/04 18:31:00 davem Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -76,6 +78,138 @@ * PROM entry point is on %o4 */ sparc64_boot: + rdpr %ver, %g1 + sethi %hi(0x003e0014), %g5 + srlx %g1, 32, %g1 + or %g5, %lo(0x003e0014), %g5 + cmp %g1, %g5 + bne,pt %icc, spitfire_boot + nop + +cheetah_boot: + mov DCR_BPE | DCR_RPE | DCR_SI | DCR_MS, %g1 + wr %g1, %asr18 + + sethi %uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + or %g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + sllx %g5, 32, %g5 + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + or %g1, %g5, %g1 + stxa %g5, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + + wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate + wr %g0, 0, %fprs + + /* Just like for Spitfire, we probe itlb-2 for a mapping which + * matches our current %pc. We take the physical address in + * that mapping and use it to make our own. + */ + + /* %g5 holds the tlb data */ + sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5 + sllx %g5, 32, %g5 + or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5 + + /* Put PADDR tlb data mask into %g3. */ + sethi %uhi(_PAGE_PADDR), %g3 + or %g3, %ulo(_PAGE_PADDR), %g3 + sllx %g3, 32, %g3 + sethi %hi(_PAGE_PADDR), %g7 + or %g7, %lo(_PAGE_PADDR), %g7 + or %g3, %g7, %g3 + + set 2 << 16, %l0 /* TLB entry walker. */ + set 0x1fff, %l2 /* Page mask. */ + rd %pc, %l3 + andn %l3, %l2, %g2 /* vaddr comparator */ + +1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1 + membar #Sync + andn %g1, %l2, %g1 + cmp %g1, %g2 + be,pn %xcc, cheetah_got_tlbentry + nop + and %l0, (127 << 3), %g1 + cmp %g1, (127 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + +cheetah_got_tlbentry: + ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1 + membar #Sync + and %g1, %g3, %g1 + sub %g1, %g2, %g1 + or %g5, %g1, %g5 + + /* Clear out any KERNBASE area entries. */ + set 2 << 16, %l0 + sethi %hi(KERNBASE), %g3 + sethi %hi(KERNBASE<<1), %g7 + mov TLB_TAG_ACCESS, %l7 + + /* First, check ITLB */ +1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1 + membar #Sync + andn %g1, %l2, %g1 + cmp %g1, %g3 + blu,pn %xcc, 2f + cmp %g1, %g7 + bgeu,pn %xcc, 2f + nop + stxa %g0, [%l7] ASI_IMMU + membar #Sync + stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS + membar #Sync + +2: and %l0, (127 << 3), %g1 + cmp %g1, (127 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + + /* Next, check DTLB */ + set 2 << 16, %l0 +1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1 + membar #Sync + andn %g1, %l2, %g1 + cmp %g1, %g3 + blu,pn %xcc, 2f + cmp %g1, %g7 + bgeu,pn %xcc, 2f + nop + stxa %g0, [%l7] ASI_DMMU + membar #Sync + stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS + membar #Sync + +2: and %l0, (511 << 3), %g1 + cmp %g1, (511 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + + /* Now lock the TTE we created into ITLB-0 and DTLB-0, + * entry 15. + */ + sethi %hi(KERNBASE), %g3 + set (0 << 16) | (15 << 3), %g7 + stxa %g3, [%l7] ASI_DMMU + membar #Sync + stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS + membar #Sync + stxa %g3, [%l7] ASI_IMMU + membar #Sync + stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS + membar #Sync + flush %g3 + membar #Sync + ba,pt %xcc, 1f + nop + +1: set sun4u_init, %g2 + jmpl %g2 + %g0, %g0 + nop + +spitfire_boot: /* Typically PROM has already enabled both MMU's and both on-chip * caches, but we do it here anyway just to be paranoid. */ @@ -93,7 +227,7 @@ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate wr %g0, 0, %fprs -create_mappings: +spitfire_create_mappings: /* %g5 holds the tlb data */ sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5 sllx %g5, 32, %g5 @@ -104,11 +238,11 @@ */ /* Put PADDR tlb data mask into %g3. */ - sethi %uhi(_PAGE_PADDR), %g3 - or %g3, %ulo(_PAGE_PADDR), %g3 + sethi %uhi(_PAGE_PADDR_SF), %g3 + or %g3, %ulo(_PAGE_PADDR_SF), %g3 sllx %g3, 32, %g3 - sethi %hi(_PAGE_PADDR), %g7 - or %g7, %lo(_PAGE_PADDR), %g7 + sethi %hi(_PAGE_PADDR_SF), %g7 + or %g7, %lo(_PAGE_PADDR_SF), %g7 or %g3, %g7, %g3 /* Walk through entire ITLB, looking for entry which maps @@ -126,13 +260,14 @@ nop andn %g1, %l2, %g1 /* Get vaddr */ cmp %g1, %g2 - be,a,pn %xcc, got_tlbentry + be,a,pn %xcc, spitfire_got_tlbentry ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1 + /* XXX Spitfire dependency... */ cmp %l0, (63 << 3) blu,pt %xcc, 1b add %l0, (1 << 3), %l0 -got_tlbentry: +spitfire_got_tlbentry: /* Nops here again, perhaps Cheetah/Blackbird are better behaved... */ nop nop @@ -165,6 +300,7 @@ stxa %g0, [%l7] ASI_IMMU stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS 2: + /* XXX Spitfire dependency... */ cmp %l0, (63 << 3) blu,pt %xcc, 1b add %l0, (1 << 3), %l0 @@ -187,6 +323,7 @@ stxa %g0, [%l7] ASI_DMMU stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS 2: + /* XXX Spitfire dependency... */ cmp %l0, (63 << 3) blu,pt %xcc, 1b add %l0, (1 << 3), %l0 @@ -199,6 +336,7 @@ */ sethi %hi(KERNBASE), %g3 + /* XXX Spitfire dependency... */ mov (63 << 3), %g7 stxa %g3, [%l7] ASI_DMMU /* KERNBASE into TLB TAG */ stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS /* TTE into TLB DATA */ @@ -236,6 +374,7 @@ stxa %g3, [%g2] ASI_IMMU stxa %g3, [%g2] ASI_DMMU + /* XXX Spitfire dependency... */ mov (63 << 3), %g7 ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1 andn %g1, (_PAGE_G), %g1 @@ -342,12 +481,10 @@ /* Set fixed globals used by dTLB miss handler. */ #define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) -#ifdef THIS_IS_CHEETAH -#error Dave, make sure you took care of other issues in rest of sparc64 code... -#define VPTE_BASE 0xffe0000000000000 -#else /* Spitfire/Blackbird */ -#define VPTE_BASE 0xfffffffe00000000 -#endif + +#define VPTE_BASE_CHEETAH 0xffe0000000000000 +#define VPTE_BASE_SPITFIRE 0xfffffffe00000000 + mov TSB_REG, %g1 stxa %g0, [%g1] ASI_DMMU membar #Sync @@ -356,9 +493,25 @@ or %g2, %ulo(KERN_HIGHBITS), %g2 sllx %g2, 32, %g2 or %g2, KERN_LOWBITS, %g2 - sethi %uhi(VPTE_BASE), %g3 - or %g3, %ulo(VPTE_BASE), %g3 - sllx %g3, 32, %g3 + + rdpr %ver, %g3 + sethi %hi(0x003e0014), %g7 + srlx %g3, 32, %g3 + or %g7, %lo(0x003e0014), %g7 + cmp %g3, %g7 + bne,pt %icc, 1f + nop + + sethi %uhi(VPTE_BASE_CHEETAH), %g3 + or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 + ba,pt %xcc, 2f + sllx %g3, 32, %g3 +1: + sethi %uhi(VPTE_BASE_SPITFIRE), %g3 + or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 + sllx %g3, 32, %g3 + +2: clr %g7 #undef KERN_HIGHBITS #undef KERN_LOWBITS diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.4.2/linux/arch/sparc64/kernel/ioctl32.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/ioctl32.c Mon Mar 12 18:11:56 2001 @@ -3331,6 +3331,7 @@ COMPATIBLE_IOCTL(PPPIOCCONNECT) COMPATIBLE_IOCTL(PPPIOCDISCONN) COMPATIBLE_IOCTL(PPPIOCATTCHAN) +COMPATIBLE_IOCTL(PPPIOCGCHAN) /* PPPOX */ COMPATIBLE_IOCTL(PPPOEIOCSFWD); COMPATIBLE_IOCTL(PPPOEIOCDFWD); diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.4.2/linux/arch/sparc64/kernel/pci.c Sat Feb 3 19:51:24 2001 +++ linux/arch/sparc64/kernel/pci.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.21 2001/01/10 18:22:59 davem Exp $ +/* $Id: pci.c,v 1.22 2001/02/28 05:59:45 davem Exp $ * pci.c: UltraSparc PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -78,9 +78,7 @@ /* Probe for all PCI controllers in the system. */ extern void sabre_init(int); extern void psycho_init(int); -#if 0 extern void schizo_init(int); -#endif static struct { char *model_name; @@ -89,11 +87,9 @@ { "SUNW,sabre", sabre_init }, { "pci108e,a000", sabre_init }, { "SUNW,psycho", psycho_init }, - { "pci108e,8000", psycho_init } -#if 0 + { "pci108e,8000", psycho_init }, { "SUNW,schizo", schizo_init }, { "pci108e,8001", schizo_init } -#endif }; #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ sizeof(pci_controller_table[0])) diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c --- v2.4.2/linux/arch/sparc64/kernel/pci_common.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/pci_common.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_common.c,v 1.13 2001/02/13 01:16:44 davem Exp $ +/* $Id: pci_common.c,v 1.14 2001/02/28 03:28:55 davem Exp $ * pci_common.c: PCI controller common support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -560,19 +560,19 @@ /* Fully specified already? */ if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { - pdev->irq = p->irq_build(p, pdev, prom_irq); + pdev->irq = p->irq_build(pbm, pdev, prom_irq); goto have_irq; } /* An onboard device? (bit 5 set) */ if ((prom_irq & PCI_IRQ_INO) & 0x20) { - pdev->irq = p->irq_build(p, pdev, (portid << 6 | prom_irq)); + pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq)); goto have_irq; } /* Can we find a matching entry in the interrupt-map? */ if (pci_intmap_match(pdev, &prom_irq)) { - pdev->irq = p->irq_build(p, pdev, (portid << 6) | prom_irq); + pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq); goto have_irq; } @@ -609,7 +609,7 @@ } slot = slot << 2; - pdev->irq = p->irq_build(p, pdev, + pdev->irq = p->irq_build(pbm, pdev, ((portid << 6) & PCI_IRQ_IGN) | (bus | slot | line)); } @@ -632,17 +632,11 @@ pci_fixup_irq(pbm, pci_bus_b(walk)); } -#undef DEBUG_BUSMASTERING - static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz) { u16 cmd; u8 hdr_type, min_gnt, ltimer; -#ifdef DEBUG_BUSMASTERING - printk("PCI: Checking DEV(%s), ", pdev->name); -#endif - pci_read_config_word(pdev, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_MASTER; pci_write_config_word(pdev, PCI_COMMAND, cmd); @@ -652,43 +646,28 @@ * mastering so we have nothing to do here. */ pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if ((cmd & PCI_COMMAND_MASTER) == 0) { -#ifdef DEBUG_BUSMASTERING - printk("no bus mastering...\n"); -#endif + if ((cmd & PCI_COMMAND_MASTER) == 0) return; - } /* Set correct cache line size, 64-byte on all * Sparc64 PCI systems. Note that the value is * measured in 32-bit words. */ -#ifdef DEBUG_BUSMASTERING - printk("set cachelinesize, "); -#endif pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64 / sizeof(u32)); pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type); hdr_type &= ~0x80; - if (hdr_type != PCI_HEADER_TYPE_NORMAL) { -#ifdef DEBUG_BUSMASTERING - printk("hdr_type=%x, exit\n", hdr_type); -#endif + if (hdr_type != PCI_HEADER_TYPE_NORMAL) return; - } /* If the latency timer is already programmed with a non-zero * value, assume whoever set it (OBP or whoever) knows what * they are doing. */ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, <imer); - if (ltimer != 0) { -#ifdef DEBUG_BUSMASTERING - printk("ltimer was %x, exit\n", ltimer); -#endif + if (ltimer != 0) return; - } /* XXX Since I'm tipping off the min grant value to * XXX choose a suitable latency timer value, I also @@ -738,9 +717,6 @@ } pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer); -#ifdef DEBUG_BUSMASTERING - printk("set ltimer to %x\n", ltimer); -#endif } void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm, diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c --- v2.4.2/linux/arch/sparc64/kernel/pci_psycho.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/pci_psycho.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.19 2001/02/13 01:16:44 davem Exp $ +/* $Id: pci_psycho.c,v 1.21 2001/02/28 03:28:55 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -72,7 +72,7 @@ * --------------------------------------------------------- */ #define PSYCHO_CONFIG_BASE(PBM) \ - ((PBM)->parent->config_space | (1UL << 24)) + ((PBM)->config_space | (1UL << 24)) #define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \ (((unsigned long)(BUS) << 16) | \ ((unsigned long)(DEVFN) << 8) | \ @@ -376,10 +376,11 @@ return ret; } -static unsigned int __init psycho_irq_build(struct pci_controller_info *p, +static unsigned int __init psycho_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { + struct pci_controller_info *p = pbm->parent; struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; @@ -1002,12 +1003,13 @@ #define PSYCHO_PCIERR_B_INO 0x31 static void __init psycho_register_error_handlers(struct pci_controller_info *p) { + struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ unsigned long base = p->controller_regs; unsigned int irq, portid = p->portid; u64 tmp; /* Build IRQs and register handlers. */ - irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_UE_INO); + irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_UE_INO); if (request_irq(irq, psycho_ue_intr, SA_SHIRQ, "PSYCHO UE", p) < 0) { prom_printf("PSYCHO%d: Cannot register UE interrupt.\n", @@ -1015,7 +1017,7 @@ prom_halt(); } - irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_CE_INO); + irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_CE_INO); if (request_irq(irq, psycho_ce_intr, SA_SHIRQ, "PSYCHO CE", p) < 0) { prom_printf("PSYCHO%d: Cannot register CE interrupt.\n", @@ -1023,7 +1025,7 @@ prom_halt(); } - irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); + irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); if (request_irq(irq, psycho_pcierr_intr, SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) { prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n", @@ -1031,7 +1033,7 @@ prom_halt(); } - irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); + irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); if (request_irq(irq, psycho_pcierr_intr, SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) { prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n", @@ -1574,8 +1576,10 @@ printk("PCI: Found PSYCHO, control regs at %016lx\n", p->controller_regs); - p->config_space = pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE; - printk("PSYCHO: PCI config space at %016lx\n", p->config_space); + p->pbm_A.config_space = p->pbm_B.config_space = + (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE); + printk("PSYCHO: Shared PCI config space at %016lx\n", + p->pbm_A.config_space); /* * Psycho's PCI MEM space is mapped to a 2GB aligned area, so diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c --- v2.4.2/linux/arch/sparc64/kernel/pci_sabre.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/pci_sabre.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.23 2001/02/13 01:16:44 davem Exp $ +/* $Id: pci_sabre.c,v 1.25 2001/02/28 03:28:55 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -209,7 +209,7 @@ * --------------------------------------------------------- */ #define SABRE_CONFIG_BASE(PBM) \ - ((PBM)->parent->config_space | (1UL << 24)) + ((PBM)->config_space | (1UL << 24)) #define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ (((unsigned long)(BUS) << 16) | \ ((unsigned long)(DEVFN) << 8) | \ @@ -604,10 +604,11 @@ return ret; } -static unsigned int __init sabre_irq_build(struct pci_controller_info *p, +static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { + struct pci_controller_info *p = pbm->parent; struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; @@ -961,6 +962,7 @@ #define SABRE_PCIERR_INO 0x30 static void __init sabre_register_error_handlers(struct pci_controller_info *p) { + struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ unsigned long base = p->controller_regs; unsigned long irq, portid = p->portid; u64 tmp; @@ -973,7 +975,7 @@ (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); - irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_UE_INO); + irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_UE_INO); if (request_irq(irq, sabre_ue_intr, SA_SHIRQ, "SABRE UE", p) < 0) { prom_printf("SABRE%d: Cannot register UE interrupt.\n", @@ -984,7 +986,7 @@ sabre_write(base + SABRE_CE_AFSR, (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); - irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_CE_INO); + irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_CE_INO); if (request_irq(irq, sabre_ce_intr, SA_SHIRQ, "SABRE CE", p) < 0) { prom_printf("SABRE%d: Cannot register CE interrupt.\n", @@ -992,7 +994,7 @@ prom_halt(); } - irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_PCIERR_INO); + irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_PCIERR_INO); if (request_irq(irq, sabre_pcierr_intr, SA_SHIRQ, "SABRE PCIERR", p) < 0) { prom_printf("SABRE%d: Cannot register PciERR interrupt.\n", @@ -1434,8 +1436,10 @@ SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN)); /* Now map in PCI config space for entire SABRE. */ - p->config_space = p->controller_regs + SABRE_CONFIGSPACE; - printk("SABRE: PCI config space at %016lx\n", p->config_space); + p->pbm_A.config_space = p->pbm_B.config_space = + (p->controller_regs + SABRE_CONFIGSPACE); + printk("SABRE: Shared PCI config space at %016lx\n", + p->pbm_A.config_space); err = prom_getproperty(pnode, "virtual-dma", (char *)&vdma[0], sizeof(vdma)); diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c --- v2.4.2/linux/arch/sparc64/kernel/pci_schizo.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/pci_schizo.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_schizo.c,v 1.3 2001/02/13 01:16:44 davem Exp $ +/* $Id: pci_schizo.c,v 1.8 2001/03/01 08:05:32 davem Exp $ * pci_schizo.c: SCHIZO specific PCI controller support. * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -16,34 +16,240 @@ #include "pci_impl.h" +/* All SCHIZO registers are 64-bits. The following accessor + * routines are how they are accessed. The REG parameter + * is a physical address. + */ +#define schizo_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define schizo_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E)) + +/* This is a convention that at least Excalibur and Merlin + * follow. I suppose the SCHIZO used in Starcat and friends + * will do similar. + * + * The only way I could see this changing is if the newlink + * block requires more space in Schizo's address space than + * they predicted, thus requiring an address space reorg when + * the newer Schizo is taped out. + * + * These offsets look weird because I keep in p->controller_regs + * the second PROM register property minus 0x10000 which is the + * base of the Safari and UPA64S registers of SCHIZO. + */ +#define SCHIZO_PBM_A_REGS_OFF (0x600000UL - 0x400000UL) +#define SCHIZO_PBM_B_REGS_OFF (0x700000UL - 0x400000UL) + +/* Streaming buffer control register. */ +#define SCHIZO_STRBUF_CTRL_LPTR 0x00000000000000f0UL /* LRU Lock Pointer */ +#define SCHIZO_STRBUF_CTRL_LENAB 0x0000000000000008UL /* LRU Lock Enable */ +#define SCHIZO_STRBUF_CTRL_RRDIS 0x0000000000000004UL /* Rerun Disable */ +#define SCHIZO_STRBUF_CTRL_DENAB 0x0000000000000002UL /* Diagnostic Mode Enable */ +#define SCHIZO_STRBUF_CTRL_ENAB 0x0000000000000001UL /* Streaming Buffer Enable */ + +/* IOMMU control register. */ +#define SCHIZO_IOMMU_CTRL_RESV 0xfffffffff9000000 /* Reserved */ +#define SCHIZO_IOMMU_CTRL_XLTESTAT 0x0000000006000000 /* Translation Error Status */ +#define SCHIZO_IOMMU_CTRL_XLTEERR 0x0000000001000000 /* Translation Error encountered */ +#define SCHIZO_IOMMU_CTRL_LCKEN 0x0000000000800000 /* Enable translation locking */ +#define SCHIZO_IOMMU_CTRL_LCKPTR 0x0000000000780000 /* Translation lock pointer */ +#define SCHIZO_IOMMU_CTRL_TSBSZ 0x0000000000070000 /* TSB Size */ +#define SCHIZO_IOMMU_TSBSZ_1K 0x0000000000000000 /* TSB Table 1024 8-byte entries */ +#define SCHIZO_IOMMU_TSBSZ_2K 0x0000000000010000 /* TSB Table 2048 8-byte entries */ +#define SCHIZO_IOMMU_TSBSZ_4K 0x0000000000020000 /* TSB Table 4096 8-byte entries */ +#define SCHIZO_IOMMU_TSBSZ_8K 0x0000000000030000 /* TSB Table 8192 8-byte entries */ +#define SCHIZO_IOMMU_TSBSZ_16K 0x0000000000040000 /* TSB Table 16k 8-byte entries */ +#define SCHIZO_IOMMU_TSBSZ_32K 0x0000000000050000 /* TSB Table 32k 8-byte entries */ +#define SCHIZO_IOMMU_TSBSZ_64K 0x0000000000060000 /* TSB Table 64k 8-byte entries */ +#define SCHIZO_IOMMU_TSBSZ_128K 0x0000000000070000 /* TSB Table 128k 8-byte entries */ +#define SCHIZO_IOMMU_CTRL_RESV2 0x000000000000fff8 /* Reserved */ +#define SCHIZO_IOMMU_CTRL_TBWSZ 0x0000000000000004 /* Assumed page size, 0=8k 1=64k */ +#define SCHIZO_IOMMU_CTRL_DENAB 0x0000000000000002 /* Diagnostic mode enable */ +#define SCHIZO_IOMMU_CTRL_ENAB 0x0000000000000001 /* IOMMU Enable */ + +/* Schizo config space address format is nearly identical to + * that of PSYCHO: + * + * 32 24 23 16 15 11 10 8 7 2 1 0 + * --------------------------------------------------------- + * |0 0 0 0 0 0 0 0 0| bus | device | function | reg | 0 0 | + * --------------------------------------------------------- + */ +#define SCHIZO_CONFIG_BASE(PBM) ((PBM)->config_space) +#define SCHIZO_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 16) | \ + ((unsigned long)(DEVFN) << 8) | \ + ((unsigned long)(REG))) + +static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned int devfn, + int where) +{ + if (!pbm) + return NULL; + return (void *) + (SCHIZO_CONFIG_BASE(pbm) | + SCHIZO_CONFIG_ENCODE(bus, devfn, where)); +} + +/* 4 slots on pbm A, and 6 slots on pbm B. In both cases + * slot 0 is the SCHIZO host bridge itself. + */ +static int schizo_out_of_range(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned char devfn) +{ + return ((pbm->parent == 0) || + ((pbm == &pbm->parent->pbm_B) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 6) || + ((pbm == &pbm->parent->pbm_A) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 4)); +} + +/* SCHIZO PCI configuration space accessors. */ + static int schizo_read_byte(struct pci_dev *dev, int where, u8 *value) { - /* IMPLEMENT ME */ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + *value = 0xff; + addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (schizo_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + pci_config_read8(addr, value); + return PCIBIOS_SUCCESSFUL; } static int schizo_read_word(struct pci_dev *dev, int where, u16 *value) { - /* IMPLEMENT ME */ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + *value = 0xffff; + addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (schizo_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_read_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_read16(addr, value); + return PCIBIOS_SUCCESSFUL; } static int schizo_read_dword(struct pci_dev *dev, int where, u32 *value) { - /* IMPLEMENT ME */ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + *value = 0xffffffff; + addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (schizo_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_read_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + + pci_config_read32(addr, value); + return PCIBIOS_SUCCESSFUL; } static int schizo_write_byte(struct pci_dev *dev, int where, u8 value) { - /* IMPLEMENT ME */ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (schizo_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + pci_config_write8(addr, value); + return PCIBIOS_SUCCESSFUL; } static int schizo_write_word(struct pci_dev *dev, int where, u16 value) { - /* IMPLEMENT ME */ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (schizo_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_write_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write16(addr, value); + return PCIBIOS_SUCCESSFUL; } static int schizo_write_dword(struct pci_dev *dev, int where, u32 value) { - /* IMPLEMENT ME */ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (schizo_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_write_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write32(addr, value); + return PCIBIOS_SUCCESSFUL; } static struct pci_ops schizo_ops = { @@ -55,34 +261,1383 @@ schizo_write_dword }; -static void __init schizo_scan_bus(struct pci_controller_info *p) +/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the + * imap/iclr registers are per-PBM. + */ +#define SCHIZO_IMAP_BASE 0x1000UL +#define SCHIZO_ICLR_BASE 0x1400UL + +static unsigned long schizo_imap_offset(unsigned long ino) { - /* IMPLEMENT ME */ + return SCHIZO_IMAP_BASE + (ino * 8UL); } -static unsigned int __init schizo_irq_build(struct pci_controller_info *p, +static unsigned long schizo_iclr_offset(unsigned long ino) +{ + return SCHIZO_ICLR_BASE + (ino * 8UL); +} + +/* PCI SCHIZO INO number to Sparc PIL level. This table only matters for + * INOs which will not have an associated PCI device struct, ie. onboard + * EBUS devices and PCI controller internal error interrupts. + */ +static unsigned char schizo_pil_table[] = { +/*0x00*/0, 0, 0, 0, /* PCI slot 0 Int A, B, C, D */ +/*0x04*/0, 0, 0, 0, /* PCI slot 1 Int A, B, C, D */ +/*0x08*/0, 0, 0, 0, /* PCI slot 2 Int A, B, C, D */ +/*0x0c*/0, 0, 0, 0, /* PCI slot 3 Int A, B, C, D */ +/*0x10*/0, 0, 0, 0, /* PCI slot 4 Int A, B, C, D */ +/*0x14*/0, 0, 0, 0, /* PCI slot 5 Int A, B, C, D */ +/*0x18*/0, 0, 0, 0, /* PCI slot 6 Int A, B, C, D */ +/*0x1c*/8, /* Parallel */ +/*0x1d*/0, /* UNKNOWN */ +/*0x1e*/0, /* UNKNOWN */ +/*0x1f*/0, /* UNKNOWN */ +/*0x20*/13, /* Audio Record */ +/*0x21*/14, /* Audio Playback */ +/*0x22*/12, /* Serial */ +/*0x23*/2, /* EBUS I2C */ +/*0x24*/10, /* RTC Clock */ +/*0x25*/11, /* Floppy */ +/*0x26*/0, /* UNKNOWN */ +/*0x27*/0, /* UNKNOWN */ +/*0x28*/0, /* UNKNOWN */ +/*0x29*/0, /* UNKNOWN */ +/*0x2a*/10, /* UPA 1 */ +/*0x2b*/10, /* UPA 2 */ +/*0x2c*/0, /* UNKNOWN */ +/*0x2d*/0, /* UNKNOWN */ +/*0x2e*/0, /* UNKNOWN */ +/*0x2f*/0, /* UNKNOWN */ +/*0x30*/15, /* Uncorrectable ECC */ +/*0x31*/15, /* Correctable ECC */ +/*0x32*/15, /* PCI Bus A Error */ +/*0x33*/15, /* PCI Bus B Error */ +/*0x34*/15, /* Safari Bus Error */ +/*0x35*/0, /* Reserved */ +/*0x36*/0, /* Reserved */ +/*0x37*/0, /* Reserved */ +/*0x38*/0, /* Reserved for NewLink */ +/*0x39*/0, /* Reserved for NewLink */ +/*0x3a*/0, /* Reserved for NewLink */ +/*0x3b*/0, /* Reserved for NewLink */ +/*0x3c*/0, /* Reserved for NewLink */ +/*0x3d*/0, /* Reserved for NewLink */ +/*0x3e*/0, /* Reserved for NewLink */ +/*0x3f*/0, /* Reserved for NewLink */ +}; + +static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino) +{ + int ret; + + ret = schizo_pil_table[ino]; + if (ret == 0 && pdev == NULL) { + ret = 1; + } else if (ret == 0) { + switch ((pdev->class >> 16) & 0x0f) { + case PCI_BASE_CLASS_STORAGE: + ret = 4; + + case PCI_BASE_CLASS_NETWORK: + ret = 6; + + case PCI_BASE_CLASS_DISPLAY: + ret = 9; + + case PCI_BASE_CLASS_MULTIMEDIA: + case PCI_BASE_CLASS_MEMORY: + case PCI_BASE_CLASS_BRIDGE: + ret = 10; + + default: + ret = 1; + }; + } + + return ret; +} + +static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm, struct pci_dev *pdev, unsigned int ino) { - /* IMPLEMENT ME */ + struct pci_controller_info *p = pbm->parent; + struct ino_bucket *bucket; + unsigned long imap, iclr, pbm_off; + unsigned long imap_off, iclr_off; + int pil, inofixup = 0; + + if (pbm == &p->pbm_A) + pbm_off = SCHIZO_PBM_A_REGS_OFF; + else + pbm_off = SCHIZO_PBM_B_REGS_OFF; + + ino &= PCI_IRQ_INO; + imap_off = schizo_imap_offset(ino); + + /* Now build the IRQ bucket. */ + pil = schizo_ino_to_pil(pdev, ino); + imap = p->controller_regs + pbm_off + imap_off; + imap += 4; + + iclr_off = schizo_iclr_offset(ino); + iclr = p->controller_regs + pbm_off + iclr_off; + iclr += 4; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket->flags |= IBF_PCI; + + return __irq(bucket); +} + +/* SCHIZO error handling support. */ +enum schizo_error_type { + UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR +}; + +static spinlock_t stc_buf_lock = SPIN_LOCK_UNLOCKED; +static unsigned long stc_error_buf[128]; +static unsigned long stc_tag_buf[16]; +static unsigned long stc_line_buf[16]; + +#define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */ +#define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */ +#define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */ + +#define SCHIZO_STCERR_WRITE 0x2UL +#define SCHIZO_STCERR_READ 0x1UL + +#define SCHIZO_STCTAG_PPN 0x3fffffff00000000UL +#define SCHIZO_STCTAG_VPN 0x00000000ffffe000UL +#define SCHIZO_STCTAG_VALID 0x8000000000000000UL +#define SCHIZO_STCTAG_READ 0x4000000000000000UL + +#define SCHIZO_STCLINE_LINDX 0x0000000007800000UL +#define SCHIZO_STCLINE_SPTR 0x000000000007e000UL +#define SCHIZO_STCLINE_LADDR 0x0000000000001fc0UL +#define SCHIZO_STCLINE_EPTR 0x000000000000003fUL +#define SCHIZO_STCLINE_VALID 0x0000000000600000UL +#define SCHIZO_STCLINE_FOFN 0x0000000000180000UL + +static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, + enum schizo_error_type type) +{ + struct pci_controller_info *p = pbm->parent; + struct pci_strbuf *strbuf = &pbm->stc; + unsigned long regbase = p->controller_regs; + unsigned long err_base, tag_base, line_base; + u64 control; + char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B'); + int i; + + if (pbm == &p->pbm_A) + regbase += SCHIZO_PBM_A_REGS_OFF; + else + regbase += SCHIZO_PBM_B_REGS_OFF; + + err_base = regbase + SCHIZO_STC_ERR; + tag_base = regbase + SCHIZO_STC_TAG; + line_base = regbase + SCHIZO_STC_LINE; + + spin_lock(&stc_buf_lock); + + /* This is __REALLY__ dangerous. When we put the + * streaming buffer into diagnostic mode to probe + * it's tags and error status, we _must_ clear all + * of the line tag valid bits before re-enabling + * the streaming buffer. If any dirty data lives + * in the STC when we do this, we will end up + * invalidating it before it has a chance to reach + * main memory. + */ + control = schizo_read(strbuf->strbuf_control); + schizo_write(strbuf->strbuf_control, + (control | SCHIZO_STRBUF_CTRL_DENAB)); + for (i = 0; i < 128; i++) { + unsigned long val; + + val = schizo_read(err_base + (i * 8UL)); + schizo_write(err_base + (i * 8UL), 0UL); + stc_error_buf[i] = val; + } + for (i = 0; i < 16; i++) { + stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL)); + stc_line_buf[i] = schizo_read(line_base + (i * 8UL)); + schizo_write(tag_base + (i * 8UL), 0UL); + schizo_write(line_base + (i * 8UL), 0UL); + } + + /* OK, state is logged, exit diagnostic mode. */ + schizo_write(strbuf->strbuf_control, control); + + for (i = 0; i < 16; i++) { + int j, saw_error, first, last; + + saw_error = 0; + first = i * 8; + last = first + 8; + for (j = first; j < last; j++) { + unsigned long errval = stc_error_buf[j]; + if (errval != 0) { + saw_error++; + printk("SCHIZO%d: PBM-%c STC_ERR(%d)[wr(%d)rd(%d)]\n", + p->index, pbm_name, + j, + (errval & SCHIZO_STCERR_WRITE) ? 1 : 0, + (errval & SCHIZO_STCERR_READ) ? 1 : 0); + } + } + if (saw_error != 0) { + unsigned long tagval = stc_tag_buf[i]; + unsigned long lineval = stc_line_buf[i]; + printk("SCHIZO%d: PBM-%c STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n", + p->index, pbm_name, + i, + ((tagval & SCHIZO_STCTAG_PPN) >> 19UL), + (tagval & SCHIZO_STCTAG_VPN), + ((tagval & SCHIZO_STCTAG_VALID) ? 1 : 0), + ((tagval & SCHIZO_STCTAG_READ) ? 1 : 0)); + + /* XXX Should spit out per-bank error information... -DaveM */ + printk("SCHIZO%d: PBM-%c STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" + "V(%d)FOFN(%d)]\n", + p->index, pbm_name, + i, + ((lineval & SCHIZO_STCLINE_LINDX) >> 23UL), + ((lineval & SCHIZO_STCLINE_SPTR) >> 13UL), + ((lineval & SCHIZO_STCLINE_LADDR) >> 6UL), + ((lineval & SCHIZO_STCLINE_EPTR) >> 0UL), + ((lineval & SCHIZO_STCLINE_VALID) ? 1 : 0), + ((lineval & SCHIZO_STCLINE_FOFN) ? 1 : 0)); + } + } + + spin_unlock(&stc_buf_lock); +} + +/* IOMMU is per-PBM in Schizo, so interrogate both for anonymous + * controller level errors. + */ + +#define SCHIZO_IOMMU_TAG 0xa580UL +#define SCHIZO_IOMMU_DATA 0xa600UL + +#define SCHIZO_IOMMU_TAG_CTXT 0x0000001ffe000000UL +#define SCHIZO_IOMMU_TAG_ERRSTS 0x0000000001800000UL +#define SCHIZO_IOMMU_TAG_ERR 0x0000000000400000UL +#define SCHIZO_IOMMU_TAG_WRITE 0x0000000000200000UL +#define SCHIZO_IOMMU_TAG_STREAM 0x0000000000100000UL +#define SCHIZO_IOMMU_TAG_SIZE 0x0000000000080000UL +#define SCHIZO_IOMMU_TAG_VPAGE 0x000000000007ffffUL + +#define SCHIZO_IOMMU_DATA_VALID 0x0000000100000000UL +#define SCHIZO_IOMMU_DATA_CACHE 0x0000000040000000UL +#define SCHIZO_IOMMU_DATA_PPAGE 0x000000003fffffffUL + +static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, + enum schizo_error_type type) +{ + struct pci_controller_info *p = pbm->parent; + struct pci_iommu *iommu = pbm->iommu; + unsigned long iommu_tag[16]; + unsigned long iommu_data[16]; + unsigned long flags; + u64 control; + char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B'); + int i; + + spin_lock_irqsave(&iommu->lock, flags); + control = schizo_read(iommu->iommu_control); + if (control & SCHIZO_IOMMU_CTRL_XLTEERR) { + unsigned long base; + char *type_string; + + /* Clear the error encountered bit. */ + control &= ~SCHIZO_IOMMU_CTRL_XLTEERR; + schizo_write(iommu->iommu_control, control); + + switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) { + case 0: + type_string = "Protection Error"; + break; + case 1: + type_string = "Invalid Error"; + break; + case 2: + type_string = "TimeOut Error"; + break; + case 3: + default: + type_string = "ECC Error"; + break; + }; + printk("SCHIZO%d: PBM-%c IOMMU Error, type[%s]\n", + p->index, pbm_name, type_string); + + /* Put the IOMMU into diagnostic mode and probe + * it's TLB for entries with error status. + * + * It is very possible for another DVMA to occur + * while we do this probe, and corrupt the system + * further. But we are so screwed at this point + * that we are likely to crash hard anyways, so + * get as much diagnostic information to the + * console as we can. + */ + schizo_write(iommu->iommu_control, + control | SCHIZO_IOMMU_CTRL_DENAB); + + base = p->controller_regs; + if (pbm == &p->pbm_A) + base += SCHIZO_PBM_A_REGS_OFF; + else + base += SCHIZO_PBM_B_REGS_OFF; + + for (i = 0; i < 16; i++) { + iommu_tag[i] = + schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL)); + iommu_data[i] = + schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL)); + + /* Now clear out the entry. */ + schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0); + schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0); + } + + /* Leave diagnostic mode. */ + schizo_write(iommu->iommu_control, control); + + for (i = 0; i < 16; i++) { + unsigned long tag, data; + + tag = iommu_tag[i]; + if (!(tag & SCHIZO_IOMMU_TAG_ERR)) + continue; + + data = iommu_data[i]; + switch((tag & SCHIZO_IOMMU_TAG_ERRSTS) >> 23UL) { + case 0: + type_string = "Protection Error"; + break; + case 1: + type_string = "Invalid Error"; + break; + case 2: + type_string = "TimeOut Error"; + break; + case 3: + default: + type_string = "ECC Error"; + break; + }; + printk("SCHIZO%d: PBM-%c IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) " + "sz(%dK) vpg(%08lx)]\n", + p->index, pbm_name, i, type_string, + (int)((tag & SCHIZO_IOMMU_TAG_CTXT) >> 25UL), + ((tag & SCHIZO_IOMMU_TAG_WRITE) ? 1 : 0), + ((tag & SCHIZO_IOMMU_TAG_STREAM) ? 1 : 0), + ((tag & SCHIZO_IOMMU_TAG_SIZE) ? 64 : 8), + (tag & SCHIZO_IOMMU_TAG_VPAGE) << PAGE_SHIFT); + printk("SCHIZO%d: PBM-%c IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", + p->index, pbm_name, i, + ((data & SCHIZO_IOMMU_DATA_VALID) ? 1 : 0), + ((data & SCHIZO_IOMMU_DATA_CACHE) ? 1 : 0), + (data & SCHIZO_IOMMU_DATA_PPAGE) << PAGE_SHIFT); + } + } + __schizo_check_stc_error_pbm(pbm, type); + spin_unlock_irqrestore(&iommu->lock, flags); +} + +static void schizo_check_iommu_error(struct pci_controller_info *p, + enum schizo_error_type type) +{ + schizo_check_iommu_error_pbm(&p->pbm_A, type); + schizo_check_iommu_error_pbm(&p->pbm_B, type); +} + +/* Uncorrectable ECC error status gathering. */ +#define SCHIZO_UE_AFSR 0x10030UL +#define SCHIZO_UE_AFAR 0x10038UL + +#define SCHIZO_UEAFSR_PPIO 0x8000000000000000UL +#define SCHIZO_UEAFSR_PDRD 0x4000000000000000UL +#define SCHIZO_UEAFSR_PDWR 0x2000000000000000UL +#define SCHIZO_UEAFSR_SPIO 0x1000000000000000UL +#define SCHIZO_UEAFSR_SDMA 0x0800000000000000UL +#define SCHIZO_UEAFSR_ERRPNDG 0x0300000000000000UL +#define SCHIZO_UEAFSR_BMSK 0x000003ff00000000UL +#define SCHIZO_UEAFSR_QOFF 0x00000000c0000000UL +#define SCHIZO_UEAFSR_AID 0x000000001f000000UL +#define SCHIZO_UEAFSR_PARTIAL 0x0000000000800000UL +#define SCHIZO_UEAFSR_OWNEDIN 0x0000000000400000UL +#define SCHIZO_UEAFSR_MTAGSYND 0x00000000000f0000UL +#define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL +#define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffUL + +static void schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + SCHIZO_UE_AFSR; + unsigned long afar_reg = p->controller_regs + SCHIZO_UE_AFAR; + unsigned long afsr, afar, error_bits; + int reported, limit; + + /* Latch uncorrectable error status. */ + afar = schizo_read(afar_reg); + + /* If either of the error pending bits are set in the + * AFSR, the error status is being actively updated by + * the hardware and we must re-read to get a clean value. + */ + limit = 1000; + do { + afsr = schizo_read(afsr_reg); + } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit); + + /* Clear the primary/secondary error status bits. */ + error_bits = afsr & + (SCHIZO_UEAFSR_PPIO | SCHIZO_UEAFSR_PDRD | SCHIZO_UEAFSR_PDWR | + SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA); + schizo_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SCHIZO%d: Uncorrectable Error, primary error type[%s]\n", + p->index, + (((error_bits & SCHIZO_UEAFSR_PPIO) ? + "PIO" : + ((error_bits & SCHIZO_UEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & SCHIZO_UEAFSR_PDWR) ? + "DMA Write" : "???"))))); + printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", + p->index, + (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL, + (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL, + (afsr & SCHIZO_UEAFSR_AID) >> 24UL); + printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", + p->index, + (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0, + (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0, + (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL, + (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL, + (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL); + printk("SCHIZO%d: UE AFAR [%016lx]\n", p->index, afar); + printk("SCHIZO%d: UE Secondary errors [", p->index); + reported = 0; + if (afsr & SCHIZO_UEAFSR_SPIO) { + reported++; + printk("(PIO)"); + } + if (afsr & SCHIZO_UEAFSR_SDMA) { + reported++; + printk("(DMA)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* Interrogate IOMMU for error status. */ + schizo_check_iommu_error(p, UE_ERR); +} + +#define SCHIZO_CE_AFSR 0x10040UL +#define SCHIZO_CE_AFAR 0x10048UL + +#define SCHIZO_CEAFSR_PPIO 0x8000000000000000UL +#define SCHIZO_CEAFSR_PDRD 0x4000000000000000UL +#define SCHIZO_CEAFSR_PDWR 0x2000000000000000UL +#define SCHIZO_CEAFSR_SPIO 0x1000000000000000UL +#define SCHIZO_CEAFSR_SDMA 0x0800000000000000UL +#define SCHIZO_CEAFSR_ERRPNDG 0x0300000000000000UL +#define SCHIZO_CEAFSR_BMSK 0x000003ff00000000UL +#define SCHIZO_CEAFSR_QOFF 0x00000000c0000000UL +#define SCHIZO_CEAFSR_AID 0x000000001f000000UL +#define SCHIZO_CEAFSR_PARTIAL 0x0000000000800000UL +#define SCHIZO_CEAFSR_OWNEDIN 0x0000000000400000UL +#define SCHIZO_CEAFSR_MTAGSYND 0x00000000000f0000UL +#define SCHIZO_CEAFSR_MTAG 0x000000000000e000UL +#define SCHIZO_CEAFSR_ECCSYND 0x00000000000001ffUL + +static void schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + SCHIZO_CE_AFSR; + unsigned long afar_reg = p->controller_regs + SCHIZO_CE_AFAR; + unsigned long afsr, afar, error_bits; + int reported, limit; + + /* Latch error status. */ + afar = schizo_read(afar_reg); + + /* If either of the error pending bits are set in the + * AFSR, the error status is being actively updated by + * the hardware and we must re-read to get a clean value. + */ + limit = 1000; + do { + afsr = schizo_read(afsr_reg); + } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SCHIZO_CEAFSR_PPIO | SCHIZO_CEAFSR_PDRD | SCHIZO_CEAFSR_PDWR | + SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA); + schizo_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SCHIZO%d: Correctable Error, primary error type[%s]\n", + p->index, + (((error_bits & SCHIZO_CEAFSR_PPIO) ? + "PIO" : + ((error_bits & SCHIZO_CEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & SCHIZO_CEAFSR_PDWR) ? + "DMA Write" : "???"))))); + + /* XXX Use syndrome and afar to print out module string just like + * XXX UDB CE trap handler does... -DaveM + */ + printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", + p->index, + (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL, + (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL, + (afsr & SCHIZO_UEAFSR_AID) >> 24UL); + printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", + p->index, + (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0, + (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0, + (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL, + (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL, + (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL); + printk("SCHIZO%d: CE AFAR [%016lx]\n", p->index, afar); + printk("SCHIZO%d: CE Secondary errors [", p->index); + reported = 0; + if (afsr & SCHIZO_CEAFSR_SPIO) { + reported++; + printk("(PIO)"); + } + if (afsr & SCHIZO_CEAFSR_SDMA) { + reported++; + printk("(DMA)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); +} + +#define SCHIZO_PCI_AFSR 0x2010UL +#define SCHIZO_PCI_AFAR 0x2018UL + +#define SCHIZO_PCIAFSR_PMA 0x8000000000000000UL +#define SCHIZO_PCIAFSR_PTA 0x4000000000000000UL +#define SCHIZO_PCIAFSR_PRTRY 0x2000000000000000UL +#define SCHIZO_PCIAFSR_PPERR 0x1000000000000000UL +#define SCHIZO_PCIAFSR_PTTO 0x0800000000000000UL +#define SCHIZO_PCIAFSR_PUNUS 0x0400000000000000UL +#define SCHIZO_PCIAFSR_SMA 0x0200000000000000UL +#define SCHIZO_PCIAFSR_STA 0x0100000000000000UL +#define SCHIZO_PCIAFSR_SRTRY 0x0080000000000000UL +#define SCHIZO_PCIAFSR_SPERR 0x0040000000000000UL +#define SCHIZO_PCIAFSR_STTO 0x0020000000000000UL +#define SCHIZO_PCIAFSR_SUNUS 0x0010000000000000UL +#define SCHIZO_PCIAFSR_BMSK 0x000003ff00000000UL +#define SCHIZO_PCIAFSR_BLK 0x0000000080000000UL +#define SCHIZO_PCIAFSR_CFG 0x0000000040000000UL +#define SCHIZO_PCIAFSR_MEM 0x0000000020000000UL +#define SCHIZO_PCIAFSR_IO 0x0000000010000000UL + +static void schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_pbm_info *pbm = dev_id; + struct pci_controller_info *p = pbm->parent; + unsigned long afsr_reg, afar_reg, base; + unsigned long afsr, afar, error_bits; + int reported; + char pbm_name; + + base = p->controller_regs; + if (pbm == &pbm->parent->pbm_A) { + base += SCHIZO_PBM_A_REGS_OFF; + pbm_name = 'A'; + } else { + base += SCHIZO_PBM_B_REGS_OFF; + pbm_name = 'B'; + } + + afsr_reg = base + SCHIZO_PCI_AFSR; + afar_reg = base + SCHIZO_PCI_AFAR; + + /* Latch error status. */ + afar = schizo_read(afar_reg); + afsr = schizo_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | + SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | + SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | + SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | + SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | + SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS); + schizo_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SCHIZO%d: PBM-%c PCI Error, primary error type[%s]\n", + p->index, pbm_name, + (((error_bits & SCHIZO_PCIAFSR_PMA) ? + "Master Abort" : + ((error_bits & SCHIZO_PCIAFSR_PTA) ? + "Target Abort" : + ((error_bits & SCHIZO_PCIAFSR_PRTRY) ? + "Excessive Retries" : + ((error_bits & SCHIZO_PCIAFSR_PPERR) ? + "Parity Error" : + ((error_bits & SCHIZO_PCIAFSR_PTTO) ? + "Timeout" : + ((error_bits & SCHIZO_PCIAFSR_PUNUS) ? + "Bus Unusable" : "???")))))))); + printk("SCHIZO%d: PBM-%c bytemask[%04lx] was_block(%d) space(%s)\n", + p->index, pbm_name, + (afsr & SCHIZO_PCIAFSR_BMSK) >> 32UL, + (afsr & SCHIZO_PCIAFSR_BLK) ? 1 : 0, + ((afsr & SCHIZO_PCIAFSR_CFG) ? + "Config" : + ((afsr & SCHIZO_PCIAFSR_MEM) ? + "Memory" : + ((afsr & SCHIZO_PCIAFSR_IO) ? + "I/O" : "???")))); + printk("SCHIZO%d: PBM-%c PCI AFAR [%016lx]\n", + p->index, pbm_name, afar); + printk("SCHIZO%d: PBM-%c PCI Secondary errors [", + p->index, pbm_name); + reported = 0; + if (afsr & SCHIZO_PCIAFSR_SMA) { + reported++; + printk("(Master Abort)"); + } + if (afsr & SCHIZO_PCIAFSR_STA) { + reported++; + printk("(Target Abort)"); + } + if (afsr & SCHIZO_PCIAFSR_SRTRY) { + reported++; + printk("(Excessive Retries)"); + } + if (afsr & SCHIZO_PCIAFSR_SPERR) { + reported++; + printk("(Parity Error)"); + } + if (afsr & SCHIZO_PCIAFSR_STTO) { + reported++; + printk("(Timeout)"); + } + if (afsr & SCHIZO_PCIAFSR_SUNUS) { + reported++; + printk("(Bus Unusable)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* For the error types shown, scan PBM's PCI bus for devices + * which have logged that error type. + */ + + /* If we see a Target Abort, this could be the result of an + * IOMMU translation error of some sort. It is extremely + * useful to log this information as usually it indicates + * a bug in the IOMMU support code or a PCI device driver. + */ + if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) { + schizo_check_iommu_error(p, PCI_ERR); + pci_scan_for_target_abort(p, pbm, pbm->pci_bus); + } + if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA)) + pci_scan_for_master_abort(p, pbm, pbm->pci_bus); + + /* For excessive retries, PSYCHO/PBM will abort the device + * and there is no way to specifically check for excessive + * retries in the config space status registers. So what + * we hope is that we'll catch it via the master/target + * abort events. + */ + + if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR)) + pci_scan_for_parity_error(p, pbm, pbm->pci_bus); +} + +#define SCHIZO_SAFARI_ERRLOG 0x10018UL + +#define SAFARI_ERRLOG_ERROUT 0x8000000000000000UL + +#define SAFARI_ERROR_BADCMD 0x4000000000000000UL +#define SAFARI_ERROR_SSMDIS 0x2000000000000000UL +#define SAFARI_ERROR_BADMA 0x1000000000000000UL +#define SAFARI_ERROR_BADMB 0x0800000000000000UL +#define SAFARI_ERROR_BADMC 0x0400000000000000UL +#define SAFARI_ERROR_CPU1PS 0x0000000000002000UL +#define SAFARI_ERROR_CPU1PB 0x0000000000001000UL +#define SAFARI_ERROR_CPU0PS 0x0000000000000800UL +#define SAFARI_ERROR_CPU0PB 0x0000000000000400UL +#define SAFARI_ERROR_CIQTO 0x0000000000000200UL +#define SAFARI_ERROR_LPQTO 0x0000000000000100UL +#define SAFARI_ERROR_SFPQTO 0x0000000000000080UL +#define SAFARI_ERROR_UFPQTO 0x0000000000000040UL +#define SAFARI_ERROR_APERR 0x0000000000000020UL +#define SAFARI_ERROR_UNMAP 0x0000000000000010UL +#define SAFARI_ERROR_BUSERR 0x0000000000000004UL +#define SAFARI_ERROR_TIMEOUT 0x0000000000000002UL +#define SAFARI_ERROR_ILL 0x0000000000000001UL + +/* We only expect UNMAP errors here. The rest of the Safari errors + * are marked fatal and thus cause a system reset. + */ +static void schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + u64 errlog; + + errlog = schizo_read(p->controller_regs + SCHIZO_SAFARI_ERRLOG); + schizo_write(p->controller_regs + SCHIZO_SAFARI_ERRLOG, + errlog & ~(SAFARI_ERRLOG_ERROUT)); + + if (!(errlog & SAFARI_ERROR_UNMAP)) { + printk("SCHIZO%d: Unexpected Safari error interrupt, errlog[%016lx]\n", + p->index, errlog); + return; + } + + printk("SCHIZO%d: Safari interrupt, UNMAPPED error, interrogating IOMMUs.\n", + p->index); + schizo_check_iommu_error(p, SAFARI_ERR); +} + +/* Nearly identical to PSYCHO equivalents... */ +#define SCHIZO_ECC_CTRL 0x10020UL +#define SCHIZO_ECCCTRL_EE 0x8000000000000000 /* Enable ECC Checking */ +#define SCHIZO_ECCCTRL_UE 0x4000000000000000 /* Enable UE Interrupts */ +#define SCHIZO_ECCCTRL_CE 0x2000000000000000 /* Enable CE INterrupts */ + +#define SCHIZO_SAFARI_ERRCTRL 0x10008UL +#define SCHIZO_SAFERRCTRL_EN 0x8000000000000000UL +#define SCHIZO_SAFARI_IRQCTRL 0x10010UL +#define SCHIZO_SAFIRQCTRL_EN 0x8000000000000000UL + +#define SCHIZO_UE_INO 0x30 /* Uncorrectable ECC error */ +#define SCHIZO_CE_INO 0x31 /* Correctable ECC error */ +#define SCHIZO_PCIERR_A_INO 0x32 /* PBM A PCI bus error */ +#define SCHIZO_PCIERR_B_INO 0x33 /* PBM B PCI bus error */ +#define SCHIZO_SERR_INO 0x34 /* Safari interface error */ + +#define SCHIZO_PCIA_CTRL (SCHIZO_PBM_A_REGS_OFF + 0x2000UL) +#define SCHIZO_PCIB_CTRL (SCHIZO_PBM_B_REGS_OFF + 0x2000UL) +#define SCHIZO_PCICTRL_SBH_ERR (1UL << 35UL) +#define SCHIZO_PCICTRL_SERR (1UL << 34UL) +#define SCHIZO_PCICTRL_SBH_INT (1UL << 18UL) +#define SCHIZO_PCICTRL_EEN (1UL << 17UL) + +/* XXX It is not entirely clear if I need to enable the PCI controller interrupts + * XXX in both PBMs, the documentation is very vague about this point. For now + * XXX I'll just enable it on PBM A but this needs to be verified! -DaveM + */ +static void __init schizo_register_error_handlers(struct pci_controller_info *p) +{ + struct pci_pbm_info *pbm = &p->pbm_A; /* XXX verify me XXX */ + unsigned long base = p->controller_regs; + unsigned int irq, portid = p->portid; + u64 tmp; + + /* Build IRQs and register handlers. */ + irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_UE_INO); + if (request_irq(irq, schizo_ue_intr, + SA_SHIRQ, "SCHIZO UE", p) < 0) { + prom_printf("SCHIZO%d: Cannot register UE interrupt.\n", + p->index); + prom_halt(); + } + + irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_CE_INO); + if (request_irq(irq, schizo_ce_intr, + SA_SHIRQ, "SCHIZO CE", p) < 0) { + prom_printf("SCHIZO%d: Cannot register CE interrupt.\n", + p->index); + prom_halt(); + } + + irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_PCIERR_A_INO); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_A) < 0) { + prom_printf("SCHIZO%d(PBMA): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + + irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_B) < 0) { + prom_printf("SCHIZO%d(PBMB): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + + irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_SERR_INO); + if (request_irq(irq, schizo_safarierr_intr, + SA_SHIRQ, "SCHIZO SERR", p) < 0) { + prom_printf("SCHIZO%d(PBMB): Cannot register SafariERR interrupt.\n", + p->index); + prom_halt(); + } + + /* Enable UE and CE interrupts for controller. */ + schizo_write(base + SCHIZO_ECC_CTRL, + (SCHIZO_ECCCTRL_EE | + SCHIZO_ECCCTRL_UE | + SCHIZO_ECCCTRL_CE)); + + /* Enable PCI Error interrupts and clear error + * bits for each PBM. + * + * XXX More error bits should be cleared, this is + * XXX just the stuff which is identical on Psycho. -DaveM + */ + tmp = schizo_read(base + SCHIZO_PCIA_CTRL); + tmp |= (SCHIZO_PCICTRL_SBH_ERR | + SCHIZO_PCICTRL_SERR | + SCHIZO_PCICTRL_SBH_INT | + SCHIZO_PCICTRL_EEN); + schizo_write(base + SCHIZO_PCIA_CTRL, tmp); + + tmp = schizo_read(base + SCHIZO_PCIB_CTRL); + tmp |= (SCHIZO_PCICTRL_SBH_ERR | + SCHIZO_PCICTRL_SERR | + SCHIZO_PCICTRL_SBH_INT | + SCHIZO_PCICTRL_EEN); + schizo_write(base + SCHIZO_PCIB_CTRL, tmp); + + /* Make all Safari error conditions fatal except unmapped errors + * which we make generate interrupts. + */ + schizo_write(base + SCHIZO_SAFARI_ERRCTRL, + (SCHIZO_SAFERRCTRL_EN | + (SAFARI_ERROR_BADCMD | SAFARI_ERROR_SSMDIS | + SAFARI_ERROR_BADMA | SAFARI_ERROR_BADMB | + SAFARI_ERROR_BADMC | SAFARI_ERROR_CPU1PS | + SAFARI_ERROR_CPU1PB | SAFARI_ERROR_CPU0PS | + SAFARI_ERROR_CPU0PB | SAFARI_ERROR_CIQTO | + SAFARI_ERROR_LPQTO | SAFARI_ERROR_SFPQTO | + SAFARI_ERROR_UFPQTO | SAFARI_ERROR_APERR | + SAFARI_ERROR_BUSERR | SAFARI_ERROR_TIMEOUT | + SAFARI_ERROR_ILL))); + + schizo_write(base + SCHIZO_SAFARI_IRQCTRL, + (SCHIZO_SAFIRQCTRL_EN | (SAFARI_ERROR_UNMAP))); +} + +/* We have to do the config space accesses by hand, thus... */ +#define PBM_BRIDGE_BUS 0x40 +#define PBM_BRIDGE_SUBORDINATE 0x41 +static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno) +{ + u8 *addr, busno; + int nbus; + + busno = pci_highest_busnum; + nbus = pbm->pci_last_busno - pbm->pci_first_busno; + + addr = schizo_pci_config_mkaddr(pbm, orig_busno, + 0, PBM_BRIDGE_BUS); + pci_config_write8(addr, busno); + addr = schizo_pci_config_mkaddr(pbm, busno, + 0, PBM_BRIDGE_SUBORDINATE); + pci_config_write8(addr, busno + nbus); + + pbm->pci_first_busno = busno; + pbm->pci_last_busno = busno + nbus; + pci_highest_busnum = busno + nbus + 1; + + do { + pci_bus2pbm[busno++] = pbm; + } while (nbus--); +} + +/* We have to do the config space accesses by hand here since + * the pci_bus2pbm array is not ready yet. + */ +static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm, + u8 busno) +{ + u32 devfn, l, class; + u8 hdr_type; + int is_multi = 0; + + for(devfn = 0; devfn < 0xff; ++devfn) { + u32 *dwaddr; + u8 *baddr; + + if (PCI_FUNC(devfn) != 0 && is_multi == 0) + continue; + + /* Anything there? */ + dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID); + l = 0xffffffff; + pci_config_read32(dwaddr, &l); + if (l == 0xffffffff || l == 0x00000000 || + l == 0x0000ffff || l == 0xffff0000) { + is_multi = 0; + continue; + } + + baddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE); + pci_config_read8(baddr, &hdr_type); + if (PCI_FUNC(devfn) == 0) + is_multi = hdr_type & 0x80; + + dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION); + class = 0xffffffff; + pci_config_read32(dwaddr, &class); + if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { + u32 buses = 0xffffffff; + + dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, + PCI_PRIMARY_BUS); + pci_config_read32(dwaddr, &buses); + pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff); + buses &= 0xff000000; + pci_config_write32(dwaddr, buses); + } + } +} + +static void __init pbm_bridge_reconfigure(struct pci_controller_info *p) +{ + struct pci_pbm_info *pbm; + u8 *addr; + + /* Clear out primary/secondary/subordinate bus numbers on + * all PCI-to-PCI bridges under each PBM. The generic bus + * probing will fix them up. + */ + pbm_pci_bridge_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); + pbm_pci_bridge_renumber(&p->pbm_A, p->pbm_A.pci_first_busno); + + /* Move PBM A out of the way. */ + pbm = &p->pbm_A; + addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno, + 0, PBM_BRIDGE_BUS); + pci_config_write8(addr, 0xff); + addr = schizo_pci_config_mkaddr(pbm, 0xff, + 0, PBM_BRIDGE_SUBORDINATE); + pci_config_write8(addr, 0xff); + + /* Now we can safely renumber both PBMs. */ + pbm_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); + pbm_renumber(&p->pbm_A, 0xff); +} + +static void __init pbm_config_busmastering(struct pci_pbm_info *pbm) +{ + u8 *addr; + + /* Set cache-line size to 64 bytes, this is actually + * a nop but I do it for completeness. + */ + addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno, + 0, PCI_CACHE_LINE_SIZE); + pci_config_write8(addr, 64 / sizeof(u32)); + + /* Set PBM latency timer to 64 PCI clocks. */ + addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno, + 0, PCI_LATENCY_TIMER); + pci_config_write8(addr, 64); +} + +static void __init pbm_scan_bus(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, + p->pci_ops, + pbm); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbm->pci_bus); + pci_assign_unassigned(pbm, pbm->pci_bus); + pci_fixup_irq(pbm, pbm->pci_bus); + pci_determine_66mhz_disposition(pbm, pbm->pci_bus); + pci_setup_busmastering(pbm, pbm->pci_bus); +} + +static void __init schizo_scan_bus(struct pci_controller_info *p) +{ + pbm_bridge_reconfigure(p); + pbm_config_busmastering(&p->pbm_B); + p->pbm_B.is_66mhz_capable = 0; + pbm_config_busmastering(&p->pbm_A); + p->pbm_A.is_66mhz_capable = 1; + pbm_scan_bus(p, &p->pbm_B); + pbm_scan_bus(p, &p->pbm_A); + + /* After the PCI bus scan is complete, we can register + * the error interrupt handlers. + */ + schizo_register_error_handlers(p); } static void __init schizo_base_address_update(struct pci_dev *pdev, int resource) { - /* IMPLEMENT ME */ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct resource *res, *root; + u32 reg; + int where, size, is_64bit; + + res = &pdev->resource[resource]; + where = PCI_BASE_ADDRESS_0 + (resource * 4); + + is_64bit = 0; + if (res->flags & IORESOURCE_IO) + root = &pbm->io_space; + else { + root = &pbm->mem_space; + if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) + == PCI_BASE_ADDRESS_MEM_TYPE_64) + is_64bit = 1; + } + + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - root->start)) & ~size)); + pci_write_config_dword(pdev, where, reg); + + /* This knows that the upper 32-bits of the address + * must be zero. Our PCI common layer enforces this. + */ + if (is_64bit) + pci_write_config_dword(pdev, where + 4, 0); } static void __init schizo_resource_adjust(struct pci_dev *pdev, struct resource *res, struct resource *root) { - /* IMPLEMENT ME */ + res->start += root->start; + res->end += root->start; +} + +/* Interrogate Safari match/mask registers to figure out where + * PCI MEM, I/O, and Config space are for this PCI bus module. + */ + +#define SCHIZO_PCI_A_MEM_MATCH 0x00040UL +#define SCHIZO_PCI_A_MEM_MASK 0x00048UL +#define SCHIZO_PCI_A_IO_MATCH 0x00050UL +#define SCHIZO_PCI_A_IO_MASK 0x00058UL +#define SCHIZO_PCI_B_MEM_MATCH 0x00060UL +#define SCHIZO_PCI_B_MEM_MASK 0x00068UL +#define SCHIZO_PCI_B_IO_MATCH 0x00070UL +#define SCHIZO_PCI_B_IO_MASK 0x00078UL + +/* VAL must be non-zero. */ +static unsigned long strip_to_lowest_bit_set(unsigned long val) +{ + unsigned long tmp; + + tmp = 1UL; + while (!(tmp & val)) + tmp <<= 1UL; + + return tmp; +} + +static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm, + int is_pbm_a, unsigned long reg_base) +{ + u64 mem_match, mem_mask; + u64 io_match; + u64 long a, b; + + if (is_pbm_a) { + mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH; + io_match = reg_base + SCHIZO_PCI_A_IO_MATCH; + } else { + mem_match = reg_base + SCHIZO_PCI_B_MEM_MATCH; + io_match = reg_base + SCHIZO_PCI_B_IO_MATCH; + } + mem_mask = mem_match + 0x8UL; + + a = schizo_read(mem_match) & ~0x8000000000000000UL; + b = strip_to_lowest_bit_set(schizo_read(mem_mask)); + + /* It should be 2GB in size. */ + pbm->mem_space.start = a; + pbm->mem_space.end = a + (b - 1UL); + pbm->mem_space.flags = IORESOURCE_MEM; + + /* This 32MB area is divided into two pieces. The first + * 16MB is Config space, the next 16MB is I/O space. + */ + + a = schizo_read(io_match) & ~0x8000000000000000UL; + pbm->config_space = a; + printk("SCHIZO PBM%c: Local PCI config space at %016lx\n", + (is_pbm_a ? 'A' : 'B'), pbm->config_space); + + a += (16UL * 1024UL * 1024UL); + pbm->io_space.start = a; + pbm->io_space.end = a + ((16UL * 1024UL * 1024UL) - 1UL); + pbm->io_space.flags = IORESOURCE_IO; +} + +static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + char *name = pbm->name; + + sprintf(name, "SCHIZO%d PBM%c", + p->index, + (pbm == &p->pbm_A ? 'A' : 'B')); + pbm->io_space.name = pbm->mem_space.name = name; + + request_resource(&ioport_resource, &pbm->io_space); + request_resource(&iomem_resource, &pbm->mem_space); +} + +#define SCHIZO_STRBUF_CONTROL_A (SCHIZO_PBM_A_REGS_OFF + 0x02800UL) +#define SCHIZO_STRBUF_FLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x02808UL) +#define SCHIZO_STRBUF_FSYNC_A (SCHIZO_PBM_A_REGS_OFF + 0x02810UL) +#define SCHIZO_STRBUF_CTXFLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x02818UL) +#define SCHIZO_STRBUF_CTXMATCH_A (SCHIZO_PBM_A_REGS_OFF + 0x10000UL) + +#define SCHIZO_STRBUF_CONTROL_B (SCHIZO_PBM_B_REGS_OFF + 0x02800UL) +#define SCHIZO_STRBUF_FLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x02808UL) +#define SCHIZO_STRBUF_FSYNC_B (SCHIZO_PBM_B_REGS_OFF + 0x02810UL) +#define SCHIZO_STRBUF_CTXFLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x02818UL) +#define SCHIZO_STRBUF_CTXMATCH_B (SCHIZO_PBM_B_REGS_OFF + 0x10000UL) + +static void schizo_pbm_strbuf_init(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + int is_pbm_a) +{ + unsigned long base = p->controller_regs; + u64 control; + + /* SCHIZO has context flushing. */ + if (is_pbm_a) { + pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL_A; + pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH_A; + pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC_A; + pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH_A; + pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH_A; + } else { + pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL_B; + pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH_B; + pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC_B; + pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH_B; + pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH_B; + } + + pbm->stc.strbuf_flushflag = (volatile unsigned long *) + ((((unsigned long)&pbm->stc.__flushflag_buf[0]) + + 63UL) + & ~63UL); + pbm->stc.strbuf_flushflag_pa = (unsigned long) + __pa(pbm->stc.strbuf_flushflag); + + /* Turn off LRU locking and diag mode, enable the + * streaming buffer and leave the rerun-disable + * setting however OBP set it. + */ + control = schizo_read(pbm->stc.strbuf_control); + control &= ~(SCHIZO_STRBUF_CTRL_LPTR | + SCHIZO_STRBUF_CTRL_LENAB | + SCHIZO_STRBUF_CTRL_DENAB); + control |= SCHIZO_STRBUF_CTRL_ENAB; + schizo_write(pbm->stc.strbuf_control, control); + + pbm->stc.strbuf_enabled = 1; +} + +#define SCHIZO_IOMMU_CONTROL_A (SCHIZO_PBM_A_REGS_OFF + 0x00200UL) +#define SCHIZO_IOMMU_TSBBASE_A (SCHIZO_PBM_A_REGS_OFF + 0x00208UL) +#define SCHIZO_IOMMU_FLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x00210UL) +#define SCHIZO_IOMMU_CTXFLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x00218UL) +#define SCHIZO_IOMMU_TAG_A (SCHIZO_PBM_A_REGS_OFF + 0x0a580UL) +#define SCHIZO_IOMMU_DATA_A (SCHIZO_PBM_A_REGS_OFF + 0x0a600UL) +#define SCHIZO_IOMMU_CONTROL_B (SCHIZO_PBM_B_REGS_OFF + 0x00200UL) +#define SCHIZO_IOMMU_TSBBASE_B (SCHIZO_PBM_B_REGS_OFF + 0x00208UL) +#define SCHIZO_IOMMU_FLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x00210UL) +#define SCHIZO_IOMMU_CTXFLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x00218UL) +#define SCHIZO_IOMMU_TAG_B (SCHIZO_PBM_B_REGS_OFF + 0x0a580UL) +#define SCHIZO_IOMMU_DATA_B (SCHIZO_PBM_B_REGS_OFF + 0x0a600UL) + +static void schizo_pbm_iommu_init(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + int is_pbm_a) +{ + struct pci_iommu *iommu = pbm->iommu; + unsigned long tsbbase, i, tagbase, database; + u64 control; + + /* Setup initial software IOMMU state. */ + spin_lock_init(&iommu->lock); + iommu->iommu_cur_ctx = 0; + + /* Register addresses, SCHIZO has iommu ctx flushing. */ + if (is_pbm_a) { + iommu->iommu_control = p->controller_regs + SCHIZO_IOMMU_CONTROL_A; + iommu->iommu_tsbbase = p->controller_regs + SCHIZO_IOMMU_TSBBASE_A; + iommu->iommu_flush = p->controller_regs + SCHIZO_IOMMU_FLUSH_A; + iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_A; + } else { + iommu->iommu_control = p->controller_regs + SCHIZO_IOMMU_CONTROL_B; + iommu->iommu_tsbbase = p->controller_regs + SCHIZO_IOMMU_TSBBASE_B; + iommu->iommu_flush = p->controller_regs + SCHIZO_IOMMU_FLUSH_B; + iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_B; + } + + /* We use the main control/status register of SCHIZO as the write + * completion register. + */ + iommu->write_complete_reg = p->controller_regs + 0x10000UL; + + /* + * Invalidate TLB Entries. + */ + control = schizo_read(iommu->iommu_control); + control |= SCHIZO_IOMMU_CTRL_DENAB; + schizo_write(iommu->iommu_control, control); + + if (is_pbm_a) + tagbase = SCHIZO_IOMMU_TAG_A, database = SCHIZO_IOMMU_DATA_A; + else + tagbase = SCHIZO_IOMMU_TAG_B, database = SCHIZO_IOMMU_DATA_B; + for(i = 0; i < 16; i++) { + schizo_write(p->controller_regs + tagbase + (i * 8UL), 0); + schizo_write(p->controller_regs + database + (i * 8UL), 0); + } + + /* Leave diag mode enabled for full-flushing done + * in pci_iommu.c + */ + + /* Using assumed page size 8K with 128K entries we need 1MB iommu page + * table (128K ioptes * 8 bytes per iopte). This is + * page order 7 on UltraSparc. + */ + tsbbase = __get_free_pages(GFP_KERNEL, 7); + if (!tsbbase) { + prom_printf("SCHIZO_IOMMU: Error, gfp(tsb) failed.\n"); + prom_halt(); + } + iommu->page_table = (iopte_t *)tsbbase; + iommu->page_table_sz_bits = 17; + iommu->page_table_map_base = 0xc0000000; + iommu->dma_addr_mask = 0xffffffff; + memset((char *)tsbbase, 0, PAGE_SIZE << 7); + + /* We start with no consistent mappings. */ + iommu->lowest_consistent_map = + 1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS); + + for (i = 0; i < PBM_NCLUSTERS; i++) { + iommu->alloc_info[i].flush = 0; + iommu->alloc_info[i].next = 0; + } + + schizo_write(iommu->iommu_tsbbase, __pa(tsbbase)); + + control = schizo_read(iommu->iommu_control); + control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ); + control |= (SCHIZO_IOMMU_TSBSZ_128K | SCHIZO_IOMMU_CTRL_ENAB); + schizo_write(iommu->iommu_control, control); } static void schizo_pbm_init(struct pci_controller_info *p, int prom_node, int is_pbm_a) { - /* IMPLEMENT ME */ + unsigned int busrange[2]; + struct pci_pbm_info *pbm; + int err; + + if (is_pbm_a) + pbm = &p->pbm_A; + else + pbm = &p->pbm_B; + + schizo_determine_mem_io_space(pbm, is_pbm_a, p->controller_regs); + pbm_register_toplevel_resources(p, pbm); + + pbm->parent = p; + pbm->prom_node = prom_node; + prom_getstring(prom_node, "name", + pbm->prom_name, + sizeof(pbm->prom_name)); + + err = prom_getproperty(prom_node, "ranges", + (char *) pbm->pbm_ranges, + sizeof(pbm->pbm_ranges)); + if (err != -1) + pbm->num_pbm_ranges = + (err / sizeof(struct linux_prom_pci_ranges)); + else + pbm->num_pbm_ranges = 0; + + err = prom_getproperty(prom_node, "interrupt-map", + (char *)pbm->pbm_intmap, + sizeof(pbm->pbm_intmap)); + if (err != -1) { + pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); + err = prom_getproperty(prom_node, "interrupt-map-mask", + (char *)&pbm->pbm_intmask, + sizeof(pbm->pbm_intmask)); + if (err == -1) { + prom_printf("SCHIZO-PBM: Fatal error, no " + "interrupt-map-mask.\n"); + prom_halt(); + } + } else { + pbm->num_pbm_intmap = 0; + memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); + } + + err = prom_getproperty(prom_node, "bus-range", + (char *)&busrange[0], + sizeof(busrange)); + if (err == 0 || err == -1) { + prom_printf("SCHIZO-PBM: Fatal error, no bus-range.\n"); + prom_halt(); + } + pbm->pci_first_busno = busrange[0]; + pbm->pci_last_busno = busrange[1]; + + schizo_pbm_iommu_init(p, pbm, is_pbm_a); + schizo_pbm_strbuf_init(p, pbm, is_pbm_a); +} + +static void schizo_controller_hwinit(struct pci_controller_info *p) +{ + unsigned long pbm_a_base, pbm_b_base; + u64 tmp; + + pbm_a_base = p->controller_regs + SCHIZO_PBM_A_REGS_OFF; + pbm_b_base = p->controller_regs + SCHIZO_PBM_B_REGS_OFF; + + /* Set IRQ retry to infinity. */ + schizo_write(pbm_a_base + 0x1a00UL, 0xff); + schizo_write(pbm_b_base + 0x1a00UL, 0xff); + + /* Enable arbiter for all PCI slots. */ + tmp = schizo_read(pbm_a_base + 0x2000UL); + tmp |= 0x3fUL; + schizo_write(pbm_a_base + 0x2000UL, tmp); + + tmp = schizo_read(pbm_b_base + 0x2000UL); + tmp |= 0x3fUL; + schizo_write(pbm_b_base + 0x2000UL, tmp); } void __init schizo_init(int node) @@ -90,6 +1645,7 @@ struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; struct pci_iommu *iommu; + unsigned long flags; u32 portid; int is_pbm_a, err; @@ -142,7 +1698,6 @@ p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; -pbm_init: /* Three OBP regs: * 1) PBM controller regs * 2) Schizo front-end controller regs (same for both PBMs) @@ -156,14 +1711,16 @@ prom_halt(); } - /* XXX Read REG base, record in controller/pbm structures. */ - - /* XXX Report controller to console. */ + p->controller_regs = pr_regs[1].phys_addr - 0x10000UL; + printk("PCI: Found SCHIZO, control regs at %016lx\n", + p->controller_regs); - /* XXX Setup pci_memspace_mask */ + /* Like PSYCHO we have a 2GB aligned area for memory space. */ + pci_memspace_mask = 0x7fffffffUL; - /* XXX Init core controller and IOMMU */ + /* Init core controller. */ + schizo_controller_hwinit(p); - is_pbm_a = XXX; /* Figure out this test */ + is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000); schizo_pbm_init(p, node, is_pbm_a); } diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.4.2/linux/arch/sparc64/kernel/setup.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/setup.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.59 2001/02/13 01:16:44 davem Exp $ +/* $Id: setup.c,v 1.62 2001/03/03 10:34:45 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -166,10 +166,14 @@ "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); /* - * Locked down tlb entry 63. + * Locked down tlb entry. */ - tte = spitfire_get_dtlb_data(63); + if (tlb_type == spitfire) + tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT); + else if (tlb_type == cheetah) + tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT); + res = PROM_TRUE; goto done; } @@ -253,7 +257,7 @@ unsigned long tte; tte = args[3]; - prom_printf("%lx ", (tte & _PAGE_SOFT2) >> 50); + prom_printf("%lx ", (tte & 0x07FC000000000000) >> 50); args[2] = 2; args[args[1] + 3] = 0; diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S --- v2.4.2/linux/arch/sparc64/kernel/trampoline.S Mon Dec 20 22:05:52 1999 +++ linux/arch/sparc64/kernel/trampoline.S Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.12 1999/12/15 15:45:12 davem Exp $ +/* $Id: trampoline.S,v 1.14 2001/03/04 18:31:00 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -30,177 +32,235 @@ sparc64_cpu_startup: flushw - mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1 - stxa %g1, [%g0] ASI_LSU_CONTROL - membar #Sync + rdpr %ver, %g1 + sethi %hi(0x003e0014), %g5 + srlx %g1, 32, %g1 + or %g5, %lo(0x003e0014), %g5 + cmp %g1, %g5 + bne,pt %icc, spitfire_startup + nop + +cheetah_startup: + mov DCR_BPE | DCR_RPE | DCR_SI | DCR_MS, %g1 + wr %g1, %asr18 + + sethi %uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + or %g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 + sllx %g5, 32, %g5 + ldxa [%g0] ASI_DCU_CONTROL_REG, %g1 + or %g1, %g5, %g1 + stxa %g5, [%g0] ASI_DCU_CONTROL_REG + membar #Sync - wrpr %g0, 15, %pil - wr %g0, 0, %tick_cmpr + ba,pt %xcc, startup_continue + nop + +spitfire_startup: + mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1 + stxa %g1, [%g0] ASI_LSU_CONTROL + membar #Sync + +startup_continue: + wrpr %g0, 15, %pil + wr %g0, 0, %tick_cmpr /* Call OBP by hand to lock KERNBASE into i/d tlbs. */ - mov %o0, %l0 + mov %o0, %l0 - sethi %hi(prom_entry_lock), %g2 -1: ldstub [%g2 + %lo(prom_entry_lock)], %g1 - brnz,pn %g1, 1b - membar #StoreLoad | #StoreStore - - sethi %hi(p1275buf), %g2 - or %g2, %lo(p1275buf), %g2 - ldx [%g2 + 0x10], %l2 - mov %sp, %l1 - add %l2, -(192 + 128), %sp + sethi %hi(prom_entry_lock), %g2 +1: ldstub [%g2 + %lo(prom_entry_lock)], %g1 + brnz,pn %g1, 1b + membar #StoreLoad | #StoreStore + + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x10], %l2 + mov %sp, %l1 + add %l2, -(192 + 128), %sp flushw - sethi %hi(call_method), %g2 - or %g2, %lo(call_method), %g2 - stx %g2, [%sp + 2047 + 128 + 0x00] - mov 5, %g2 - stx %g2, [%sp + 2047 + 128 + 0x08] - mov 1, %g2 - stx %g2, [%sp + 2047 + 128 + 0x10] - sethi %hi(itlb_load), %g2 - or %g2, %lo(itlb_load), %g2 - stx %g2, [%sp + 2047 + 128 + 0x18] - sethi %hi(mmu_ihandle_cache), %g2 - lduw [%g2 + %lo(mmu_ihandle_cache)], %g2 - stx %g2, [%sp + 2047 + 128 + 0x20] - sethi %hi(KERNBASE), %g2 - stx %g2, [%sp + 2047 + 128 + 0x28] - sethi %hi(kern_locked_tte_data), %g2 - ldx [%g2 + %lo(kern_locked_tte_data)], %g2 - stx %g2, [%sp + 2047 + 128 + 0x30] - mov 63, %g2 - stx %g2, [%sp + 2047 + 128 + 0x38] - sethi %hi(p1275buf), %g2 - or %g2, %lo(p1275buf), %g2 - ldx [%g2 + 0x08], %o1 - call %o1 - add %sp, (2047 + 128), %o0 - - sethi %hi(call_method), %g2 - or %g2, %lo(call_method), %g2 - stx %g2, [%sp + 2047 + 128 + 0x00] - mov 5, %g2 - stx %g2, [%sp + 2047 + 128 + 0x08] - mov 1, %g2 - stx %g2, [%sp + 2047 + 128 + 0x10] - sethi %hi(dtlb_load), %g2 - or %g2, %lo(dtlb_load), %g2 - stx %g2, [%sp + 2047 + 128 + 0x18] - sethi %hi(mmu_ihandle_cache), %g2 - lduw [%g2 + %lo(mmu_ihandle_cache)], %g2 - stx %g2, [%sp + 2047 + 128 + 0x20] - sethi %hi(KERNBASE), %g2 - stx %g2, [%sp + 2047 + 128 + 0x28] - sethi %hi(kern_locked_tte_data), %g2 - ldx [%g2 + %lo(kern_locked_tte_data)], %g2 - stx %g2, [%sp + 2047 + 128 + 0x30] - mov 63, %g2 - stx %g2, [%sp + 2047 + 128 + 0x38] - sethi %hi(p1275buf), %g2 - or %g2, %lo(p1275buf), %g2 - ldx [%g2 + 0x08], %o1 - call %o1 - add %sp, (2047 + 128), %o0 - - sethi %hi(prom_entry_lock), %g2 - stb %g0, [%g2 + %lo(prom_entry_lock)] - membar #StoreStore | #StoreLoad + sethi %hi(call_method), %g2 + or %g2, %lo(call_method), %g2 + stx %g2, [%sp + 2047 + 128 + 0x00] + mov 5, %g2 + stx %g2, [%sp + 2047 + 128 + 0x08] + mov 1, %g2 + stx %g2, [%sp + 2047 + 128 + 0x10] + sethi %hi(itlb_load), %g2 + or %g2, %lo(itlb_load), %g2 + stx %g2, [%sp + 2047 + 128 + 0x18] + sethi %hi(mmu_ihandle_cache), %g2 + lduw [%g2 + %lo(mmu_ihandle_cache)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x20] + sethi %hi(KERNBASE), %g2 + stx %g2, [%sp + 2047 + 128 + 0x28] + sethi %hi(kern_locked_tte_data), %g2 + ldx [%g2 + %lo(kern_locked_tte_data)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x30] + + rdpr %ver, %g1 + sethi %hi(0x003e0014), %g5 + srlx %g1, 32, %g1 + or %g5, %lo(0x003e0014), %g5 + cmp %g1, %g5 + bne,a,pt %icc, 1f + mov 63, %g2 + mov 15, %g2 +1: + stx %g2, [%sp + 2047 + 128 + 0x38] + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x08], %o1 + call %o1 + add %sp, (2047 + 128), %o0 + + sethi %hi(call_method), %g2 + or %g2, %lo(call_method), %g2 + stx %g2, [%sp + 2047 + 128 + 0x00] + mov 5, %g2 + stx %g2, [%sp + 2047 + 128 + 0x08] + mov 1, %g2 + stx %g2, [%sp + 2047 + 128 + 0x10] + sethi %hi(dtlb_load), %g2 + or %g2, %lo(dtlb_load), %g2 + stx %g2, [%sp + 2047 + 128 + 0x18] + sethi %hi(mmu_ihandle_cache), %g2 + lduw [%g2 + %lo(mmu_ihandle_cache)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x20] + sethi %hi(KERNBASE), %g2 + stx %g2, [%sp + 2047 + 128 + 0x28] + sethi %hi(kern_locked_tte_data), %g2 + ldx [%g2 + %lo(kern_locked_tte_data)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x30] + + rdpr %ver, %g1 + sethi %hi(0x003e0014), %g5 + srlx %g1, 32, %g1 + or %g5, %lo(0x003e0014), %g5 + cmp %g1, %g5 + bne,a,pt %icc, 1f + mov 63, %g2 + mov 15, %g2 +1: + + stx %g2, [%sp + 2047 + 128 + 0x38] + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x08], %o1 + call %o1 + add %sp, (2047 + 128), %o0 + + sethi %hi(prom_entry_lock), %g2 + stb %g0, [%g2 + %lo(prom_entry_lock)] + membar #StoreStore | #StoreLoad - mov %l1, %sp + mov %l1, %sp flushw - mov %l0, %o0 + mov %l0, %o0 - wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate - wr %g0, 0, %fprs + wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate + wr %g0, 0, %fprs - sethi %uhi(PAGE_OFFSET), %g4 - sllx %g4, 32, %g4 + sethi %uhi(PAGE_OFFSET), %g4 + sllx %g4, 32, %g4 /* XXX Buggy PROM... */ - srl %o0, 0, %o0 - ldx [%o0], %g6 + srl %o0, 0, %o0 + ldx [%o0], %g6 - wr %g0, ASI_P, %asi + wr %g0, ASI_P, %asi - mov PRIMARY_CONTEXT, %g7 - stxa %g0, [%g7] ASI_DMMU - membar #Sync - mov SECONDARY_CONTEXT, %g7 - stxa %g0, [%g7] ASI_DMMU - membar #Sync - - mov 1, %g5 - sllx %g5, (PAGE_SHIFT + 1), %g5 - sub %g5, (REGWIN_SZ + STACK_BIAS), %g5 - add %g6, %g5, %sp - mov 0, %fp + mov PRIMARY_CONTEXT, %g7 + stxa %g0, [%g7] ASI_DMMU + membar #Sync + mov SECONDARY_CONTEXT, %g7 + stxa %g0, [%g7] ASI_DMMU + membar #Sync + + mov 1, %g5 + sllx %g5, (PAGE_SHIFT + 1), %g5 + sub %g5, (REGWIN_SZ + STACK_BIAS), %g5 + add %g6, %g5, %sp + mov 0, %fp - wrpr %g0, 0, %wstate - wrpr %g0, 0, %tl + wrpr %g0, 0, %wstate + wrpr %g0, 0, %tl /* Setup the trap globals, then we can resurface. */ - rdpr %pstate, %o1 - mov %g6, %o2 - wrpr %o1, PSTATE_AG, %pstate - sethi %hi(sparc64_ttable_tl0), %g5 - wrpr %g5, %tba - mov %o2, %g6 + rdpr %pstate, %o1 + mov %g6, %o2 + wrpr %o1, PSTATE_AG, %pstate + sethi %hi(sparc64_ttable_tl0), %g5 + wrpr %g5, %tba + mov %o2, %g6 - wrpr %o1, PSTATE_MG, %pstate + wrpr %o1, PSTATE_MG, %pstate #define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) -#ifdef THIS_IS_CHEETAH -#error Dave, make sure you took care of other issues in rest of sparc64 code... -#define VPTE_BASE 0xffe0000000000000 -#else /* Spitfire/Blackbird */ -#define VPTE_BASE 0xfffffffe00000000 -#endif - mov TSB_REG, %g1 - stxa %g0, [%g1] ASI_DMMU - membar #Sync - mov TLB_SFSR, %g1 - sethi %uhi(KERN_HIGHBITS), %g2 - or %g2, %ulo(KERN_HIGHBITS), %g2 - sllx %g2, 32, %g2 - or %g2, KERN_LOWBITS, %g2 - sethi %uhi(VPTE_BASE), %g3 - or %g3, %ulo(VPTE_BASE), %g3 - sllx %g3, 32, %g3 + +#define VPTE_BASE_CHEETAH 0xffe0000000000000 +#define VPTE_BASE_SPITFIRE 0xfffffffe00000000 + + mov TSB_REG, %g1 + stxa %g0, [%g1] ASI_DMMU + membar #Sync + mov TLB_SFSR, %g1 + sethi %uhi(KERN_HIGHBITS), %g2 + or %g2, %ulo(KERN_HIGHBITS), %g2 + sllx %g2, 32, %g2 + or %g2, KERN_LOWBITS, %g2 + + rdpr %ver, %g3 + sethi %hi(0x003e0014), %g7 + srlx %g3, 32, %g3 + or %g7, %lo(0x003e0014), %g7 + cmp %g3, %g7 + bne,pt %icc, 1f + nop + + sethi %uhi(VPTE_BASE_CHEETAH), %g3 + or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 + ba,pt %xcc, 2f + sllx %g3, 32, %g3 +1: + sethi %uhi(VPTE_BASE_SPITFIRE), %g3 + or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 + sllx %g3, 32, %g3 + +2: clr %g7 #undef KERN_HIGHBITS #undef KERN_LOWBITS #undef VPTE_BASE /* Setup interrupt globals, we are always SMP. */ - wrpr %o1, PSTATE_IG, %pstate + wrpr %o1, PSTATE_IG, %pstate /* Get our UPA MID. */ - lduw [%o2 + AOFF_task_processor], %g1 - sethi %hi(cpu_data), %g5 - or %g5, %lo(cpu_data), %g5 + lduw [%o2 + AOFF_task_processor], %g1 + sethi %hi(cpu_data), %g5 + or %g5, %lo(cpu_data), %g5 /* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */ - sllx %g1, 7, %g1 - add %g5, %g1, %g1 - add %g1, 64, %g6 - - wrpr %g0, 0, %wstate - or %o1, PSTATE_IE, %o1 - wrpr %o1, 0, %pstate + sllx %g1, 7, %g1 + add %g5, %g1, %g1 + add %g1, 64, %g6 + + wrpr %g0, 0, %wstate + or %o1, PSTATE_IE, %o1 + wrpr %o1, 0, %pstate - call prom_set_trap_table - sethi %hi(sparc64_ttable_tl0), %o0 + call prom_set_trap_table + sethi %hi(sparc64_ttable_tl0), %o0 - call smp_callin + call smp_callin nop - call cpu_idle - mov 0, %o0 - call cpu_panic + call cpu_idle + mov 0, %o0 + call cpu_panic nop -1: b,a,pt %xcc, 1b +1: b,a,pt %xcc, 1b .align 8 sparc64_cpu_startup_end: diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.4.2/linux/arch/sparc64/mm/init.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/mm/init.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.162 2001/02/13 01:16:44 davem Exp $ +/* $Id: init.c,v 1.164 2001/03/03 10:34:45 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -40,6 +40,8 @@ /* Ugly, but necessary... -DaveM */ unsigned long phys_base; +enum ultra_tlb_layout tlb_type = spitfire; + /* get_new_mmu_context() uses "cache + 1". */ spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED; unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; @@ -57,17 +59,17 @@ { int freed = 0; - if(pgtable_cache_size > high) { + if (pgtable_cache_size > high) { do { #ifdef CONFIG_SMP - if(pgd_quicklist) + if (pgd_quicklist) free_pgd_slow(get_pgd_fast()), freed++; #endif - if(pte_quicklist[0]) + if (pte_quicklist[0]) free_pte_slow(get_pte_fast(0)), freed++; - if(pte_quicklist[1]) + if (pte_quicklist[1]) free_pte_slow(get_pte_fast(1)), freed++; - } while(pgtable_cache_size > low); + } while (pgtable_cache_size > low); } #ifndef CONFIG_SMP if (pgd_cache_size > high / 4) { @@ -163,13 +165,12 @@ int mmu_info(char *buf) { - /* We'll do the rest later to make it nice... -DaveM */ -#if 0 - if (this_is_cheetah) - sprintf(buf, "MMU Type\t: One bad ass cpu\n"); + if (tlb_type == cheetah) + return sprintf(buf, "MMU Type\t: Cheetah\n"); + else if (tlb_type == spitfire) + return sprintf(buf, "MMU Type\t: Spitfire\n"); else -#endif - return sprintf(buf, "MMU Type\t: Spitfire\n"); + return sprintf(buf, "MMU Type\t: ???\n"); } struct linux_prom_translation { @@ -231,6 +232,8 @@ for (vaddr = trans[i].virt; vaddr < trans[i].virt + trans[i].size; vaddr += PAGE_SIZE) { + unsigned long val; + pgdp = pgd_offset(&init_mm, vaddr); if (pgd_none(*pgdp)) { pmdp = __alloc_bootmem(PMD_TABLE_SIZE, @@ -252,7 +255,14 @@ pmd_set(pmdp, ptep); } ptep = pte_offset(pmdp, vaddr); - set_pte (ptep, __pte(trans[i].data | _PAGE_MODIFIED)); + + val = trans[i].data; + + /* Clear diag TTE bits. */ + if (tlb_type == spitfire) + val &= ~0x0003fe0000000000UL; + + set_pte (ptep, __pte(val | _PAGE_MODIFIED)); trans[i].data += PAGE_SIZE; } } @@ -268,26 +278,59 @@ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR; + switch (tlb_type) { + default: + case spitfire: + phys_page = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()); + break; + + case cheetah: + phys_page = cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent()); + break; + }; + + phys_page &= _PAGE_PADDR; phys_page += ((unsigned long)&prom_boot_page - (unsigned long)&empty_zero_page); - /* Lock this into i/d tlb entry 59 */ - __asm__ __volatile__( - "stxa %%g0, [%2] %3\n\t" - "stxa %0, [%1] %4\n\t" - "membar #Sync\n\t" - "flush %%g6\n\t" - "stxa %%g0, [%2] %5\n\t" - "stxa %0, [%1] %6\n\t" - "membar #Sync\n\t" - "flush %%g6" - : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP | - _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), - "r" (59 << 3), "r" (TLB_TAG_ACCESS), - "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), - "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) - : "memory"); + if (tlb_type == spitfire) { + /* Lock this into i/d tlb entry 59 */ + __asm__ __volatile__( + "stxa %%g0, [%2] %3\n\t" + "stxa %0, [%1] %4\n\t" + "membar #Sync\n\t" + "flush %%g6\n\t" + "stxa %%g0, [%2] %5\n\t" + "stxa %0, [%1] %6\n\t" + "membar #Sync\n\t" + "flush %%g6" + : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP | + _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), + "r" (59 << 3), "r" (TLB_TAG_ACCESS), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), + "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) + : "memory"); + } else if (tlb_type == cheetah) { + /* Lock this into i/d tlb-0 entry 11 */ + __asm__ __volatile__( + "stxa %%g0, [%2] %3\n\t" + "stxa %0, [%1] %4\n\t" + "membar #Sync\n\t" + "flush %%g6\n\t" + "stxa %%g0, [%2] %5\n\t" + "stxa %0, [%1] %6\n\t" + "membar #Sync\n\t" + "flush %%g6" + : : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP | + _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), + "r" ((0 << 16) | (11 << 3)), "r" (TLB_TAG_ACCESS), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), + "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) + : "memory"); + } else { + /* Implement me :-) */ + BUG(); + } tte_vaddr = (unsigned long) &empty_zero_page; @@ -298,7 +341,12 @@ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63); + if (tlb_type == spitfire) + tte_data = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()); + else + tte_data = cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent()); + + kern_locked_tte_data = tte_data; remap_func = (void *) ((unsigned long) &prom_remap - (unsigned long) &prom_boot_page); @@ -311,7 +359,9 @@ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR, + remap_func((tlb_type == spitfire ? + (spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR) : + (cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR)), (unsigned long) &empty_zero_page, prom_get_mmu_ihandle()); @@ -320,8 +370,8 @@ spitfire_flush_itlb_nucleus_page(0x0); /* Now lock us back into the TLBs via OBP. */ - prom_dtlb_load(63, tte_data, tte_vaddr); - prom_itlb_load(63, tte_data, tte_vaddr); + prom_dtlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr); + prom_itlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr); /* Re-read translations property. */ if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) { @@ -372,26 +422,45 @@ int i; /* Only DTLB must be checked for VPTE entries. */ - for(i = 0; i < 63; i++) { - unsigned long tag; + if (tlb_type == spitfire) { + for (i = 0; i < 63; i++) { + unsigned long tag; - /* Spitfire Errata #32 workaround */ - __asm__ __volatile__("stxa %0, [%1] %2\n\t" - "flush %%g6" - : /* No outputs */ - : "r" (0), - "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - - tag = spitfire_get_dtlb_tag(i); - if(((tag & ~(PAGE_MASK)) == 0) && - ((tag & (PAGE_MASK)) >= prom_reserved_base)) { - __asm__ __volatile__("stxa %%g0, [%0] %1" - : /* no outputs */ - : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(i, 0x0UL); - membar("#Sync"); + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + + tag = spitfire_get_dtlb_tag(i); + if (((tag & ~(PAGE_MASK)) == 0) && + ((tag & (PAGE_MASK)) >= prom_reserved_base)) { + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(i, 0x0UL); + membar("#Sync"); + } + } + } else if (tlb_type == cheetah) { + for (i = 0; i < 511; i++) { + unsigned long tag = cheetah_get_dtlb_tag(i); + + if ((tag & ~PAGE_MASK) == 0 && + (tag & PAGE_MASK) >= prom_reserved_base) { + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + cheetah_put_dtlb_data(i, 0x0UL); + membar("#Sync"); + } } + } else { + /* Implement me :-) */ + BUG(); } } @@ -401,7 +470,7 @@ unsigned long tlb_tag; unsigned long tlb_data; }; -struct prom_tlb_entry prom_itlb[8], prom_dtlb[8]; +struct prom_tlb_entry prom_itlb[16], prom_dtlb[16]; void prom_world(int enter) { @@ -426,41 +495,56 @@ __flush_nucleus_vptes(); /* Install PROM world. */ - for (i = 0; i < 8; i++) { + for (i = 0; i < 16; i++) { if (prom_dtlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %0, [%1] %2" : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); membar("#Sync"); - spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, - prom_dtlb[i].tlb_data); + if (tlb_type == spitfire) + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, + prom_dtlb[i].tlb_data); + else if (tlb_type == cheetah) + cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, + prom_dtlb[i].tlb_data); membar("#Sync"); } - if (prom_itlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_IMMU)); + : : "r" (prom_itlb[i].tlb_tag), + "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); membar("#Sync"); - spitfire_put_itlb_data(prom_itlb[i].tlb_ent, - prom_itlb[i].tlb_data); + if (tlb_type == spitfire) + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, + prom_itlb[i].tlb_data); + else if (tlb_type == cheetah) + cheetah_put_litlb_data(prom_itlb[i].tlb_ent, + prom_itlb[i].tlb_data); membar("#Sync"); } } } else { - for (i = 0; i < 8; i++) { + for (i = 0; i < 16; i++) { if (prom_dtlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); membar("#Sync"); - spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); + if (tlb_type == spitfire) + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); + else + cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); membar("#Sync"); } if (prom_itlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + : : "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); membar("#Sync"); - spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL); + if (tlb_type == spitfire) + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL); + else + cheetah_put_litlb_data(prom_itlb[i].tlb_ent, 0x0UL); membar("#Sync"); } } @@ -490,25 +574,14 @@ * UNDOCUMENTED!!!!!! Thanks S(t)un! */ if (save_p) { - for(i = 0; i < 8; i++) { - prom_dtlb[i].tlb_ent = -1; + for (i = 0; i < 16; i++) { prom_itlb[i].tlb_ent = -1; + prom_dtlb[i].tlb_ent = -1; } } - for(i = 0; i < 63; i++) { - unsigned long data; - - - /* Spitfire Errata #32 workaround */ - __asm__ __volatile__("stxa %0, [%1] %2\n\t" - "flush %%g6" - : /* No outputs */ - : "r" (0), - "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - - data = spitfire_get_dtlb_data(i); - if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { - unsigned long tag; + if (tlb_type == spitfire) { + for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) { + unsigned long data; /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" @@ -517,36 +590,37 @@ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - tag = spitfire_get_dtlb_tag(i); - if(save_p) { - prom_dtlb[dtlb_seen].tlb_ent = i; - prom_dtlb[dtlb_seen].tlb_tag = tag; - prom_dtlb[dtlb_seen].tlb_data = data; - } - __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(i, 0x0UL); - membar("#Sync"); + data = spitfire_get_dtlb_data(i); + if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { + unsigned long tag; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + + tag = spitfire_get_dtlb_tag(i); + if (save_p) { + prom_dtlb[dtlb_seen].tlb_ent = i; + prom_dtlb[dtlb_seen].tlb_tag = tag; + prom_dtlb[dtlb_seen].tlb_data = data; + } + __asm__ __volatile__("stxa %%g0, [%0] %1" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(i, 0x0UL); + membar("#Sync"); - dtlb_seen++; - if(dtlb_seen > 7) - break; + dtlb_seen++; + if (dtlb_seen > 15) + break; + } } - } - for(i = 0; i < 63; i++) { - unsigned long data; - /* Spitfire Errata #32 workaround */ - __asm__ __volatile__("stxa %0, [%1] %2\n\t" - "flush %%g6" - : /* No outputs */ - : "r" (0), - "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - - data = spitfire_get_itlb_data(i); - if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { - unsigned long tag; + for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) { + unsigned long data; /* Spitfire Errata #32 workaround */ __asm__ __volatile__("stxa %0, [%1] %2\n\t" @@ -555,22 +629,87 @@ : "r" (0), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - tag = spitfire_get_itlb_tag(i); - if(save_p) { - prom_itlb[itlb_seen].tlb_ent = i; - prom_itlb[itlb_seen].tlb_tag = tag; - prom_itlb[itlb_seen].tlb_data = data; + data = spitfire_get_itlb_data(i); + if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { + unsigned long tag; + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + + tag = spitfire_get_itlb_tag(i); + if (save_p) { + prom_itlb[itlb_seen].tlb_ent = i; + prom_itlb[itlb_seen].tlb_tag = tag; + prom_itlb[itlb_seen].tlb_data = data; + } + __asm__ __volatile__("stxa %%g0, [%0] %1" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(i, 0x0UL); + membar("#Sync"); + + itlb_seen++; + if (itlb_seen > 15) + break; } - __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(i, 0x0UL); - membar("#Sync"); + } + } else if (tlb_type == cheetah) { + for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) { + unsigned long data; + + data = cheetah_get_ldtlb_data(i); + if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { + unsigned long tag; + + tag = cheetah_get_ldtlb_tag(i); + if (save_p) { + prom_dtlb[dtlb_seen].tlb_ent = i; + prom_dtlb[dtlb_seen].tlb_tag = tag; + prom_dtlb[dtlb_seen].tlb_data = data; + } + __asm__ __volatile__("stxa %%g0, [%0] %1" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + cheetah_put_ldtlb_data(i, 0x0UL); + membar("#Sync"); - itlb_seen++; - if(itlb_seen > 7) - break; + dtlb_seen++; + if (dtlb_seen > 15) + break; + } } + + for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) { + unsigned long data; + + data = cheetah_get_litlb_data(i); + if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) { + unsigned long tag; + + tag = cheetah_get_litlb_tag(i); + if (save_p) { + prom_itlb[itlb_seen].tlb_ent = i; + prom_itlb[itlb_seen].tlb_tag = tag; + prom_itlb[itlb_seen].tlb_data = data; + } + __asm__ __volatile__("stxa %%g0, [%0] %1" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + membar("#Sync"); + cheetah_put_litlb_data(i, 0x0UL); + membar("#Sync"); + + itlb_seen++; + if (itlb_seen > 15) + break; + } + } + } else { + /* Implement me :-) */ + BUG(); } if (save_p) prom_ditlb_set = 1; @@ -581,24 +720,33 @@ { int i; - for (i = 0; i < 8; i++) { + for (i = 0; i < 16; i++) { if (prom_dtlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %0, [%1] %2" : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); membar("#Sync"); - spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, - prom_dtlb[i].tlb_data); + if (tlb_type == spitfire) + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, + prom_dtlb[i].tlb_data); + else if (tlb_type == cheetah) + cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, + prom_dtlb[i].tlb_data); membar("#Sync"); } if (prom_itlb[i].tlb_ent != -1) { __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_IMMU)); + : : "r" (prom_itlb[i].tlb_tag), + "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); membar("#Sync"); - spitfire_put_itlb_data(prom_itlb[i].tlb_ent, - prom_itlb[i].tlb_data); + if (tlb_type == spitfire) + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, + prom_itlb[i].tlb_data); + else + cheetah_put_litlb_data(prom_itlb[i].tlb_ent, + prom_itlb[i].tlb_data); membar("#Sync"); } } @@ -621,7 +769,7 @@ unsigned long va; flushw_all(); - for(va = 0; va < (PAGE_SIZE << 1); va += 32) + for (va = 0; va < (PAGE_SIZE << 1); va += 32) spitfire_put_icache_tag(va, 0x0); } @@ -636,38 +784,43 @@ "wrpr %0, %1, %%pstate" : "=r" (pstate) : "i" (PSTATE_IE)); - for(i = 0; i < 64; i++) { - /* Spitfire Errata #32 workaround */ - __asm__ __volatile__("stxa %0, [%1] %2\n\t" - "flush %%g6" - : /* No outputs */ - : "r" (0), - "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - - if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) { - __asm__ __volatile__("stxa %%g0, [%0] %1" - : /* no outputs */ - : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(i, 0x0UL); - membar("#Sync"); - } + if (tlb_type == spitfire) { + for (i = 0; i < 64; i++) { + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - /* Spitfire Errata #32 workaround */ - __asm__ __volatile__("stxa %0, [%1] %2\n\t" - "flush %%g6" - : /* No outputs */ - : "r" (0), - "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - - if(!(spitfire_get_itlb_data(i) & _PAGE_L)) { - __asm__ __volatile__("stxa %%g0, [%0] %1" - : /* no outputs */ - : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(i, 0x0UL); - membar("#Sync"); + if (!(spitfire_get_dtlb_data(i) & _PAGE_L)) { + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(i, 0x0UL); + membar("#Sync"); + } + + /* Spitfire Errata #32 workaround */ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "flush %%g6" + : /* No outputs */ + : "r" (0), + "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); + + if (!(spitfire_get_itlb_data(i) & _PAGE_L)) { + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(i, 0x0UL); + membar("#Sync"); + } } + } else if (tlb_type == cheetah) { + cheetah_flush_dtlb_all(); + cheetah_flush_itlb_all(); } __asm__ __volatile__("wrpr %0, 0, %%pstate" : : "r" (pstate)); @@ -709,7 +862,7 @@ mmu_context_bmap[1] = 0; mmu_context_bmap[2] = 0; mmu_context_bmap[3] = 0; - for(i = 4; i < CTX_BMAP_SLOTS; i += 4) { + for (i = 4; i < CTX_BMAP_SLOTS; i += 4) { mmu_context_bmap[i + 0] = 0; mmu_context_bmap[i + 1] = 0; mmu_context_bmap[i + 2] = 0; @@ -740,7 +893,7 @@ pmd_t *pmd; pmd = (pmd_t *) __get_free_page(GFP_KERNEL); - if(pmd) { + if (pmd) { memset(pmd, 0, PAGE_SIZE); pgd_set(pgd, pmd); return pmd + offset; @@ -798,31 +951,77 @@ { int slot; - printk ("Contents of itlb: "); - for (slot = 0; slot < 14; slot++) printk (" "); - printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0)); - for (slot = 1; slot < 64; slot+=3) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot), - slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1), - slot+2, spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2)); - } + if (tlb_type == spitfire) { + printk ("Contents of itlb: "); + for (slot = 0; slot < 14; slot++) printk (" "); + printk ("%2x:%016lx,%016lx\n", + 0, + spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0)); + for (slot = 1; slot < 64; slot+=3) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot), + slot+1, + spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1), + slot+2, + spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2)); + } + } else if (tlb_type == cheetah) { + printk ("Contents of itlb0:\n"); + for (slot = 0; slot < 16; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_litlb_tag(slot), cheetah_get_litlb_data(slot), + slot+1, + cheetah_get_litlb_tag(slot+1), cheetah_get_litlb_data(slot+1)); + } + printk ("Contents of itlb2:\n"); + for (slot = 0; slot < 128; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_itlb_tag(slot), cheetah_get_itlb_data(slot), + slot+1, + cheetah_get_itlb_tag(slot+1), cheetah_get_itlb_data(slot+1)); + } + } } void sparc_ultra_dump_dtlb(void) { int slot; - printk ("Contents of dtlb: "); - for (slot = 0; slot < 14; slot++) printk (" "); - printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), - spitfire_get_dtlb_data(0)); - for (slot = 1; slot < 64; slot+=3) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", - slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot), - slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1), - slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2)); - } + if (tlb_type == spitfire) { + printk ("Contents of dtlb: "); + for (slot = 0; slot < 14; slot++) printk (" "); + printk ("%2x:%016lx,%016lx\n", 0, + spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0)); + for (slot = 1; slot < 64; slot+=3) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot), + slot+1, + spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1), + slot+2, + spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2)); + } + } else if (tlb_type == cheetah) { + printk ("Contents of dtlb0:\n"); + for (slot = 0; slot < 16; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_ldtlb_tag(slot), cheetah_get_ldtlb_data(slot), + slot+1, + cheetah_get_ldtlb_tag(slot+1), cheetah_get_ldtlb_data(slot+1)); + } + printk ("Contents of dtlb2:\n"); + for (slot = 0; slot < 512; slot+=2) { + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", + slot, + cheetah_get_dtlb_tag(slot), cheetah_get_dtlb_data(slot), + slot+1, + cheetah_get_dtlb_tag(slot+1), cheetah_get_dtlb_data(slot+1)); + } + } } extern unsigned long cmdline_memory_size; @@ -959,20 +1158,7 @@ pt = phys_base | _PAGE_VALID | _PAGE_SZ4MB; pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W; __save_and_cli(flags); - __asm__ __volatile__(" - stxa %1, [%0] %3 - stxa %2, [%5] %4 - membar #Sync - flush %%g6 - nop - nop - nop" - : /* No outputs */ - : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), - "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) - : "memory"); - if (((unsigned long)&_end) >= KERNBASE + 0x340000) { - second_alias_page = alias_base + 0x400000; + if (tlb_type == spitfire) { __asm__ __volatile__(" stxa %1, [%0] %3 stxa %2, [%5] %4 @@ -982,9 +1168,52 @@ nop nop" : /* No outputs */ - : "r" (TLB_TAG_ACCESS), "r" (second_alias_page), "r" (pt + 0x400000), - "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3) + : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) : "memory"); + if (((unsigned long)&_end) >= KERNBASE + 0x340000) { + second_alias_page = alias_base + 0x400000; + __asm__ __volatile__(" + stxa %1, [%0] %3 + stxa %2, [%5] %4 + membar #Sync + flush %%g6 + nop + nop + nop" + : /* No outputs */ + : "r" (TLB_TAG_ACCESS), "r" (second_alias_page), "r" (pt + 0x400000), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3) + : "memory"); + } + } else if (tlb_type == cheetah) { + __asm__ __volatile__(" + stxa %1, [%0] %3 + stxa %2, [%5] %4 + membar #Sync + flush %%g6 + nop + nop + nop" + : /* No outputs */ + : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" ((0<<16) | (13<<3)) + : "memory"); + if (((unsigned long)&_end) >= KERNBASE + 0x340000) { + second_alias_page = alias_base + 0x400000; + __asm__ __volatile__(" + stxa %1, [%0] %3 + stxa %2, [%5] %4 + membar #Sync + flush %%g6 + nop + nop + nop" + : /* No outputs */ + : "r" (TLB_TAG_ACCESS), "r" (second_alias_page), "r" (pt + 0x400000), + "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" ((0<<16) | (12<<3)) + : "memory"); + } } __restore_flags(flags); diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S --- v2.4.2/linux/arch/sparc64/mm/ultra.S Thu Nov 9 15:57:41 2000 +++ linux/arch/sparc64/mm/ultra.S Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.48 2000/11/06 06:59:04 davem Exp $ +/* $Id: ultra.S,v 1.49 2001/03/02 03:12:00 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com) @@ -59,6 +59,7 @@ /*IC5*/ rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate mov TLB_TAG_ACCESS, %g3 + /* XXX Spitfire dependency... */ mov (62 << 3), %g2 /* Spitfire Errata #32 workaround. */ @@ -469,6 +470,7 @@ stx %g0, [%g4 + %lo(errata32_hwbug)] 2: add %g2, 1, %g2 + /* XXX Spitfire dependency... */ cmp %g2, 63 ble,pt %icc, 1b sll %g2, 3, %g3 diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/char/i2c.c linux/drivers/acorn/char/i2c.c --- v2.4.2/linux/drivers/acorn/char/i2c.c Mon Sep 18 15:15:21 2000 +++ linux/drivers/acorn/char/i2c.c Fri Mar 2 18:38:37 2001 @@ -122,43 +122,62 @@ #define SCL 0x02 #define SDA 0x01 -static int ioc_control; +/* + * We must preserve all non-i2c output bits in IOC_CONTROL. + * Note also that we need to preserve the value of SCL and + * SDA outputs as well (which may be different from the + * values read back from IOC_CONTROL). + */ +static u_int force_ones; static void ioc_setscl(void *data, int state) { + u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); + u_int ones = force_ones; + if (state) - ioc_control |= SCL; + ones |= SCL; else - ioc_control &= ~SCL; - outb(ioc_control, IOC_CONTROL); + ones &= ~SCL; + + force_ones = ones; + + ioc_writeb(ioc_control | ones, IOC_CONTROL); } static void ioc_setsda(void *data, int state) { + u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); + u_int ones = force_ones; + if (state) - ioc_control |= SDA; + ones |= SDA; else - ioc_control &= ~SDA; - outb(ioc_control, IOC_CONTROL); + ones &= ~SDA; + + force_ones = ones; + + ioc_writeb(ioc_control | ones, IOC_CONTROL); } static int ioc_getscl(void *data) { - return (inb(IOC_CONTROL) & SCL) != 0; + return (ioc_readb(IOC_CONTROL) & SCL) != 0; } static int ioc_getsda(void *data) { - return (inb(IOC_CONTROL) & SDA) != 0; + return (ioc_readb(IOC_CONTROL) & SDA) != 0; } static struct i2c_algo_bit_data ioc_data = { - NULL, - ioc_setsda, - ioc_setscl, - ioc_getsda, - ioc_getscl, - 80, 80, 100 + setsda: ioc_setsda, + setscl: ioc_setscl, + getsda: ioc_getsda, + getscl: ioc_getscl, + udelay: 80, + mdelay: 80, + timeout: 100 }; static int ioc_client_reg(struct i2c_client *client) @@ -184,22 +203,16 @@ } static struct i2c_adapter ioc_ops = { - "IOC/IOMD", - I2C_HW_B_IOC, - NULL, - &ioc_data, - NULL, - NULL, - ioc_client_reg, - ioc_client_unreg + name: "IOC/IOMD", + id: I2C_HW_B_IOC, + algo_data: &ioc_data, + client_register: ioc_client_reg, + client_unregister: ioc_client_unreg }; static int __init i2c_ioc_init(void) { - ioc_control = inb(IOC_CONTROL) | FORCE_ONES; - - ioc_setscl(NULL, 1); - ioc_setsda(NULL, 1); + force_ones = FORCE_ONES | SCL | SDA; return i2c_bit_add_bus(&ioc_ops); } diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/char/pcf8583.c linux/drivers/acorn/char/pcf8583.c --- v2.4.2/linux/drivers/acorn/char/pcf8583.c Wed Feb 21 18:20:16 2001 +++ linux/drivers/acorn/char/pcf8583.c Fri Mar 2 18:38:37 2001 @@ -20,16 +20,16 @@ static struct i2c_driver pcf8583_driver; static unsigned short ignore[] = { I2C_CLIENT_END }; -static unsigned short normal_addr[] = { 0x50, 0x51, I2C_CLIENT_END }; +static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { - force: ignore, + normal_i2c: normal_addr, + normal_i2c_range: ignore, + probe: ignore, + probe_range: ignore, ignore: ignore, ignore_range: ignore, - normal_i2c: ignore, - normal_i2c_range: normal_addr, - probe: ignore, - probe_range: ignore + force: ignore, }; #define DAT(x) ((unsigned int)(x->data)) @@ -86,7 +86,10 @@ }; int ret = -EIO; - if (i2c_transfer(client->adapter, msgs, 2) == 2) { + memset(buf, 0, sizeof(buf)); + + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret == 2) { dt->year_off = buf[4] >> 6; dt->wday = buf[5] >> 5; @@ -126,6 +129,8 @@ } ret = i2c_master_send(client, (char *)buf, len); + if (ret == len) + ret = 0; buf[1] = DAT(client); i2c_master_send(client, (char *)buf, 2); @@ -219,12 +224,12 @@ } static struct i2c_driver pcf8583_driver = { - "PCF8583", - I2C_DRIVERID_PCF8583, - I2C_DF_NOTIFY, - pcf8583_probe, - pcf8583_detach, - pcf8583_command + name: "PCF8583", + id: I2C_DRIVERID_PCF8583, + flags: I2C_DF_NOTIFY, + attach_adapter: pcf8583_probe, + detach_client: pcf8583_detach, + command: pcf8583_command }; static __init int pcf8583_init(void) diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c --- v2.4.2/linux/drivers/acorn/scsi/acornscsi.c Mon Sep 18 15:15:22 2000 +++ linux/drivers/acorn/scsi/acornscsi.c Fri Mar 2 18:38:37 2001 @@ -1248,7 +1248,7 @@ /* * Function: void acornscsi_dma_adjust(AS_Host *host) - * Purpose : adjust DMA pointers & count for bytes transfered to + * Purpose : adjust DMA pointers & count for bytes transferred to * SBIC but not SCSI bus. * Params : host - host to adjust DMA count for */ diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c --- v2.4.2/linux/drivers/acorn/scsi/cumana_2.c Wed Feb 21 18:20:16 2001 +++ linux/drivers/acorn/scsi/cumana_2.c Fri Mar 2 18:38:37 2001 @@ -90,7 +90,7 @@ /* * Use term=0,1,0,0,0 to turn terminators on/off */ -int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; +static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; #define NR_SG 256 diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c --- v2.4.2/linux/drivers/acorn/scsi/eesox.c Wed Feb 21 18:20:16 2001 +++ linux/drivers/acorn/scsi/eesox.c Fri Mar 2 18:38:37 2001 @@ -88,7 +88,7 @@ /* * Use term=0,1,0,0,0 to turn terminators on/off */ -int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; +static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; #define NR_SG 256 diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c --- v2.4.2/linux/drivers/acorn/scsi/powertec.c Wed Feb 21 18:20:16 2001 +++ linux/drivers/acorn/scsi/powertec.c Fri Mar 2 18:38:37 2001 @@ -87,7 +87,7 @@ /* * Use term=0,1,0,0,0 to turn terminators on/off */ -int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; +static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; #define NR_SG 256 diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/Makefile linux/drivers/acpi/Makefile --- v2.4.2/linux/drivers/acpi/Makefile Sat Feb 3 19:51:25 2001 +++ linux/drivers/acpi/Makefile Sat Mar 3 17:46:47 2001 @@ -20,14 +20,6 @@ EXTRA_CFLAGS += $(ACPI_CFLAGS) -# genksyms only reads $(CFLAGS), it should really read $(EXTRA_CFLAGS) as well. -# Without EXTRA_CFLAGS the gcc pass for genksyms fails, resulting in an empty -# include/linux/modules/acpi_ksyms.ver. Changing genkyms to use EXTRA_CFLAGS -# will hit everything, too risky in 2.4.0-prerelease. Bandaid by tweaking -# CFLAGS only for .ver targets. Review after 2.4.0 release. KAO - -$(MODINCL)/%.ver: CFLAGS := -I./include $(CFLAGS) - acpi-subdirs := common dispatcher events hardware \ interpreter namespace parser resources tables diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/events/evsci.c linux/drivers/acpi/events/evsci.c --- v2.4.2/linux/drivers/acpi/events/evsci.c Sat Feb 3 19:51:25 2001 +++ linux/drivers/acpi/events/evsci.c Tue Mar 6 19:44:36 2001 @@ -177,7 +177,7 @@ * PARAMETERS: Event Event that generated an SCI. * * RETURN: Number of SCI's for requested event since last time - * Sci_occured() was called for this event. + * Sci_occurred() was called for this event. * * DESCRIPTION: Checks to see if SCI has been generated from requested source * since the last time this function was called. diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/include/acconfig.h linux/drivers/acpi/include/acconfig.h --- v2.4.2/linux/drivers/acpi/include/acconfig.h Wed Feb 21 18:20:17 2001 +++ linux/drivers/acpi/include/acconfig.h Tue Mar 6 19:44:36 2001 @@ -89,7 +89,7 @@ /* * Debugger threading model * Use single threaded if the entire subsystem is contained in an application - * Use multiple threaded when the the subsystem is running in the kernel. + * Use multiple threaded when the subsystem is running in the kernel. * * By default the model is single threaded if ACPI_APPLICATION is set, * multi-threaded if ACPI_APPLICATION is not set. diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/interpreter/amstore.c linux/drivers/acpi/interpreter/amstore.c --- v2.4.2/linux/drivers/acpi/interpreter/amstore.c Wed Feb 21 18:20:17 2001 +++ linux/drivers/acpi/interpreter/amstore.c Tue Mar 6 19:44:36 2001 @@ -190,7 +190,7 @@ * FUNCTION: Acpi_aml_store_object_to_index * * PARAMETERS: *Val_desc - Value to be stored - * *Node - Named object to recieve the value + * *Node - Named object to receive the value * * RETURN: Status * @@ -390,7 +390,7 @@ * FUNCTION: Acpi_aml_store_object_to_node * * PARAMETERS: *Source_desc - Value to be stored - * *Node - Named object to recieve the value + * *Node - Named object to receive the value * * RETURN: Status * diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/namespace/nsinit.c linux/drivers/acpi/namespace/nsinit.c --- v2.4.2/linux/drivers/acpi/namespace/nsinit.c Wed Feb 21 18:20:17 2001 +++ linux/drivers/acpi/namespace/nsinit.c Tue Mar 6 19:44:36 2001 @@ -271,7 +271,7 @@ } else { - /* Count of successfull INIs */ + /* Count of successful INIs */ info->num_INI++; } diff -u --recursive --new-file v2.4.2/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.4.2/linux/drivers/block/ll_rw_blk.c Wed Feb 21 18:20:18 2001 +++ linux/drivers/block/ll_rw_blk.c Fri Mar 2 15:16:59 2001 @@ -1239,9 +1239,6 @@ #ifdef CONFIG_BLK_DEV_RAM rd_init(); #endif -#ifdef CONFIG_BLK_DEV_LOOP - loop_init(); -#endif #ifdef CONFIG_ISP16_CDI isp16_init(); #endif diff -u --recursive --new-file v2.4.2/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.4.2/linux/drivers/block/loop.c Wed Feb 21 18:20:18 2001 +++ linux/drivers/block/loop.c Tue Mar 6 19:35:36 2001 @@ -31,11 +31,14 @@ * max_loop=<1-255> to the kernel on boot. * Erik I. Bolsĝ, , Oct 31, 1999 * + * Completely rewrite request handling to be make_request_fn style and + * non blocking, pushing work to a helper thread. Lots of fixes from + * Al Viro too. + * Jens Axboe , Nov 2000 + * * Still To Fix: * - Advisory locking is ignored here. * - Should use an own CAP_* category instead of CAP_SYS_ADMIN - * - Should use the underlying filesystems/devices read function if possible - * to support read ahead (and for write) * * WARNING/FIXME: * - The block number as IV passing to low level transfer functions is broken: @@ -48,6 +51,7 @@ * number. */ +#include #include #include @@ -56,9 +60,13 @@ #include #include #include - +#include +#include #include #include +#include +#include +#include #include @@ -66,40 +74,28 @@ #define MAJOR_NR LOOP_MAJOR -#define DEVICE_NAME "loop" -#define DEVICE_REQUEST do_lo_request -#define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) -#define DEVICE_NO_RANDOM -#define TIMEOUT_VALUE (6 * HZ) -#include - -#include static int max_loop = 8; static struct loop_device *loop_dev; static int *loop_sizes; static int *loop_blksizes; static devfs_handle_t devfs_handle; /* For the directory */ -#define FALSE 0 -#define TRUE (!FALSE) - /* * Transfer functions */ static int transfer_none(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, int real_block) + char *loop_buf, int size, int real_block) { if (cmd == READ) memcpy(loop_buf, raw_buf, size); else memcpy(raw_buf, loop_buf, size); + return 0; } static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf, - char *loop_buf, int size, int real_block) + char *loop_buf, int size, int real_block) { char *in, *out, *key; int i, keysize; @@ -111,17 +107,18 @@ in = loop_buf; out = raw_buf; } + key = lo->lo_encrypt_key; keysize = lo->lo_encrypt_key_size; - for (i=0; i < size; i++) + for (i = 0; i < size; i++) *out++ = *in++ ^ key[(i & 511) % keysize]; return 0; } static int none_status(struct loop_device *lo, struct loop_info *info) { - return 0; -} + return 0; +} static int xor_status(struct loop_device *lo, struct loop_info *info) { @@ -133,7 +130,7 @@ struct loop_func_table none_funcs = { number: LO_CRYPT_NONE, transfer: transfer_none, - init: none_status + init: none_status, }; struct loop_func_table xor_funcs = { @@ -150,39 +147,41 @@ #define MAX_DISK_SIZE 1024*1024*1024 -static void figure_loop_size(struct loop_device *lo) +static int compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev) { - int size; - - if (S_ISREG(lo->lo_dentry->d_inode->i_mode)) - size = (lo->lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS; - else { - kdev_t lodev = lo->lo_device; - if (blk_size[MAJOR(lodev)]) - size = blk_size[MAJOR(lodev)][MINOR(lodev)] - + if (S_ISREG(lo_dentry->d_inode->i_mode)) + return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS; + if (blk_size[MAJOR(lodev)]) + return blk_size[MAJOR(lodev)][MINOR(lodev)] - (lo->lo_offset >> BLOCK_SIZE_BITS); - else - size = MAX_DISK_SIZE; - } + return MAX_DISK_SIZE; +} - loop_sizes[lo->lo_number] = size; +static void figure_loop_size(struct loop_device *lo) +{ + loop_sizes[lo->lo_number] = compute_loop_size(lo, + lo->lo_backing_file->f_dentry, + lo->lo_device); } -static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos, - int blksize) +static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize, + loff_t pos) { struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */ - struct address_space *mapping = lo->lo_dentry->d_inode->i_mapping; + struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct address_space_operations *aops = mapping->a_ops; struct page *page; - char *kaddr; + char *kaddr, *data; unsigned long index; unsigned size, offset; + int len; index = pos >> PAGE_CACHE_SHIFT; offset = pos & (PAGE_CACHE_SIZE - 1); + len = bh->b_size; + data = bh->b_data; while (len > 0) { - int IV = index * (PAGE_CACHE_SIZE/blksize) + offset/blksize; + int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize; size = PAGE_CACHE_SIZE - offset; if (size > len) size = len; @@ -193,7 +192,8 @@ if (aops->prepare_write(file, page, offset, offset+size)) goto unlock; kaddr = page_address(page); - if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV)) + flush_dcache_page(page); + if (lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV)) goto write_fail; if (aops->commit_write(file, page, offset, offset+size)) goto unlock; @@ -203,6 +203,7 @@ index++; pos += size; UnlockPage(page); + deactivate_page(page); page_cache_release(page); } return 0; @@ -213,6 +214,7 @@ kunmap(page); unlock: UnlockPage(page); + deactivate_page(page); page_cache_release(page); fail: return -1; @@ -221,7 +223,7 @@ struct lo_read_data { struct loop_device *lo; char *data; - int blksize; + int bsize; }; static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) @@ -230,16 +232,15 @@ unsigned long count = desc->count; struct lo_read_data *p = (struct lo_read_data*)desc->buf; struct loop_device *lo = p->lo; - int IV = page->index * (PAGE_CACHE_SIZE/p->blksize) + offset/p->blksize; + int IV = page->index * (PAGE_CACHE_SIZE/p->bsize) + offset/p->bsize; if (size > count) size = count; kaddr = kmap(page); - if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) { + if (lo_do_transfer(lo, READ, kaddr + offset, p->data, size, IV)) { size = 0; - printk(KERN_ERR "loop: transfer error block %ld\n", - page->index); + printk(KERN_ERR "loop: transfer error block %ld\n",page->index); desc->error = -EINVAL; } kunmap(page); @@ -250,160 +251,345 @@ return size; } -static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos, - int blksize) +static int lo_receive(struct loop_device *lo, struct buffer_head *bh, int bsize, + loff_t pos) { - struct file *file = lo->lo_backing_file; struct lo_read_data cookie; read_descriptor_t desc; + struct file *file; cookie.lo = lo; - cookie.data = data; - cookie.blksize = blksize; + cookie.data = bh->b_data; + cookie.bsize = bsize; desc.written = 0; - desc.count = len; + desc.count = bh->b_size; desc.buf = (char*)&cookie; desc.error = 0; + spin_lock_irq(&lo->lo_lock); + file = lo->lo_backing_file; + spin_unlock_irq(&lo->lo_lock); do_generic_file_read(file, &pos, &desc, lo_read_actor); return desc.error; } -static void do_lo_request(request_queue_t * q) +static inline int loop_get_bs(struct loop_device *lo) +{ + int bs = 0; + + if (blksize_size[MAJOR(lo->lo_device)]) + bs = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)]; + if (!bs) + bs = BLOCK_SIZE; + + return bs; +} + +static inline unsigned long loop_get_iv(struct loop_device *lo, + unsigned long sector) +{ + int bs = loop_get_bs(lo); + unsigned long offset, IV; + + IV = sector / (bs >> 9) + lo->lo_offset / bs; + offset = ((sector % (bs >> 9)) << 9) + lo->lo_offset % bs; + if (offset >= bs) + IV++; + + return IV; +} + +static int do_bh_filebacked(struct loop_device *lo, struct buffer_head *bh, int rw) { - int block, offset, len, blksize, size; - char *dest_addr; - struct loop_device *lo; - struct buffer_head *bh; - struct request *current_request; loff_t pos; + int ret; + + pos = ((loff_t) bh->b_rsector << 9) + lo->lo_offset; + + if (rw == WRITE) + ret = lo_send(lo, bh, loop_get_bs(lo), pos); + else + ret = lo_receive(lo, bh, loop_get_bs(lo), pos); + + return ret; +} + +static void loop_put_buffer(struct buffer_head *bh) +{ + if (bh) { + kunmap(bh->b_page); + __free_page(bh->b_page); + kmem_cache_free(bh_cachep, bh); + } +} + +/* + * Add buffer_head to back of pending list + */ +static void loop_add_bh(struct loop_device *lo, struct buffer_head *bh) +{ + unsigned long flags; + + spin_lock_irqsave(&lo->lo_lock, flags); + if (lo->lo_bhtail) { + lo->lo_bhtail->b_reqnext = bh; + lo->lo_bhtail = bh; + } else + lo->lo_bh = lo->lo_bhtail = bh; + spin_unlock_irqrestore(&lo->lo_lock, flags); + + up(&lo->lo_bh_mutex); +} + +/* + * Grab first pending buffer + */ +static struct buffer_head *loop_get_bh(struct loop_device *lo) +{ + struct buffer_head *bh; + + spin_lock_irq(&lo->lo_lock); + if ((bh = lo->lo_bh)) { + if (bh == lo->lo_bhtail) + lo->lo_bhtail = NULL; + lo->lo_bh = bh->b_reqnext; + bh->b_reqnext = NULL; + } + spin_unlock_irq(&lo->lo_lock); + + return bh; +} + +/* + * when buffer i/o has completed. if BH_Dirty is set, this was a WRITE + * and lo->transfer stuff has already been done. if not, it was a READ + * so queue it for the loop thread and let it do the transfer out of + * b_end_io context (we don't want to do decrypt of a page with irqs + * disabled) + */ +static void loop_end_io_transfer(struct buffer_head *bh, int uptodate) +{ + struct loop_device *lo = &loop_dev[MINOR(bh->b_dev)]; + + if (!uptodate || test_bit(BH_Dirty, &bh->b_state)) { + struct buffer_head *rbh = bh->b_private; + + rbh->b_end_io(rbh, uptodate); + if (atomic_dec_and_test(&lo->lo_pending)) + up(&lo->lo_bh_mutex); + loop_put_buffer(bh); + } else + loop_add_bh(lo, bh); +} + +static struct buffer_head *loop_get_buffer(struct loop_device *lo, + struct buffer_head *rbh) +{ + struct buffer_head *bh; + + do { + bh = kmem_cache_alloc(bh_cachep, SLAB_BUFFER); + if (bh) + break; + + run_task_queue(&tq_disk); + schedule_timeout(HZ); + } while (1); + memset(bh, 0, sizeof(*bh)); + + bh->b_size = rbh->b_size; + bh->b_dev = rbh->b_rdev; + spin_lock_irq(&lo->lo_lock); + bh->b_rdev = lo->lo_device; + spin_unlock_irq(&lo->lo_lock); + bh->b_state = (1 << BH_Req) | (1 << BH_Mapped) | (1 << BH_Lock); + + /* + * easy way out, although it does waste some memory for < PAGE_SIZE + * blocks... if highmem bounce buffering can get away with it, + * so can we :-) + */ + bh->b_page = alloc_page(GFP_BUFFER); + bh->b_data = kmap(bh->b_page); + + bh->b_end_io = loop_end_io_transfer; + bh->b_rsector = rbh->b_rsector + (lo->lo_offset >> 9); + init_waitqueue_head(&bh->b_wait); + + return bh; +} + +static int loop_make_request(request_queue_t *q, int rw, struct buffer_head *rbh) +{ + struct buffer_head *bh = NULL; + struct loop_device *lo; + unsigned long IV; + + if (!buffer_locked(rbh)) + BUG(); + + if (MINOR(rbh->b_rdev) >= max_loop) + goto out; -repeat: - INIT_REQUEST; - current_request=CURRENT; - blkdev_dequeue_request(current_request); - if (MINOR(current_request->rq_dev) >= max_loop) - goto error_out; - lo = &loop_dev[MINOR(current_request->rq_dev)]; - if (!lo->lo_dentry || !lo->transfer) - goto error_out; - if (current_request->cmd == WRITE) { + lo = &loop_dev[MINOR(rbh->b_rdev)]; + spin_lock_irq(&lo->lo_lock); + if (lo->lo_state != Lo_bound) + goto inactive; + atomic_inc(&lo->lo_pending); + spin_unlock_irq(&lo->lo_lock); + + if (rw == WRITE) { if (lo->lo_flags & LO_FLAGS_READ_ONLY) - goto error_out; - } else if (current_request->cmd != READ) { - printk(KERN_ERR "unknown loop device command (%d)?!?", - current_request->cmd); - goto error_out; + goto err; + } else if (rw == READA) { + rw = READ; + } else if (rw != READ) { + printk(KERN_ERR "loop: unknown command (%d)\n", rw); + goto err; } - dest_addr = current_request->buffer; - len = current_request->current_nr_sectors << 9; +#if CONFIG_HIGHMEM + rbh = create_bounce(rw, rbh); +#endif - blksize = BLOCK_SIZE; - if (blksize_size[MAJOR(lo->lo_device)]) { - blksize = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)]; - if (!blksize) - blksize = BLOCK_SIZE; + /* + * file backed, queue for loop_thread to handle + */ + if (lo->lo_flags & LO_FLAGS_DO_BMAP) { + if (rw == WRITE) + set_bit(BH_Dirty, &rbh->b_state); + loop_add_bh(lo, rbh); + return 0; } - if (lo->lo_flags & LO_FLAGS_DO_BMAP) - goto file_backed; + /* + * piggy old buffer on original, and submit for I/O + */ + bh = loop_get_buffer(lo, rbh); + bh->b_private = rbh; + IV = loop_get_iv(lo, bh->b_rsector); + if (rw == WRITE) { + set_bit(BH_Dirty, &bh->b_state); + if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data, bh->b_size, IV)) + goto err; + } - if (blksize < 512) { - block = current_request->sector * (512/blksize); - offset = 0; + generic_make_request(rw, bh); + return 0; + +err: + if (atomic_dec_and_test(&lo->lo_pending)) + up(&lo->lo_bh_mutex); + loop_put_buffer(bh); +out: + buffer_IO_error(rbh); + return 0; +inactive: + spin_unlock_irq(&lo->lo_lock); + goto out; +} + +static inline void loop_handle_bh(struct loop_device *lo,struct buffer_head *bh) +{ + int ret; + + /* + * For block backed loop, we know this is a READ + */ + if (lo->lo_flags & LO_FLAGS_DO_BMAP) { + int rw = !!test_and_clear_bit(BH_Dirty, &bh->b_state); + + ret = do_bh_filebacked(lo, bh, rw); + bh->b_end_io(bh, !ret); } else { - block = current_request->sector / (blksize >> 9); - offset = (current_request->sector % (blksize >> 9)) << 9; - } - block += lo->lo_offset / blksize; - offset += lo->lo_offset % blksize; - if (offset >= blksize) { - block++; - offset -= blksize; + struct buffer_head *rbh = bh->b_private; + unsigned long IV = loop_get_iv(lo, rbh->b_rsector); + + ret = lo_do_transfer(lo, READ, bh->b_data, rbh->b_data, + bh->b_size, IV); + + rbh->b_end_io(rbh, !ret); + loop_put_buffer(bh); } - spin_unlock_irq(&io_request_lock); +} - while (len > 0) { +/* + * worker thread that handles reads/writes to file backed loop devices, + * to avoid blocking in our make_request_fn. it also does loop decrypting + * on reads for block backed loop, as that is too heavy to do from + * b_end_io context where irqs may be disabled. + */ +static int loop_thread(void *data) +{ + struct loop_device *lo = data; + struct buffer_head *bh; - size = blksize - offset; - if (size > len) - size = len; + daemonize(); + exit_files(current); - bh = getblk(lo->lo_device, block, blksize); - if (!bh) { - printk(KERN_ERR "loop: device %s: getblk(-, %d, %d) returned NULL", - kdevname(lo->lo_device), - block, blksize); - goto error_out_lock; - } - if (!buffer_uptodate(bh) && ((current_request->cmd == READ) || - (offset || (len < blksize)))) { - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - brelse(bh); - goto error_out_lock; - } - } + sprintf(current->comm, "loop%d", lo->lo_number); - if ((lo->transfer)(lo, current_request->cmd, - bh->b_data + offset, - dest_addr, size, block)) { - printk(KERN_ERR "loop: transfer error block %d\n", - block); - brelse(bh); - goto error_out_lock; - } + spin_lock_irq(¤t->sigmask_lock); + sigfillset(¤t->blocked); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + + current->policy = SCHED_OTHER; + current->nice = -20; + + spin_lock_irq(&lo->lo_lock); + lo->lo_state = Lo_bound; + atomic_inc(&lo->lo_pending); + spin_unlock_irq(&lo->lo_lock); + + /* + * up sem, we are running + */ + up(&lo->lo_sem); - if (current_request->cmd == WRITE) { - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh); + for (;;) { + down_interruptible(&lo->lo_bh_mutex); + /* + * could be upped because of tear-down, not because of + * pending work + */ + if (!atomic_read(&lo->lo_pending)) + break; + + bh = loop_get_bh(lo); + if (!bh) { + printk("loop: missing bh\n"); + continue; } - brelse(bh); - dest_addr += size; - len -= size; - offset = 0; - block++; - } - goto done; + loop_handle_bh(lo, bh); -file_backed: - pos = ((loff_t)current_request->sector << 9) + lo->lo_offset; - spin_unlock_irq(&io_request_lock); - if (current_request->cmd == WRITE) { - if (lo_send(lo, dest_addr, len, pos, blksize)) - goto error_out_lock; - } else { - if (lo_receive(lo, dest_addr, len, pos, blksize)) - goto error_out_lock; + /* + * upped both for pending work and tear-down, lo_pending + * will hit zero then + */ + if (atomic_dec_and_test(&lo->lo_pending)) + break; } -done: - spin_lock_irq(&io_request_lock); - current_request->sector += current_request->current_nr_sectors; - current_request->nr_sectors -= current_request->current_nr_sectors; - list_add(¤t_request->queue, &q->queue_head); - end_request(1); - goto repeat; -error_out_lock: - spin_lock_irq(&io_request_lock); -error_out: - list_add(¤t_request->queue, &q->queue_head); - end_request(0); - goto repeat; + + up(&lo->lo_sem); + return 0; } -static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg) +static int loop_set_fd(struct loop_device *lo, struct file *lo_file, kdev_t dev, + unsigned int arg) { struct file *file; struct inode *inode; - int error; + kdev_t lo_device; + int lo_flags = 0; + int error; + int bs; MOD_INC_USE_COUNT; error = -EBUSY; - if (lo->lo_dentry) + if (lo->lo_state != Lo_unbound) goto out; - + error = -EBADF; file = fget(arg); if (!file) @@ -412,24 +598,13 @@ error = -EINVAL; inode = file->f_dentry->d_inode; - if (S_ISBLK(inode->i_mode)) { - /* dentry will be wired, so... */ - error = blkdev_get(inode->i_bdev, file->f_mode, - file->f_flags, BDEV_FILE); - - lo->lo_device = inode->i_rdev; - lo->lo_flags = 0; - - /* Backed by a block device - don't need to hold onto - a file structure */ - lo->lo_backing_file = NULL; + if (!(file->f_mode & FMODE_WRITE)) + lo_flags |= LO_FLAGS_READ_ONLY; - if (error) - goto out_putf; + if (S_ISBLK(inode->i_mode)) { + lo_device = inode->i_rdev; } else if (S_ISREG(inode->i_mode)) { - struct address_space_operations *aops; - - aops = inode->i_mapping->a_ops; + struct address_space_operations *aops = inode->i_mapping->a_ops; /* * If we can't read - sorry. If we only can't write - well, * it's going to be read-only. @@ -439,57 +614,50 @@ goto out_putf; if (!aops->prepare_write || !aops->commit_write) - lo->lo_flags |= LO_FLAGS_READ_ONLY; - - error = get_write_access(inode); - if (error) - goto out_putf; - - /* Backed by a regular file - we need to hold onto a file - structure for this file. Friggin' NFS can't live without - it on write and for reading we use do_generic_file_read(), - so... We create a new file structure based on the one - passed to us via 'arg'. This is to avoid changing the file - structure that the caller is using */ - - lo->lo_device = inode->i_dev; - lo->lo_flags |= LO_FLAGS_DO_BMAP; - - error = -ENFILE; - lo->lo_backing_file = get_empty_filp(); - if (lo->lo_backing_file == NULL) { - put_write_access(inode); - goto out_putf; - } - - lo->lo_backing_file->f_mode = file->f_mode; - lo->lo_backing_file->f_pos = file->f_pos; - lo->lo_backing_file->f_flags = file->f_flags; - lo->lo_backing_file->f_owner = file->f_owner; - lo->lo_backing_file->f_dentry = file->f_dentry; - lo->lo_backing_file->f_vfsmnt = mntget(file->f_vfsmnt); - lo->lo_backing_file->f_op = fops_get(file->f_op); - lo->lo_backing_file->private_data = file->private_data; - file_moveto(lo->lo_backing_file, file); + lo_flags |= LO_FLAGS_READ_ONLY; + lo_device = inode->i_dev; + lo_flags |= LO_FLAGS_DO_BMAP; error = 0; - } + } else + goto out_putf; + + get_file(file); - if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) - lo->lo_flags |= LO_FLAGS_READ_ONLY; + if (IS_RDONLY (inode) || is_read_only(lo_device) + || !(lo_file->f_mode & FMODE_WRITE)) + lo_flags |= LO_FLAGS_READ_ONLY; - set_device_ro(dev, (lo->lo_flags & LO_FLAGS_READ_ONLY)!=0); + set_device_ro(dev, (lo_flags & LO_FLAGS_READ_ONLY) != 0); - lo->lo_dentry = dget(file->f_dentry); + lo->lo_device = lo_device; + lo->lo_flags = lo_flags; + lo->lo_backing_file = file; lo->transfer = NULL; lo->ioctl = NULL; figure_loop_size(lo); + lo->old_gfp_mask = inode->i_mapping->gfp_mask; + inode->i_mapping->gfp_mask = GFP_BUFFER; + + bs = 0; + if (blksize_size[MAJOR(inode->i_rdev)]) + bs = blksize_size[MAJOR(inode->i_rdev)][MINOR(inode->i_rdev)]; + if (!bs) + bs = BLOCK_SIZE; + + set_blocksize(dev, bs); + + lo->lo_bh = lo->lo_bhtail = NULL; + kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + down(&lo->lo_sem); + + fput(file); + return 0; out_putf: fput(file); out: - if (error) - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; return error; } @@ -525,27 +693,25 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev) { - struct dentry *dentry = lo->lo_dentry; + struct file *filp = lo->lo_backing_file; + int gfp = lo->old_gfp_mask; - if (!dentry) + if (lo->lo_state != Lo_bound) return -ENXIO; if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */ return -EBUSY; + if (filp==NULL) + return -EINVAL; - if (S_ISBLK(dentry->d_inode->i_mode)) - blkdev_put(dentry->d_inode->i_bdev, BDEV_FILE); + spin_lock_irq(&lo->lo_lock); + lo->lo_state = Lo_rundown; + if (atomic_dec_and_test(&lo->lo_pending)) + up(&lo->lo_bh_mutex); + spin_unlock_irq(&lo->lo_lock); - lo->lo_dentry = NULL; + down(&lo->lo_sem); - if (lo->lo_backing_file != NULL) { - struct file *filp = lo->lo_backing_file; - if ((filp->f_mode & FMODE_WRITE) == 0) - put_write_access(filp->f_dentry->d_inode); - fput(filp); - lo->lo_backing_file = NULL; - } else { - dput(dentry); - } + lo->lo_backing_file = NULL; loop_release_xfer(lo); lo->transfer = NULL; @@ -554,10 +720,14 @@ lo->lo_encrypt_type = 0; lo->lo_offset = 0; lo->lo_encrypt_key_size = 0; + lo->lo_flags = 0; memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_name, 0, LO_NAME_SIZE); loop_sizes[lo->lo_number] = 0; invalidate_buffers(dev); + filp->f_dentry->d_inode->i_mapping->gfp_mask = gfp; + lo->lo_state = Lo_unbound; + fput(filp); MOD_DEC_USE_COUNT; return 0; } @@ -571,7 +741,7 @@ if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && !capable(CAP_SYS_ADMIN)) return -EPERM; - if (!lo->lo_dentry) + if (lo->lo_state != Lo_bound) return -ENXIO; if (copy_from_user(&info, arg, sizeof (struct loop_info))) return -EFAULT; @@ -608,15 +778,16 @@ static int loop_get_status(struct loop_device *lo, struct loop_info *arg) { struct loop_info info; + struct file *file = lo->lo_backing_file; - if (!lo->lo_dentry) + if (lo->lo_state != Lo_bound) return -ENXIO; if (!arg) return -EINVAL; memset(&info, 0, sizeof(info)); info.lo_number = lo->lo_number; - info.lo_device = kdev_t_to_nr(lo->lo_dentry->d_inode->i_dev); - info.lo_inode = lo->lo_dentry->d_inode->i_ino; + info.lo_device = kdev_t_to_nr(file->f_dentry->d_inode->i_dev); + info.lo_inode = file->f_dentry->d_inode->i_ino; info.lo_rdevice = kdev_t_to_nr(lo->lo_device); info.lo_offset = lo->lo_offset; info.lo_flags = lo->lo_flags; @@ -634,7 +805,7 @@ unsigned int cmd, unsigned long arg) { struct loop_device *lo; - int dev; + int dev, err; if (!inode) return -EINVAL; @@ -647,25 +818,36 @@ if (dev >= max_loop) return -ENODEV; lo = &loop_dev[dev]; + down(&lo->lo_ctl_mutex); switch (cmd) { case LOOP_SET_FD: - return loop_set_fd(lo, inode->i_rdev, arg); + err = loop_set_fd(lo, file, inode->i_rdev, arg); + break; case LOOP_CLR_FD: - return loop_clr_fd(lo, inode->i_rdev); + err = loop_clr_fd(lo, inode->i_rdev); + break; case LOOP_SET_STATUS: - return loop_set_status(lo, (struct loop_info *) arg); + err = loop_set_status(lo, (struct loop_info *) arg); + break; case LOOP_GET_STATUS: - return loop_get_status(lo, (struct loop_info *) arg); - case BLKGETSIZE: /* Return device size */ - if (!lo->lo_dentry) - return -ENXIO; - if (!arg) - return -EINVAL; - return put_user(loop_sizes[lo->lo_number] << 1, (long *) arg); + err = loop_get_status(lo, (struct loop_info *) arg); + break; + case BLKGETSIZE: + if (lo->lo_state != Lo_bound) { + err = -ENXIO; + break; + } + if (!arg) { + err = -EINVAL; + break; + } + err = put_user(loop_sizes[lo->lo_number] << 1, (long *) arg); + break; default: - return lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; + err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; } - return 0; + up(&lo->lo_ctl_mutex); + return err; } static int lo_open(struct inode *inode, struct file *file) @@ -673,7 +855,6 @@ struct loop_device *lo; int dev, type; - if (!inode) return -EINVAL; if (MAJOR(inode->i_rdev) != MAJOR_NR) { @@ -681,23 +862,25 @@ return -ENODEV; } dev = MINOR(inode->i_rdev); - if (dev >= max_loop) { + if (dev >= max_loop) return -ENODEV; - } + lo = &loop_dev[dev]; + MOD_INC_USE_COUNT; + down(&lo->lo_ctl_mutex); type = lo->lo_encrypt_type; if (type && xfer_funcs[type] && xfer_funcs[type]->lock) xfer_funcs[type]->lock(lo); lo->lo_refcnt++; - MOD_INC_USE_COUNT; + up(&lo->lo_ctl_mutex); return 0; } static int lo_release(struct inode *inode, struct file *file) { struct loop_device *lo; - int dev; + int dev, type; if (!inode) return 0; @@ -709,17 +892,16 @@ dev = MINOR(inode->i_rdev); if (dev >= max_loop) return 0; + lo = &loop_dev[dev]; - if (lo->lo_refcnt <= 0) - printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", - lo->lo_refcnt); - else { - int type = lo->lo_encrypt_type; - --lo->lo_refcnt; - if (xfer_funcs[type] && xfer_funcs[type]->unlock) - xfer_funcs[type]->unlock(lo); - MOD_DEC_USE_COUNT; - } + down(&lo->lo_ctl_mutex); + type = lo->lo_encrypt_type; + --lo->lo_refcnt; + if (xfer_funcs[type] && xfer_funcs[type]->unlock) + xfer_funcs[type]->unlock(lo); + + up(&lo->lo_ctl_mutex); + MOD_DEC_USE_COUNT; return 0; } @@ -732,11 +914,8 @@ /* * And now the modules code and kernel interface. */ -#ifdef MODULE -#define loop_init init_module MODULE_PARM(max_loop, "i"); MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)"); -#endif int loop_register_transfer(struct loop_func_table *funcs) { @@ -767,88 +946,88 @@ EXPORT_SYMBOL(loop_register_transfer); EXPORT_SYMBOL(loop_unregister_transfer); -static void no_plug_device(request_queue_t *q, kdev_t device) -{ -} - int __init loop_init(void) { int i; - if (devfs_register_blkdev(MAJOR_NR, "loop", &lo_fops)) { - printk(KERN_WARNING "Unable to get major number %d for loop device\n", - MAJOR_NR); - return -EIO; - } - devfs_handle = devfs_mk_dir (NULL, "loop", NULL); - devfs_register_series (devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT, - MAJOR_NR, 0, - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, - &lo_fops, NULL); - if ((max_loop < 1) || (max_loop > 255)) { - printk (KERN_WARNING "loop: invalid max_loop (must be between 1 and 255), using default (8)\n"); + printk(KERN_WARNING "loop: invalid max_loop (must be between" + " 1 and 255), using default (8)\n"); max_loop = 8; } - printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop); - - loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL); - if (!loop_dev) { - printk (KERN_ERR "loop: Unable to create loop_dev\n"); - return -ENOMEM; + if (devfs_register_blkdev(MAJOR_NR, "loop", &lo_fops)) { + printk(KERN_WARNING "Unable to get major number %d for loop" + " device\n", MAJOR_NR); + return -EIO; } - loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL); - if (!loop_sizes) { - printk (KERN_ERR "loop: Unable to create loop_sizes\n"); - kfree (loop_dev); - return -ENOMEM; - } + devfs_handle = devfs_mk_dir(NULL, "loop", NULL); + devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT, + MAJOR_NR, 0, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + &lo_fops, NULL); - loop_blksizes = kmalloc (max_loop * sizeof(int), GFP_KERNEL); - if (!loop_blksizes) { - printk (KERN_ERR "loop: Unable to create loop_blksizes\n"); - kfree (loop_dev); - kfree (loop_sizes); + loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL); + if (!loop_dev) return -ENOMEM; - } - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); - blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), no_plug_device); - blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0); - for (i=0; i < max_loop; i++) { - memset(&loop_dev[i], 0, sizeof(struct loop_device)); - loop_dev[i].lo_number = i; + loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL); + if (!loop_sizes) + goto out_sizes; + + loop_blksizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL); + if (!loop_blksizes) + goto out_blksizes; + + blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), loop_make_request); + + for (i = 0; i < max_loop; i++) { + struct loop_device *lo = &loop_dev[i]; + memset(lo, 0, sizeof(struct loop_device)); + init_MUTEX(&lo->lo_ctl_mutex); + init_MUTEX_LOCKED(&lo->lo_sem); + init_MUTEX_LOCKED(&lo->lo_bh_mutex); + lo->lo_number = i; + spin_lock_init(&lo->lo_lock); } + memset(loop_sizes, 0, max_loop * sizeof(int)); memset(loop_blksizes, 0, max_loop * sizeof(int)); blk_size[MAJOR_NR] = loop_sizes; blksize_size[MAJOR_NR] = loop_blksizes; - for (i=0; i < max_loop; i++) - register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &lo_fops, 0); + for (i = 0; i < max_loop; i++) + register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0); + printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop); return 0; + +out_sizes: + kfree(loop_dev); +out_blksizes: + kfree(loop_sizes); + printk(KERN_ERR "loop: ran out of memory\n"); + return -ENOMEM; } -#ifdef MODULE -void cleanup_module(void) +void loop_exit(void) { - devfs_unregister (devfs_handle); - if (devfs_unregister_blkdev(MAJOR_NR, "loop") != 0) + devfs_unregister(devfs_handle); + if (devfs_unregister_blkdev(MAJOR_NR, "loop")) printk(KERN_WARNING "loop: cannot unregister blkdev\n"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - kfree (loop_dev); - kfree (loop_sizes); - kfree (loop_blksizes); + kfree(loop_dev); + kfree(loop_sizes); + kfree(loop_blksizes); } -#endif + +module_init(loop_init); +module_exit(loop_exit); #ifndef MODULE static int __init max_loop_setup(char *str) { - max_loop = simple_strtol(str,NULL,0); + max_loop = simple_strtol(str, NULL, 0); return 1; } diff -u --recursive --new-file v2.4.2/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.4.2/linux/drivers/block/nbd.c Mon Oct 30 14:30:33 2000 +++ linux/drivers/block/nbd.c Tue Mar 6 19:19:21 2001 @@ -18,6 +18,8 @@ * 97-9-13 Cosmetic changes * 98-5-13 Attempt to make 64-bit-clean on 64-bit machines * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines + * 01-2-27 Fix to store proper blockcount for kernel (calculated using + * BLOCK_SIZE_BITS, not device blocksize) * * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall * why not: would need verify_area and friends, would share yet another @@ -413,16 +415,16 @@ nbd_blksize_bits[dev]++; temp >>= 1; } - nbd_sizes[dev] = nbd_bytesizes[dev] >> nbd_blksize_bits[dev]; - nbd_bytesizes[dev] = nbd_sizes[dev] << nbd_blksize_bits[dev]; + nbd_bytesizes[dev] &= ~(nbd_blksizes[dev]-1); + nbd_sizes[dev] = nbd_bytesizes[dev] >> BLOCK_SIZE_BITS; return 0; case NBD_SET_SIZE: - nbd_sizes[dev] = arg >> nbd_blksize_bits[dev]; - nbd_bytesizes[dev] = nbd_sizes[dev] << nbd_blksize_bits[dev]; + nbd_bytesizes[dev] = arg & ~(nbd_blksizes[dev]-1); + nbd_sizes[dev] = nbd_bytesizes[dev] >> BLOCK_SIZE_BITS; return 0; case NBD_SET_SIZE_BLOCKS: - nbd_sizes[dev] = arg; - nbd_bytesizes[dev] = ((u64) arg) << nbd_blksize_bits[dev]; + nbd_bytesizes[dev] = ((u64) arg) << nbd_blksize_bits[dev]; + nbd_sizes[dev] = nbd_bytesizes[dev] >> BLOCK_SIZE_BITS; return 0; case NBD_DO_IT: if (!lo->file) @@ -513,7 +515,7 @@ nbd_blksizes[i] = 1024; nbd_blksize_bits[i] = 10; nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */ - nbd_sizes[i] = nbd_bytesizes[i] >> nbd_blksize_bits[i]; + nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS; register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops, nbd_bytesizes[i]>>9); } diff -u --recursive --new-file v2.4.2/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.4.2/linux/drivers/char/Config.in Wed Feb 21 18:20:18 2001 +++ linux/drivers/char/Config.in Tue Mar 6 19:44:34 2001 @@ -133,6 +133,7 @@ fi tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT + tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO @@ -142,6 +143,7 @@ tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG fi fi + tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT fi endmenu @@ -176,7 +178,7 @@ fi endmenu -tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP +dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP if [ "$CONFIG_AGP" != "n" ]; then bool ' Intel 440LX/BX/GX and I815/I840/I850 support' CONFIG_AGP_INTEL bool ' Intel I810/I815 (on-board) support' CONFIG_AGP_I810 diff -u --recursive --new-file v2.4.2/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.4.2/linux/drivers/char/Makefile Thu Jan 4 13:00:55 2001 +++ linux/drivers/char/Makefile Tue Mar 6 19:44:34 2001 @@ -177,6 +177,7 @@ obj-$(CONFIG_PCWATCHDOG) += pcwd.o obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o +obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o obj-$(CONFIG_MIXCOMWD) += mixcomwd.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_WDT) += wdt.o @@ -184,6 +185,7 @@ obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o obj-$(CONFIG_I810_TCO) += i810-tco.o +obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o diff -u --recursive --new-file v2.4.2/linux/drivers/char/advantechwdt.c linux/drivers/char/advantechwdt.c --- v2.4.2/linux/drivers/char/advantechwdt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/advantechwdt.c Tue Mar 6 19:44:34 2001 @@ -0,0 +1,241 @@ +/* + * Advantech Single Board Computer WDT driver for Linux 2.4.x + * + * (c) Copyright 2000-2001 Marek Michalkiewicz + * + * Based on acquirewdt.c which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int advwdt_is_open; +static spinlock_t advwdt_lock; + +/* + * You must set these - there is no sane way to probe for this board. + * + * To enable or restart, write the timeout value in seconds (1 to 63) + * to I/O port WDT_START. To disable, read I/O port WDT_STOP. + * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but + * check your manual (at least the PCA-6159 seems to be different - + * the manual says WDT_STOP is 0x43, not 0x443). + * (0x43 is also a write-only control register for the 8254 timer!) + * + * TODO: module parameters to set the I/O port addresses and NOWAYOUT + * option at load time. + */ + +#define WDT_STOP 0x443 +#define WDT_START 0x443 + +#define WD_TIMO 60 /* 1 minute */ + +/* + * Kernel methods. + */ + +static void +advwdt_ping(void) +{ + /* Write a watchdog value */ + outb_p(WD_TIMO, WDT_START); +} + +static ssize_t +advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + advwdt_ping(); + return 1; + } + return 0; +} + +static ssize_t +advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static int +advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident = { + WDIOF_KEEPALIVEPING, 1, "Advantech WDT" + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *)arg, &advwdt_is_open, sizeof(int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + advwdt_ping(); + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int +advwdt_open(struct inode *inode, struct file *file) +{ + switch (MINOR(inode->i_rdev)) { + case WATCHDOG_MINOR: + spin_lock(&advwdt_lock); + if (advwdt_is_open) { + spin_unlock(&advwdt_lock); + return -EBUSY; + } + /* + * Activate + */ + + advwdt_is_open = 1; + advwdt_ping(); + spin_unlock(&advwdt_lock); + return 0; + default: + return -ENODEV; + } +} + +static int +advwdt_close(struct inode *inode, struct file *file) +{ + lock_kernel(); + if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { + spin_lock(&advwdt_lock); +#ifndef CONFIG_WATCHDOG_NOWAYOUT + inb_p(WDT_STOP); +#endif + advwdt_is_open = 0; + spin_unlock(&advwdt_lock); + } + unlock_kernel(); + return 0; +} + +/* + * Notifier for system down + */ + +static int +advwdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the WDT off */ + inb_p(WDT_STOP); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations advwdt_fops = { + owner: THIS_MODULE, + read: advwdt_read, + write: advwdt_write, + ioctl: advwdt_ioctl, + open: advwdt_open, + release: advwdt_close, +}; + +static struct miscdevice advwdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &advwdt_fops +}; + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block advwdt_notifier = { + advwdt_notify_sys, + NULL, + 0 +}; + +static int __init +advwdt_init(void) +{ + printk("WDT driver for Advantech single board computer initialising.\n"); + + spin_lock_init(&advwdt_lock); + misc_register(&advwdt_miscdev); +#if WDT_START != WDT_STOP + request_region(WDT_STOP, 1, "Advantech WDT"); +#endif + request_region(WDT_START, 1, "Advantech WDT"); + register_reboot_notifier(&advwdt_notifier); + return 0; +} + +static void __exit +advwdt_exit(void) +{ + misc_deregister(&advwdt_miscdev); + unregister_reboot_notifier(&advwdt_notifier); +#if WDT_START != WDT_STOP + release_region(WDT_STOP,1); +#endif + release_region(WDT_START,1); +} + +module_init(advwdt_init); +module_exit(advwdt_exit); + +/* end of advantechwdt.c */ diff -u --recursive --new-file v2.4.2/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c --- v2.4.2/linux/drivers/char/agp/agpgart_fe.c Wed Feb 21 18:20:19 2001 +++ linux/drivers/char/agp/agpgart_fe.c Tue Mar 6 19:28:32 2001 @@ -1105,7 +1105,8 @@ return 0; } -static void __exit agp_frontend_cleanup(void) +void __exit agp_frontend_cleanup(void) { misc_deregister(&agp_miscdev); } + diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/r128_drv.h linux/drivers/char/drm/r128_drv.h --- v2.4.2/linux/drivers/char/drm/r128_drv.h Thu Jan 4 13:03:20 2001 +++ linux/drivers/char/drm/r128_drv.h Fri Mar 2 18:38:37 2001 @@ -447,6 +447,11 @@ DRM_INFO( "ADVANCE_RING() tail=0x%06x wr=0x%06x\n", \ write, dev_priv->ring.tail ); \ } \ + if ( write < 32 ) { \ + memcpy( dev_priv->ring.end, \ + dev_priv->ring.start, \ + write * sizeof(u32) ); \ + } \ r128_flush_write_combine(); \ dev_priv->ring.tail = write; \ R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write ); \ diff -u --recursive --new-file v2.4.2/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c --- v2.4.2/linux/drivers/char/dsp56k.c Wed Feb 21 18:20:19 2001 +++ linux/drivers/char/dsp56k.c Fri Mar 2 18:38:37 2001 @@ -265,7 +265,7 @@ } default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); + printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); return -ENXIO; } } @@ -327,7 +327,7 @@ return -EFAULT; } default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); + printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); return -ENXIO; } } @@ -416,7 +416,7 @@ return 0; default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); + printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); return -ENXIO; } } @@ -469,7 +469,7 @@ break; default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); + printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); return -ENXIO; } @@ -490,7 +490,7 @@ break; default: - printk("DSP56k driver: Unknown minor device: %d\n", dev); + printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); return -ENXIO; } @@ -511,7 +511,9 @@ static devfs_handle_t devfs_handle; -int __init dsp56k_init(void) +static const char banner[] __initdata = KERN_INFO "DSP56k driver installed\n"; + +static int __init dsp56k_init_driver(void) { if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) { printk("DSP56k driver: Hardware not present\n"); @@ -522,27 +524,19 @@ printk("DSP56k driver: Unable to register driver\n"); return -ENODEV; } - devfs_handle = devfs_register (NULL, "dsp56k", DEVFS_FL_DEFAULT, - DSP56K_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, - &dsp56k_fops, NULL); - - dsp56k.in_use = 0; - - printk("DSP56k driver installed\n"); + devfs_handle = devfs_register(NULL, "dsp56k", DEVFS_FL_DEFAULT, + DSP56K_MAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR, + &dsp56k_fops, NULL); + printk(banner); return 0; } +module_init(dsp56k_init_driver); -#ifdef MODULE -int init_module(void) -{ - return dsp56k_init(); -} - -void cleanup_module(void) +static void __exit dsp56k_cleanup_driver(void) { devfs_unregister_chrdev(DSP56K_MAJOR, "dsp56k"); - devfs_unregister (devfs_handle); + devfs_unregister(devfs_handle); } -#endif /* MODULE */ +module_exit(dsp56k_cleanup_driver); diff -u --recursive --new-file v2.4.2/linux/drivers/char/dz.c linux/drivers/char/dz.c --- v2.4.2/linux/drivers/char/dz.c Wed Feb 21 18:20:19 2001 +++ linux/drivers/char/dz.c Fri Mar 2 18:38:37 2001 @@ -847,10 +847,12 @@ if (!new_info) return -EFAULT; - copy_from_user (&new_serial, new_info, sizeof(new_serial)); + if(copy_from_user (&new_serial, new_info, sizeof(new_serial))) + return -EFAULT; + old_info = *info; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (info->count > 1) diff -u --recursive --new-file v2.4.2/linux/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c --- v2.4.2/linux/drivers/char/i810_rng.c Wed Feb 21 18:20:19 2001 +++ linux/drivers/char/i810_rng.c Sat Mar 3 10:53:47 2001 @@ -1,8 +1,8 @@ /* Hardware driver for Intel i810 Random Number Generator (RNG) - Copyright 2000 Jeff Garzik - Copyright 2000 Philipp Rumpf + Copyright 2000,2001 Jeff Garzik + Copyright 2000,2001 Philipp Rumpf Driver Web site: http://sourceforge.net/projects/gkernel/ @@ -114,15 +114,13 @@ Minimum interval is 1 jiffy, maximum interval is 24 hours. * In order to unload the i810_rng module, you must first - disable the hardware via sysctl i810_hw_enabled, as shown above, + disable the hardware via sysctl i810_rng_timer, as shown above, and make sure all users of the character device have closed * The timer and the character device may be used simultaneously, if desired. - * FIXME: support poll() - - * FIXME: should we be crazy and support mmap()? + * FIXME: support poll(2) * FIXME: It is possible for the timer function to read, and shove into the kernel entropy pool, 2499 bytes of data @@ -135,11 +133,24 @@ * FIXME: module unload is racy. To fix this, struct ctl_table needs an owner member a la struct file_operations. + * FIXME: Timer interval should not be in jiffies, but in a more + user-understandable value like milliseconds. + * Since the RNG is accessed from a timer as well as normal kernel code, but not from interrupts, we use spin_lock_bh in regular code, and spin_lock in the timer function, to serialize access to the RNG hardware area. + NOTE: request_mem_region was removed, for two reasons: + 1) Only one RNG is supported by this driver, 2) The location + used by the RNG is a fixed location in MMIO-addressable memory, + 3) users with properly working BIOS e820 handling will always + have the region in which the RNG is located reserved, so + request_mem_region calls always fail for proper setups. + However, for people who use mem=XX, BIOS e820 information is + -not- in /proc/iomem, and request_mem_region(RNG_ADDR) can + succeed. + ---------------------------------------------------------- Change history: @@ -179,6 +190,19 @@ Version 0.9.2: * Simplify open blocking logic + Version 0.9.3: + * Clean up rng_read a bit. + * Update i810_rng driver Web site URL. + * Increase default timer interval to 4 samples per second. + * Abort if mem region is not available. + * BSS zero-initialization cleanup. + * Call misc_register() from rng_init_one. + * Fix O_NONBLOCK to occur before we schedule. + + Version 0.9.4: + * Fix: Remove request_mem_region + * Fix: Horrible bugs in FIPS calculation and test execution + */ @@ -202,7 +226,7 @@ /* * core module and version information */ -#define RNG_VERSION "0.9.2" +#define RNG_VERSION "0.9.4" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION #define PFX RNG_MODULE_NAME ": " @@ -211,7 +235,7 @@ /* * debugging macros */ -#undef RNG_DEBUG /* define to 1 to enable copious debugging info */ +#undef RNG_DEBUG /* define to enable copious debugging info */ #ifdef RNG_DEBUG /* note: prints function name for you */ @@ -220,8 +244,8 @@ #define DPRINTK(fmt, args...) #endif -#define RNG_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ -#if RNG_NDEBUG +#undef RNG_NDEBUG /* define to disable lightweight runtime checks */ +#ifdef RNG_NDEBUG #define assert(expr) #else #define assert(expr) \ @@ -249,6 +273,9 @@ #define RNG_DATA_PRESENT 0x01 #define RNG_DATA 2 +/* + * Magic address at which Intel PCI bridges locate the RNG + */ #define RNG_ADDR 0xFFBC015F #define RNG_ADDR_LEN 3 @@ -259,9 +286,9 @@ /* * Frequency that data is added to kernel entropy pool - * HZ>>1 == every half-second + * HZ>>1 == every quarter-second */ -#define RNG_DEF_TIMER_LEN (HZ >> 1) +#define RNG_DEF_TIMER_LEN (HZ >> 2) /* @@ -283,7 +310,6 @@ static unsigned int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ static unsigned int rng_entropy_sysctl; /* sysctl for changing entropy bits */ static unsigned int rng_interval_sysctl; /* sysctl for changing timer interval */ -static int rng_have_mem_region; /* did we grab RNG region via request_mem_region? */ static unsigned int rng_fips_counter; /* size of internal FIPS test data pool */ static unsigned int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */ static void *rng_mem; /* token to our ioremap'd RNG register area */ @@ -356,8 +382,11 @@ /* fitness testing via FIPS, if we have enough data */ rng_fips_test_store (rng_data); - if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD) + rng_fips_counter++; + if (rng_fips_counter == RNG_FIPS_TEST_THRESHOLD) { rng_run_fips_test (); + rng_fips_counter = 0; + } } else { spin_unlock (&rng_lock); } @@ -622,12 +651,10 @@ static int rng_dev_open (struct inode *inode, struct file *filp) { - int rc = -EINVAL; - if ((filp->f_mode & FMODE_READ) == 0) - return rc; + return -EINVAL; if (filp->f_mode & FMODE_WRITE) - return rc; + return -EINVAL; /* wait for device to become free */ if (filp->f_flags & O_NONBLOCK) { @@ -639,15 +666,11 @@ } if (rng_enable (1)) { - rc = -EIO; - goto err_out; + up (&rng_open_sem); + return -EIO; } return 0; - -err_out: - up (&rng_open_sem); - return rc; } @@ -686,20 +709,35 @@ ret++; } + if (filp->f_flags & O_NONBLOCK) + return ret ? : -EAGAIN; + if (current->need_resched) schedule (); if (signal_pending (current)) return ret ? : -ERESTARTSYS; - - if (filp->f_flags & O_NONBLOCK) - return ret ? : -EAGAIN; } return ret; } +static struct file_operations rng_chrdev_ops = { + owner: THIS_MODULE, + open: rng_dev_open, + release: rng_dev_release, + read: rng_dev_read, +}; + + +static struct miscdevice rng_miscdev = { + RNG_MISCDEV_MINOR, + RNG_MODULE_NAME, + &rng_chrdev_ops, +}; + + /* * rng_init_one - look for and attempt to init a single RNG */ @@ -713,16 +751,19 @@ if (pci_enable_device (dev)) return -EIO; - /* XXX currently fails, investigate who has our mem region */ - if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME)) - rng_have_mem_region = 1; + rc = misc_register (&rng_miscdev); + if (rc) { + printk (KERN_ERR PFX "cannot register misc device\n"); + DPRINTK ("EXIT, returning %d\n", rc); + goto err_out; + } rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN); if (rng_mem == NULL) { printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); DPRINTK ("EXIT, returning -EBUSY\n"); rc = -EBUSY; - goto err_out_free_res; + goto err_out_free_miscdev; } /* Check for Intel 82802 */ @@ -756,9 +797,9 @@ err_out_free_map: iounmap (rng_mem); -err_out_free_res: - if (rng_have_mem_region) - release_mem_region (RNG_ADDR, RNG_ADDR_LEN); +err_out_free_miscdev: + misc_deregister (&rng_miscdev); +err_out: return rc; } @@ -786,21 +827,6 @@ MODULE_PARM_DESC(rng_entropy, "Bits of entropy to add to random pool per RNG byte (range: 0-8, default 8)"); -static struct file_operations rng_chrdev_ops = { - owner: THIS_MODULE, - open: rng_dev_open, - release: rng_dev_release, - read: rng_dev_read, -}; - - -static struct miscdevice rng_miscdev = { - RNG_MISCDEV_MINOR, - RNG_MODULE_NAME, - &rng_chrdev_ops, -}; - - /* * rng_init - initialize RNG module */ @@ -826,15 +852,6 @@ if (rc) return rc; - rc = misc_register (&rng_miscdev); - if (rc) { - iounmap (rng_mem); - if (rng_have_mem_region) - release_mem_region (RNG_ADDR, RNG_ADDR_LEN); - DPRINTK ("EXIT, returning %d\n", rc); - return rc; - } - printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); rng_pdev = pdev; @@ -859,8 +876,8 @@ rng_sysctl (0); iounmap (rng_mem); - if (rng_have_mem_region) - release_mem_region (RNG_ADDR, RNG_ADDR_LEN); + + rng_pdev = NULL; DPRINTK ("EXIT\n"); } @@ -892,8 +909,8 @@ * random as random :) */ -static int poker[16] = { 0, }, runs[12] = { 0, }; -static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0; +static int poker[16], runs[12]; +static int ones, rlength = -1, current_bit, rng_test; /* @@ -927,7 +944,7 @@ /* Check if we just failed longrun test */ if (rlength >= 33) - rng_test &= 8; + rng_test |= 8; rlength = 0; /* flip the current run type */ last_bit = current_bit; @@ -955,16 +972,16 @@ else { runs[5 + (6 * current_bit)]++; if (rlength >= 33) - rng_test &= 8; + rng_test |= 8; } /* Ones test */ if ((ones >= 10346) || (ones <= 9654)) - rng_test &= 1; + rng_test |= 1; /* Poker calcs */ for (i = 0, j = 0; i < 16; i++) j += poker[i] * poker[i]; if ((j >= 1580457) || (j <= 1562821)) - rng_test &= 2; + rng_test |= 2; if ((runs[0] < 2267) || (runs[0] > 2733) || (runs[1] < 1079) || (runs[1] > 1421) || (runs[2] < 502) || (runs[2] > 748) || @@ -977,7 +994,7 @@ (runs[9] < 223) || (runs[9] > 402) || (runs[10] < 90) || (runs[10] > 223) || (runs[11] < 90) || (runs[11] > 223)) { - rng_test &= 4; + rng_test |= 4; } rng_test = !rng_test; diff -u --recursive --new-file v2.4.2/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.4.2/linux/drivers/char/istallion.c Wed Feb 21 18:20:19 2001 +++ linux/drivers/char/istallion.c Fri Mar 2 11:12:07 2001 @@ -213,12 +213,8 @@ * at 9600 baud, 8 data bits, no parity, 1 stop bit. */ static struct termios stli_deftermios = { - 0, - 0, - (B9600 | CS8 | CREAD | HUPCL | CLOCAL), - 0, - 0, - INIT_C_CC + c_cflag: (B9600 | CS8 | CREAD | HUPCL | CLOCAL), + c_cc: INIT_C_CC, }; /* diff -u --recursive --new-file v2.4.2/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.4.2/linux/drivers/char/lp.c Wed Feb 21 18:20:20 2001 +++ linux/drivers/char/lp.c Fri Mar 2 18:43:11 2001 @@ -500,7 +500,7 @@ if (copy_to_user((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats))) return -EFAULT; - if (suser()) + if (capable(CAP_SYS_ADMIN)) memset(&LP_STAT(minor), 0, sizeof(struct lp_stats)); break; diff -u --recursive --new-file v2.4.2/linux/drivers/char/machzwd.c linux/drivers/char/machzwd.c --- v2.4.2/linux/drivers/char/machzwd.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/machzwd.c Tue Mar 6 19:44:34 2001 @@ -0,0 +1,545 @@ +/* + * MachZ ZF-Logic Watchdog Timer driver for Linux + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author does NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * Author: Fernando Fuganti + * + * Based on sbc60xxwdt.c by Jakob Oestergaard + * + * + * We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the + * following periods: + * wd#1 - 2 seconds; + * wd#2 - 7.2 ms; + * After the expiration of wd#1, it can generate a NMI, SCI, SMI, or + * a system RESET and it starts wd#2 that unconditionaly will RESET + * the system when the counter reaches zero. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* ports */ +#define ZF_IOBASE 0x218 +#define INDEX 0x218 +#define DATA_B 0x219 +#define DATA_W 0x21A +#define DATA_D 0x21A + +/* indexes */ /* size */ +#define ZFL_VERSION 0x02 /* 16 */ +#define CONTROL 0x10 /* 16 */ +#define STATUS 0x12 /* 8 */ +#define COUNTER_1 0x0C /* 16 */ +#define COUNTER_2 0x0E /* 8 */ +#define PULSE_LEN 0x0F /* 8 */ + +/* controls */ +#define ENABLE_WD1 0x0001 +#define ENABLE_WD2 0x0002 +#define RESET_WD1 0x0010 +#define RESET_WD2 0x0020 +#define GEN_SCI 0x0100 +#define GEN_NMI 0x0200 +#define GEN_SMI 0x0400 +#define GEN_RESET 0x0800 + + +/* utilities */ + +#define WD1 0 +#define WD2 1 + +#define zf_writew(port, data) { outb(port, INDEX); outw(data, DATA_W); } +#define zf_writeb(port, data) { outb(port, INDEX); outb(data, DATA_B); } +#define zf_get_ZFL_version() zf_readw(ZFL_VERSION) + + +static unsigned short zf_readw(unsigned char port) +{ + outb(port, INDEX); + return inw(DATA_W); +} + +static unsigned short zf_readb(unsigned char port) +{ + outb(port, INDEX); + return inb(DATA_B); +} + + +MODULE_AUTHOR("Fernando Fuganti "); +MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver"); +MODULE_PARM(action, "i"); +MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); + +#define PFX "machzwd" + +static struct watchdog_info zf_info = { + options: WDIOF_KEEPALIVEPING, + firmware_version: 1, + identity: "ZF-Logic watchdog" +}; + + +/* + * action refers to action taken when watchdog resets + * 0 = GEN_RESET + * 1 = GEN_SMI + * 2 = GEN_NMI + * 3 = GEN_SCI + * defaults to GEN_RESET (0) + */ +static int action = 0; +static int zf_action = GEN_RESET; +static int zf_is_open = 0; +static int zf_expect_close = 0; +static spinlock_t zf_lock; +static struct timer_list zf_timer; +static unsigned long next_heartbeat = 0; + + +/* timeout for user land heart beat (10 seconds) */ +#define ZF_USER_TIMEO (HZ*10) + +/* timeout for hardware watchdog (~500ms) */ +#define ZF_HW_TIMEO (HZ/2) + +/* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */ +#define ZF_CTIMEOUT 0xffff + +#ifndef ZF_DEBUG +# define dprintk(format, args...) +#else +# define dprintk(format, args...) printk(KERN_DEBUG PFX ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args) +#endif + + +/* STATUS register functions */ + +static inline unsigned char zf_get_status(void) +{ + return zf_readb(STATUS); +} + +static inline void zf_set_status(unsigned char new) +{ + zf_writeb(STATUS, new); +} + + +/* CONTROL register functions */ + +static inline unsigned short zf_get_control(void) +{ + return zf_readw(CONTROL); +} + +static inline void zf_set_control(unsigned short new) +{ + zf_writew(CONTROL, new); +} + + +/* WD#? counter functions */ +/* + * Just get current counter value + */ + +inline unsigned short zf_get_timer(unsigned char n) +{ + switch(n){ + case WD1: + return zf_readw(COUNTER_1); + case WD2: + return zf_readb(COUNTER_2); + default: + return 0; + } +} + +/* + * Just set counter value + */ + +static inline void zf_set_timer(unsigned short new, unsigned char n) +{ + switch(n){ + case WD1: + zf_writew(COUNTER_1, new); + case WD2: + zf_writeb(COUNTER_2, new > 0xff ? 0xff : new); + default: + return; + } +} + +/* + * stop hardware timer + */ +static void zf_timer_off(void) +{ + unsigned int ctrl_reg = 0; + + /* stop internal ping */ + del_timer(&zf_timer); + + /* stop watchdog timer */ + ctrl_reg = zf_get_control(); + ctrl_reg |= (ENABLE_WD1|ENABLE_WD2); /* disable wd1 and wd2 */ + ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2); + zf_set_control(ctrl_reg); + + printk(PFX ": Watchdog timer is now disabled\n"); +} + + +/* + * start hardware timer + */ +static void zf_timer_on(void) +{ + unsigned int ctrl_reg = 0; + + zf_writeb(PULSE_LEN, 0xff); + + zf_set_timer(ZF_CTIMEOUT, WD1); + + /* user land ping */ + next_heartbeat = jiffies + ZF_USER_TIMEO; + + /* start the timer for internal ping */ + zf_timer.expires = jiffies + ZF_HW_TIMEO; + + add_timer(&zf_timer); + + /* start watchdog timer */ + ctrl_reg = zf_get_control(); + ctrl_reg |= (ENABLE_WD1|zf_action); + zf_set_control(ctrl_reg); + + printk(PFX ": Watchdog timer is now enabled\n"); +} + + +static void zf_ping(unsigned long data) +{ + unsigned int ctrl_reg = 0; + + zf_writeb(COUNTER_2, 0xff); + + if(time_before(jiffies, next_heartbeat)){ + + dprintk("time_before: %ld\n", next_heartbeat - jiffies); + + /* + * reset event is activated by transition from 0 to 1 on + * RESET_WD1 bit and we assume that it is already zero... + */ + ctrl_reg = zf_get_control(); + ctrl_reg |= RESET_WD1; + zf_set_control(ctrl_reg); + + /* ...and nothing changes until here */ + ctrl_reg &= ~(RESET_WD1); + zf_set_control(ctrl_reg); + + zf_timer.expires = jiffies + ZF_HW_TIMEO; + add_timer(&zf_timer); + }else{ + printk(PFX ": I will reset your machine\n"); + } +} + +static ssize_t zf_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count){ + +/* + * no need to check for close confirmation + * no way to disable watchdog ;) + */ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + size_t ofs; + + /* + * note: just in case someone wrote the magic character + * five months ago... + */ + zf_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++){ + if(buf[ofs] == 'V'){ + zf_expect_close = 1; + dprintk("zf_expect_close 1\n"); + } + } +#endif + /* + * Well, anyhow someone wrote to us, + * we should return that favour + */ + next_heartbeat = jiffies + ZF_USER_TIMEO; + dprintk("user ping at %ld\n", jiffies); + + return 1; + } + + return 0; +} + +static ssize_t zf_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + return -EINVAL; +} + + + +static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + + switch(cmd){ + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info *)arg, + &zf_info, sizeof(zf_info)); + if(ret) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + ret = copy_to_user((int *)arg, &zf_is_open, + sizeof(int)); + if(ret) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + zf_ping(0); + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static int zf_open(struct inode *inode, struct file *file) +{ + switch(MINOR(inode->i_rdev)){ + case WATCHDOG_MINOR: + spin_lock(&zf_lock); + if(zf_is_open){ + spin_unlock(&zf_lock); + return -EBUSY; + } + +#ifdef CONFIG_WATCHDOG_NOWAYOUT + MOD_INC_USE_COUNT; +#endif + zf_is_open = 1; + + spin_unlock(&zf_lock); + + zf_timer_on(); + + return 0; + default: + return -ENODEV; + } +} + +static int zf_close(struct inode *inode, struct file *file) +{ + if(MINOR(inode->i_rdev) == WATCHDOG_MINOR){ + + if(zf_expect_close){ + zf_timer_off(); + } else { + del_timer(&zf_timer); + printk(PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + + spin_lock(&zf_lock); + zf_is_open = 0; + spin_unlock(&zf_lock); + + zf_expect_close = 0; + } + + return 0; +} + +/* + * Notifier for system down + */ + +static int zf_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code == SYS_DOWN || code == SYS_HALT){ + zf_timer_off(); + } + + return NOTIFY_DONE; +} + + + + +static struct file_operations zf_fops = { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,34) + owner: THIS_MODULE, +#endif + read: zf_read, + write: zf_write, + ioctl: zf_ioctl, + open: zf_open, + release: zf_close, +}; + +static struct miscdevice zf_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &zf_fops +}; + + +/* + * The device needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ +static struct notifier_block zf_notifier = { + zf_notify_sys, + NULL, + 0 +}; + +static void __init zf_show_action(int act) +{ + char *str[] = { "RESET", "SMI", "NMI", "SCI" }; + + printk(PFX ": Watchdog using action = %s\n", str[act]); +} + +int __init zf_init(void) +{ + int ret; + + printk(PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); + + ret = zf_get_ZFL_version(); + printk("%#x\n", ret); + if((!ret) || (ret != 0xffff)){ + printk(PFX ": no ZF-Logic found\n"); + return -ENODEV; + } + + if((action <= 3) && (action >= 0)){ + zf_action = zf_action>>action; + } else + action = 0; + + zf_show_action(action); + + spin_lock_init(&zf_lock); + + ret = misc_register(&zf_miscdev); + if (ret){ + printk(KERN_ERR "can't misc_register on minor=%d\n", + WATCHDOG_MINOR); + goto out; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3) + if(check_region(ZF_IOBASE, 3)){ +#else + if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ +#endif + + printk(KERN_ERR "cannot reserve I/O ports at %d\n", + ZF_IOBASE); + ret = -EBUSY; + goto no_region; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3) + request_region(ZF_IOBASE, 3, "MachZ ZFL WDT"); +#define __exit +#endif + + ret = register_reboot_notifier(&zf_notifier); + if(ret){ + printk(KERN_ERR "can't register reboot notifier (err=%d)\n", + ret); + goto no_reboot; + } + + zf_set_status(0); + zf_set_control(0); + + /* this is the timer that will do the hard work */ + init_timer(&zf_timer); + zf_timer.function = zf_ping; + zf_timer.data = 0; + + return 0; + +no_reboot: + release_region(ZF_IOBASE, 3); +no_region: + misc_deregister(&zf_miscdev); +out: + return ret; +} + + +void __exit zf_exit(void) +{ + zf_timer_off(); + + misc_deregister(&zf_miscdev); + unregister_reboot_notifier(&zf_notifier); + release_region(ZF_IOBASE, 3); +} + +module_init(zf_init); +module_exit(zf_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.4.2/linux/drivers/char/mem.c Wed Feb 21 18:20:20 2001 +++ linux/drivers/char/mem.c Fri Mar 2 18:38:37 2001 @@ -642,6 +642,9 @@ #ifdef CONFIG_FTAPE ftape_init(); #endif +#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) + tapechar_init(); +#endif #if defined(CONFIG_ADB) adbdev_init(); #endif diff -u --recursive --new-file v2.4.2/linux/drivers/char/mxser.c linux/drivers/char/mxser.c --- v2.4.2/linux/drivers/char/mxser.c Wed Dec 6 12:06:18 2000 +++ linux/drivers/char/mxser.c Fri Mar 2 11:12:07 2001 @@ -120,7 +120,7 @@ #define CI104J_ASIC_ID 5 enum { - MXSER_BOARD_C168_ISA = 0, + MXSER_BOARD_C168_ISA = 1, MXSER_BOARD_C104_ISA, MXSER_BOARD_CI104J, MXSER_BOARD_C168_PCI, @@ -617,16 +617,18 @@ pdev = pci_find_device(mxser_pcibrds[b].vendor_id, mxser_pcibrds[b].device_id, pdev); if (!pdev) - break; + { + b++; + continue; + } if (pci_enable_device(pdev)) continue; - b++; hwconf.pdev = pdev; printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[mxser_pcibrds[b].board_type - 1], pdev->bus->number, PCI_SLOT(pdev->devfn >> 3)); if (m >= MXSER_BOARDS) { - printk("Too many Smartio family boards find (maximum %d),board not configured\n", MXSER_BOARDS); + printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS); } else { retval = mxser_get_PCI_conf(pdev, mxser_pcibrds[b].board_type, &hwconf); @@ -1457,7 +1459,9 @@ if (info->xmit_cnt < WAKEUP_CHARS) { set_bit(MXSER_EVENT_TXLOW, &info->event); - schedule_task(&info->tqueue); + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue) == 0) + MOD_DEC_USE_COUNT; } if (info->xmit_cnt <= 0) { info->IER &= ~UART_IER_THRI; @@ -1486,8 +1490,9 @@ else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_CALLOUT_NOHUP))) set_bit(MXSER_EVENT_HANGUP, &info->event); - schedule_task(&info->tqueue); - + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue) == 0) + MOD_DEC_USE_COUNT; } if (info->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { @@ -1671,7 +1676,7 @@ */ if (inb(info->base + UART_LSR) == 0xff) { restore_flags(flags); - if (suser()) { + if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); return (0); @@ -2188,8 +2193,7 @@ status = inb(info->base + UART_LSR); restore_flags(flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - put_user(result, value); - return (0); + return put_user(result, value); } /* @@ -2229,8 +2233,7 @@ ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - put_user(result, value); - return (0); + return put_user(result, value); } static int mxser_set_modem_info(struct mxser_struct *info, unsigned int cmd, diff -u --recursive --new-file v2.4.2/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.4.2/linux/drivers/char/pc_keyb.c Wed Feb 21 18:20:20 2001 +++ linux/drivers/char/pc_keyb.c Fri Mar 2 18:38:37 2001 @@ -908,6 +908,8 @@ controller. */ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ + + mdelay(2); /* Ensure we follow the kbc access delay rules.. */ send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ diff -u --recursive --new-file v2.4.2/linux/drivers/char/pcmcia/Config.in linux/drivers/char/pcmcia/Config.in --- v2.4.2/linux/drivers/char/pcmcia/Config.in Tue Jul 11 19:02:37 2000 +++ linux/drivers/char/pcmcia/Config.in Tue Mar 6 19:28:35 2001 @@ -2,29 +2,13 @@ # PCMCIA character device configuration # -if [ "$CONFIG_SERIAL" = "n" ]; then - define_tristate CONFIG_PCMCIA_SERIAL n -else - if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_PCMCIA" = "m" ]; then - define_tristate CONFIG_PCMCIA_SERIAL m - else - define_tristate CONFIG_PCMCIA_SERIAL y - fi -fi - -if [ "$CONFIG_PCMCIA_SERIAL" != "n" ]; then - mainmenu_option next_comment - comment 'PCMCIA character device support' +mainmenu_option next_comment +comment 'PCMCIA character devices' - dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA_SERIAL - if [ "$CONFIG_CARDBUS" = "y" ]; then - dep_tristate 'CardBus serial device support' CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA_SERIAL - fi +dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_SERIAL +if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" ]; then + define_bool CONFIG_PCMCIA_CHRDEV y +fi - if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" -o \ - "$CONFIG_PCMCIA_SERIAL_CB" = "y" ]; then - define_bool CONFIG_PCMCIA_CHRDEV y - fi +endmenu - endmenu -fi diff -u --recursive --new-file v2.4.2/linux/drivers/char/pcmcia/Makefile linux/drivers/char/pcmcia/Makefile --- v2.4.2/linux/drivers/char/pcmcia/Makefile Fri Dec 29 14:07:21 2000 +++ linux/drivers/char/pcmcia/Makefile Tue Mar 6 19:28:35 2001 @@ -16,6 +16,5 @@ obj- := obj-$(CONFIG_PCMCIA_SERIAL_CS) += serial_cs.o -obj-$(CONFIG_PCMCIA_SERIAL_CB) += serial_cb.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.2/linux/drivers/char/pcmcia/serial_cb.c linux/drivers/char/pcmcia/serial_cb.c --- v2.4.2/linux/drivers/char/pcmcia/serial_cb.c Wed Feb 21 18:20:20 2001 +++ linux/drivers/char/pcmcia/serial_cb.c Wed Dec 31 16:00:00 1969 @@ -1,163 +0,0 @@ -/*====================================================================== - - A driver for CardBus serial devices - - serial_cb.c 1.20 2000/08/07 19:02:03 - - Copyright 1998, 1999 by Donald Becker and David Hinds - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - All other rights reserved. - - This driver is an activator for CardBus serial cards, as - found on multifunction (e.g. Ethernet and Modem) CardBus cards. - - Donald Becker may be reached as becker@CESDIS.edu, or C/O - USRA Center of Excellence in Space Data and Information Sciences - Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771 - David Hinds may be reached at dahinds@users.sourceforge.net - -======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"serial_cb.c 1.20 2000/08/07 19:02:03 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================== - - Card-specific configuration hacks - -======================================================================*/ - -static void device_setup(struct pci_dev *pdev, u_int ioaddr) -{ - u_short a, b; - - a = pdev->subsystem_vendor; - b = pdev->subsystem_device; - if (((a == 0x13a2) && (b == 0x8007)) || - ((a == 0x1420) && (b == 0x8003))) { - /* Ositech, Psion 83c175-based cards */ - DEBUG(0, " 83c175 NVCTL_m = 0x%4.4x.\n", inl(ioaddr+0x80)); - outl(0x4C00, ioaddr + 0x80); - outl(0x4C80, ioaddr + 0x80); - } - DEBUG(0, " modem registers are %2.2x %2.2x %2.2x " - "%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x.\n", - inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2), - inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5), - inb(ioaddr + 6), inb(ioaddr + 7), inb(ioaddr + 8)); -} - -/*====================================================================== - - serial_attach() creates a serial device "instance" and registers - it with the kernel serial driver, and serial_detach() unregisters - an instance. - -======================================================================*/ - -static dev_node_t *serial_attach(dev_locator_t *loc) -{ - u_int io; - u_char irq; - int line; - struct serial_struct serial; - struct pci_dev *pdev; - dev_node_t *node; - - MOD_INC_USE_COUNT; - - if (loc->bus != LOC_PCI) goto err_out; - pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); - if (!pdev) goto err_out; - if (pci_enable_device(pdev)) goto err_out; - - printk(KERN_INFO "serial_attach(bus %d, fn %d)\n", pdev->bus->number, pdev->devfn); - io = pci_resource_start (pdev, 0); - irq = pdev->irq; - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) { - printk(KERN_NOTICE "serial_cb: PCI base address 0 is not IO\n"); - goto err_out; - } - device_setup(pdev, io); - memset(&serial, 0, sizeof(serial)); - serial.port = io; serial.irq = irq; - serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; - - /* Some devices seem to need extra time */ - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/50); - - line = register_serial(&serial); - if (line < 0) { - printk(KERN_NOTICE "serial_cb: register_serial() at 0x%04x, " - "irq %d failed\n", serial.port, serial.irq); - goto err_out; - } - - node = kmalloc(sizeof(dev_node_t), GFP_KERNEL); - if (!node) - goto err_out_unregister; - sprintf(node->dev_name, "ttyS%d", line); - node->major = TTY_MAJOR; node->minor = 0x40 + line; - node->next = NULL; - return node; - -err_out_unregister: - unregister_serial(line); -err_out: - MOD_DEC_USE_COUNT; - return NULL; -} - -static void serial_detach(dev_node_t *node) -{ - DEBUG(0, "serial_detach(ttyS%02d)\n", node->minor - 0x40); - unregister_serial(node->minor - 0x40); - kfree(node); - MOD_DEC_USE_COUNT; -} - -/*====================================================================*/ - -struct driver_operations serial_ops = { - "serial_cb", serial_attach, NULL, NULL, serial_detach -}; - -static int __init init_serial_cb(void) -{ - DEBUG(0, "%s\n", version); - register_driver(&serial_ops); - return 0; -} - -static void __exit exit_serial_cb(void) -{ - DEBUG(0, "serial_cb: unloading\n"); - unregister_driver(&serial_ops); -} - -module_init(init_serial_cb); -module_exit(exit_serial_cb); diff -u --recursive --new-file v2.4.2/linux/drivers/char/rocket.c linux/drivers/char/rocket.c --- v2.4.2/linux/drivers/char/rocket.c Wed Feb 21 18:20:20 2001 +++ linux/drivers/char/rocket.c Tue Mar 6 19:44:34 2001 @@ -47,19 +47,6 @@ #endif #define NEW_MODULES -#ifdef LOCAL_ROCKET_H /* We're building standalone */ -#define MODULE -#endif - -#if defined(NEW_MODULES) && defined(LOCAL_ROCKET_H) -#ifdef MODVERSIONS -#include -#endif -#else /* !NEW_MODULES */ -#ifdef MODVERSIONS -#define MODULE -#endif -#endif /* NEW_MODULES */ #include #include diff -u --recursive --new-file v2.4.2/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.4.2/linux/drivers/char/serial.c Wed Feb 21 18:20:20 2001 +++ linux/drivers/char/serial.c Tue Mar 6 20:13:51 2001 @@ -54,16 +54,13 @@ * 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT. * Arnaldo Carvalho de Melo * - * 10/00: add in optional hardware flow control for serial console. - * Kanoj Sarcar + * 10/00: add in optional software flow control for serial console. + * Kanoj Sarcar (Modified by Theodore Ts'o) * - * This module exports the following rs232 io functions: - * - * int rs_init(void); */ -static char *serial_version = "5.02"; -static char *serial_revdate = "2000-08-09"; +static char *serial_version = "5.05"; +static char *serial_revdate = "2000-12-13"; /* * Serial driver configuration section. Here are the various options: @@ -191,7 +188,7 @@ #include #include #include -#include +#include #if (LINUX_VERSION_CODE >= 131343) #include #endif @@ -325,7 +322,6 @@ #define NR_PCI_BOARDS 8 static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; -static int serial_pci_board_idx; #ifndef IS_PCI_REGION_IOPORT #define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \ @@ -564,8 +560,8 @@ { struct tty_struct *tty = info->tty; unsigned char ch; - int ignored = 0; struct async_icount *icount; + int max_count = 256; icount = &info->state->icount; do { @@ -612,15 +608,8 @@ icount->overrun++; /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. + * Mask off conditions which should be ignored. */ - if (*status & info->ignore_status_mask) { - if (++ignored > 100) - break; - goto ignore_char; - } *status &= info->read_status_mask; #ifdef CONFIG_SERIAL_CONSOLE @@ -639,19 +628,6 @@ *tty->flip.flag_buf_ptr = TTY_PARITY; else if (*status & UART_LSR_FE) *tty->flip.flag_buf_ptr = TTY_FRAME; - if (*status & UART_LSR_OE) { - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto ignore_char; - } } #if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) if (break_pressed && info->line == sercons.index) { @@ -664,16 +640,30 @@ break_pressed = 0; } #endif - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; + if ((*status & info->ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((*status & UART_LSR_OE) && + (tty->flip.count < TTY_FLIPBUF_SIZE)) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + } ignore_char: *status = serial_inp(info, UART_LSR); - } while (*status & UART_LSR_DR); + } while ((*status & UART_LSR_DR) && (max_count-- > 0)); #if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ tty_flip_buffer_push(tty); #else - queue_task(&tty->flip.tqueue, &tq_timer); + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); #endif } @@ -827,6 +817,9 @@ end_mark = info; goto next; } +#ifdef SERIAL_DEBUG_INTR + printk("IIR = %x...", serial_in(info, UART_IIR)); +#endif end_mark = 0; info->last_active = jiffies; @@ -910,6 +903,9 @@ #endif break; } +#ifdef SERIAL_DEBUG_INTR + printk("IIR = %x...", serial_in(info, UART_IIR)); +#endif } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); info->last_active = jiffies; #ifdef CONFIG_SERIAL_MULTIPORT @@ -1310,7 +1306,7 @@ */ if (!(info->flags & ASYNC_BUGGY_UART) && (serial_inp(info, UART_LSR) == 0xff)) { - printk("LSR safety check engaged!\n"); + printk("ttyS%d: LSR safety check engaged!\n", state->line); if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1554,7 +1550,10 @@ /* Arrange to enter sleep mode */ serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_LCR, 0); serial_outp(info, UART_IER, UART_IERX_SLEEP); + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, 0); serial_outp(info, UART_LCR, 0); } if (info->state->type == PORT_16750) { @@ -2906,7 +2905,6 @@ if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } - set_current_state(TASK_RUNNING); #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); #endif @@ -3254,6 +3252,10 @@ info->magic = SERIAL_MAGIC; info->port = state->port; info->flags = state->flags; + info->hub6 = state->hub6; + info->io_type = state->io_type; + info->iomem_base = state->iomem_base; + info->iomem_reg_shift = state->iomem_reg_shift; info->quot = 0; info->tty = 0; } @@ -3809,7 +3811,7 @@ #if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) -static void __init printk_pnp_dev_id(unsigned short vendor, +static void __devinit printk_pnp_dev_id(unsigned short vendor, unsigned short device) { printk("%c%c%c%x%x%x%x", @@ -3901,7 +3903,7 @@ /* * Common enabler code shared by both PCI and ISAPNP probes */ -static void __init start_pci_pnp_board(struct pci_dev *dev, +static void __devinit start_pci_pnp_board(struct pci_dev *dev, struct pci_board *board) { int k, line; @@ -3933,19 +3935,19 @@ if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0)) return; -#ifdef MODULE /* * Register the serial board in the array if we need to - * shutdown the board on a module unload. + * shutdown the board on a module unload or card removal */ if (DEACTIVATE_FUNC(dev) || board->init_fn) { - if (serial_pci_board_idx >= NR_PCI_BOARDS) + for (k=0; k < NR_PCI_BOARDS; k++) + if (serial_pci_board[k].dev == 0) + break; + if (k >= NR_PCI_BOARDS) return; - serial_pci_board[serial_pci_board_idx].board = *board; - serial_pci_board[serial_pci_board_idx].dev = dev; - serial_pci_board_idx++; + serial_pci_board[k].board = *board; + serial_pci_board[k].dev = dev; } -#endif base_baud = board->base_baud; if (!base_baud) @@ -3965,6 +3967,7 @@ if (line < 0) break; rs_table[line].baud_base = base_baud; + rs_table[line].dev = dev; } } #endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */ @@ -3978,7 +3981,7 @@ */ static int #ifndef MODULE -__init +__devinit #endif pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) { @@ -4045,7 +4048,7 @@ static int #ifndef MODULE -__init +__devinit #endif pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) { @@ -4077,7 +4080,7 @@ static int #ifndef MODULE -__init +__devinit #endif pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) { @@ -4101,7 +4104,7 @@ /* Added for EKF Intel i960 serial boards */ static int #ifndef MODULE -__init +__devinit #endif pci_inteli960ni_fn(struct pci_dev *dev, struct pci_board *board, @@ -4162,7 +4165,7 @@ static int #ifndef MODULE -__init +__devinit #endif pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) { @@ -4577,6 +4580,12 @@ SPCI_FL_BASE0, 1, 520833, 64, 3, NULL, 0x300 }, #endif +#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ + { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE3, 8, 115200, + 8 }, +#endif /* Generic serial board */ { 0, 0, 0, 0, @@ -4626,6 +4635,90 @@ return 1; } +static int __devinit serial_init_one(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + struct pci_board *board, tmp; + + for (board = pci_boards; board->vendor; board++) { + if (board->vendor != (unsigned short) PCI_ANY_ID && + dev->vendor != board->vendor) + continue; + if (board->device != (unsigned short) PCI_ANY_ID && + dev->device != board->device) + continue; + if (board->subvendor != (unsigned short) PCI_ANY_ID && + pci_get_subvendor(dev) != board->subvendor) + continue; + if (board->subdevice != (unsigned short) PCI_ANY_ID && + pci_get_subdevice(dev) != board->subdevice) + continue; + break; + } + + if (board->vendor == 0 && serial_pci_guess_board(dev, board)) + return -ENODEV; + else if (serial_pci_guess_board(dev, &tmp) == 0) { + printk(KERN_INFO "Redundant entry in serial pci_table. " + "Please send the output of\n" + "lspci -vv, this message (%d,%d,%d,%d)\n" + "and the manufacturer and name of " + "serial board or modem board\n" + "to serial-pci-info@lists.sourceforge.net.\n", + dev->vendor, dev->device, + pci_get_subvendor(dev), pci_get_subdevice(dev)); + } + + start_pci_pnp_board(dev, board); + + return 0; +} + +static void __devexit serial_remove_one(struct pci_dev *dev) +{ + int i; + + /* + * Iterate through all of the ports finding those that belong + * to this PCI device. + */ + for(i = 0; i < NR_PORTS; i++) { + if (rs_table[i].dev != dev) + continue; + unregister_serial(i); + rs_table[i].dev = 0; + } + /* + * Now execute any board-specific shutdown procedure + */ + for (i=0; i < NR_PCI_BOARDS; i++) { + struct pci_board_inst *brd = &serial_pci_board[i]; + + if (serial_pci_board[i].dev != dev) + continue; + if (brd->board.init_fn) + (brd->board.init_fn)(brd->dev, &brd->board, 0); + if (DEACTIVATE_FUNC(brd->dev)) + (DEACTIVATE_FUNC(brd->dev))(brd->dev); + serial_pci_board[i].dev = 0; + } +} + + +static struct pci_device_id serial_pci_tbl[] __devinitdata = { + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, serial_pci_tbl); + +static struct pci_driver serial_pci_driver = { + name: "serial", + probe: serial_init_one, + remove: serial_remove_one, + id_table: serial_pci_tbl, +}; /* @@ -4635,38 +4728,19 @@ * Accept a maximum of eight boards * */ -static void __init probe_serial_pci(void) +static void __devinit probe_serial_pci(void) { - struct pci_dev *dev = NULL; - struct pci_board *board; - #ifdef SERIAL_DEBUG_PCI printk(KERN_DEBUG "Entered probe_serial_pci()\n"); #endif - - pci_for_each_dev(dev) { - for (board = pci_boards; board->vendor; board++) { - if (board->vendor != (unsigned short) PCI_ANY_ID && - dev->vendor != board->vendor) - continue; - if (board->device != (unsigned short) PCI_ANY_ID && - dev->device != board->device) - continue; - if (board->subvendor != (unsigned short) PCI_ANY_ID && - pci_get_subvendor(dev) != board->subvendor) - continue; - if (board->subdevice != (unsigned short) PCI_ANY_ID && - pci_get_subdevice(dev) != board->subdevice) - continue; - break; - } - - if (board->vendor == 0 && serial_pci_guess_board(dev, board)) - continue; - - start_pci_pnp_board(dev, board); - } - + + /* Register call PCI serial devices. Null out + * the driver name upon failure, as a signal + * not to attempt to unregister the driver later + */ + if (pci_module_init (&serial_pci_driver) != 0) + serial_pci_driver.name[0] = 0; + #ifdef SERIAL_DEBUG_PCI printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n"); #endif @@ -4682,7 +4756,7 @@ unsigned short device; }; -static struct pnp_board pnp_devices[] __initdata = { +static struct pnp_board pnp_devices[] __devinitdata = { /* Archtek America Corp. */ /* Archtek SmartLink Modem 3334BT Plug & Play */ { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, @@ -4972,14 +5046,14 @@ irq->map = map; } -static char *modem_names[] __initdata = { +static char *modem_names[] __devinitdata = { "MODEM", "Modem", "modem", "FAX", "Fax", "fax", "56K", "56k", "K56", "33.6", "28.8", "14.4", "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", "33600", "28800", "14400", "V.90", "V.34", "V.32", 0 }; -static int __init check_name(char *name) +static int __devinit check_name(char *name) { char **tmp = modem_names; @@ -5041,7 +5115,7 @@ return 1; } -static void __init probe_serial_pnp(void) +static void __devinit probe_serial_pnp(void) { struct pci_dev *dev = NULL; struct pnp_board *pnp_board; @@ -5252,7 +5326,7 @@ } /* - * This is for use by architectures that know their serial port + * This is for use by architectures that know their serial console * attributes only at run time. Not to be invoked after rs_init(). */ int __init early_serial_setup(struct serial_struct *req) @@ -5318,6 +5392,14 @@ (rs_table[i].iomem_base == req->iomem_base)) break; } +#ifdef __i386__ + if (i == NR_PORTS) { + for (i = 4; i < NR_PORTS; i++) + if ((rs_table[i].type == PORT_UNKNOWN) && + (rs_table[i].count == 0)) + break; + } +#endif if (i == NR_PORTS) { for (i = 0; i < NR_PORTS; i++) if ((rs_table[i].type == PORT_UNKNOWN) && @@ -5441,12 +5523,13 @@ #endif } #if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) - for (i=0; i < serial_pci_board_idx; i++) { + for (i=0; i < NR_PCI_BOARDS; i++) { struct pci_board_inst *brd = &serial_pci_board[i]; - + + if (serial_pci_board[i].dev == 0) + continue; if (brd->board.init_fn) (brd->board.init_fn)(brd->dev, &brd->board, 0); - if (DEACTIVATE_FUNC(brd->dev)) (DEACTIVATE_FUNC(brd->dev))(brd->dev); } @@ -5456,6 +5539,11 @@ tmp_buf = NULL; free_page(pg); } + +#ifdef ENABLE_SERIAL_PCI + if (serial_pci_driver.name[0]) + pci_unregister_driver (&serial_pci_driver); +#endif } module_init(rs_init); @@ -5491,10 +5579,13 @@ if (--tmout == 0) break; } while((status & BOTH_EMPTY) != BOTH_EMPTY); - if (info->flags & ASYNC_NO_FLOW) - return; - tmout = 1000000; - while (--tmout && ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0)); + + /* Wait for flow control if necessary */ + if (info->flags & ASYNC_CONS_FLOW) { + tmout = 1000000; + while (--tmout && + ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0)); + } } @@ -5577,7 +5668,7 @@ } /* - * Setup initial baud/bits/parity/flow. We do two things here: + * Setup initial baud/bits/parity/flow control. We do two things here: * - construct a cflag setting for the first rs_open() * - initialize the serial port * Return non-zero if we didn't find a serial port. @@ -5602,8 +5693,7 @@ s++; if (*s) parity = *s++; if (*s) bits = *s++ - '0'; - if ((*s) && (!strcmp(s, "rtscts"))) - doflow = 1; + if (*s) doflow = (*s++ == 'r'); } /* @@ -5659,8 +5749,8 @@ * Divisor, bytesize and parity */ state = rs_table + co->index; - if (doflow == 0) - state->flags |= ASYNC_NO_FLOW; + if (doflow) + state->flags |= ASYNC_CONS_FLOW; info = &async_sercons; info->magic = SERIAL_MAGIC; info->state = state; diff -u --recursive --new-file v2.4.2/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.4.2/linux/drivers/char/stallion.c Wed Feb 21 18:20:20 2001 +++ linux/drivers/char/stallion.c Fri Mar 2 11:12:07 2001 @@ -165,12 +165,8 @@ * at 9600, 8 data bits, 1 stop bit. */ static struct termios stl_deftermios = { - 0, - 0, - (B9600 | CS8 | CREAD | HUPCL | CLOCAL), - 0, - 0, - INIT_C_CC + c_cflag: (B9600 | CS8 | CREAD | HUPCL | CLOCAL), + c_cc: INIT_C_CC, }; /* diff -u --recursive --new-file v2.4.2/linux/drivers/char/sx.c linux/drivers/char/sx.c --- v2.4.2/linux/drivers/char/sx.c Fri Dec 29 14:35:47 2000 +++ linux/drivers/char/sx.c Tue Mar 6 19:44:34 2001 @@ -1647,7 +1647,7 @@ #if 0 /* Removed superuser check: Sysops can use the permissions on the device file to restrict access. Recommendation: Root only. (root.root 600) */ - if (!suser ()) { + if (!capable(CAP_SYS_ADMIN)) { return -EPERM; } #endif diff -u --recursive --new-file v2.4.2/linux/drivers/char/synclink.c linux/drivers/char/synclink.c --- v2.4.2/linux/drivers/char/synclink.c Wed Feb 21 18:20:21 2001 +++ linux/drivers/char/synclink.c Tue Mar 6 19:44:34 2001 @@ -54,7 +54,11 @@ */ #define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) -#define BREAKPOINT() asm(" int $3"); +#if defined(__i386__) +# define BREAKPOINT() asm(" int $3"); +#else +# define BREAKPOINT() { } +#endif #define MAX_ISA_DEVICES 10 #define MAX_PCI_DEVICES 10 @@ -103,7 +107,7 @@ #endif #ifdef CONFIG_SYNCLINK_SYNCPPP -#include "../net/wan/syncppp.h" +#include #endif #include @@ -6994,7 +6998,7 @@ status = info->rx_buffer_list[0].status; if ( status & (BIT8 + BIT3 + BIT1) ) { - /* receive error has occured */ + /* receive error has occurred */ rc = FALSE; } else { if ( memcmp( info->tx_buffer_list[0].virt_addr , diff -u --recursive --new-file v2.4.2/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.4.2/linux/drivers/char/tpqic02.c Wed Feb 21 18:20:21 2001 +++ linux/drivers/char/tpqic02.c Fri Mar 2 18:38:37 2001 @@ -30,6 +30,8 @@ * * You are not allowed to change this line nor the text above. * + * 2001/02/26 Minor s/suser/capable/ + * * 1996/10/10 Emerald changes * * 1996/05/21 Misc changes+merges+cleanups + I/O reservations @@ -208,7 +210,7 @@ * must ensure that a large enough buffer is passed to the kernel, in order * to reduce tape repositioning wear and tear. */ -static unsigned long buffaddr; /* physical address of buffer */ +static void *buffaddr; /* virtual address of buffer */ /* This translates minor numbers to the corresponding recording format: */ static const char *format_names[] = { @@ -1376,7 +1378,7 @@ flags=claim_dma_lock(); clear_dma_ff(QIC02_TAPE_DMA); set_dma_mode(QIC02_TAPE_DMA, dma_mode); - set_dma_addr(QIC02_TAPE_DMA, buffaddr+dma_bytes_done); /* full address */ + set_dma_addr(QIC02_TAPE_DMA, virt_to_bus(buffaddr) + dma_bytes_done); set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE); /* start tape DMA controller */ @@ -1921,7 +1923,7 @@ /* copy buffer to user-space in one go */ if (bytes_done>0) { - err = copy_to_user( (void *) buf, (void *) bus_to_virt(buffaddr), bytes_done); + err = copy_to_user(buf, buffaddr, bytes_done); if (err) { return -EFAULT; @@ -2074,7 +2076,7 @@ /* copy from user to DMA buffer and initiate transfer. */ if (bytes_todo>0) { - err = copy_from_user( (void *) bus_to_virt(buffaddr), (const void *) buf, bytes_todo); + err = copy_from_user(buffaddr, buf, bytes_todo); if (err) { return -EFAULT; @@ -2198,7 +2200,7 @@ if (MINOR(dev)==255) /* special case for resetting */ { - if (suser()) + if (capable(CAP_SYS_ADMIN)) { return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO; } @@ -2607,7 +2609,7 @@ CHECK_IOC_SIZE(mtconfiginfo); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) { return -EPERM; } @@ -2780,7 +2782,7 @@ release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); if (buffaddr) { - free_pages(buffaddr, get_order(TPQBUF_SIZE)); + free_pages((unsigned long)buffaddr, get_order(TPQBUF_SIZE)); } buffaddr = 0; /* Better to cause a panic than overwite someone else */ status_zombie = YES; @@ -2830,9 +2832,7 @@ request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, TPQIC02_NAME); /* Setup the page-address for the dma transfer. */ - - /*** TODO: does _get_dma_pages() really return the physical address?? ****/ - buffaddr = __get_dma_pages(GFP_KERNEL,get_order(TPQBUF_SIZE)); + buffaddr = (void *)__get_dma_pages(GFP_KERNEL, get_order(TPQBUF_SIZE)); if (!buffaddr) { @@ -2840,7 +2840,7 @@ return -EBUSY; /* Not ideal, EAGAIN perhaps? */ } - memset( (void*) buffaddr, 0, TPQBUF_SIZE ); + memset(buffaddr, 0, TPQBUF_SIZE); printk(TPQIC02_NAME ": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n", QIC02_TAPE_IRQ, QIC02_TAPE_DMA, diff -u --recursive --new-file v2.4.2/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c --- v2.4.2/linux/drivers/i2c/i2c-algo-bit.c Wed Feb 21 18:20:21 2001 +++ linux/drivers/i2c/i2c-algo-bit.c Tue Mar 6 19:44:34 2001 @@ -169,7 +169,7 @@ /* returns: * 1 if the device acknowledged * 0 if the device did not ack - * -ETIMEDOUT if an error occured (while raising the scl line) + * -ETIMEDOUT if an error occurred (while raising the scl line) */ static int i2c_outb(struct i2c_adapter *i2c_adap, char c) { @@ -421,7 +421,7 @@ * reads, writes as well as 10bit-addresses. * returns: * 0 everything went okay, the chip ack'ed - * -x an error occured (like: -EREMOTEIO if the device did not answer, or + * -x an error occurred (like: -EREMOTEIO if the device did not answer, or * -ETIMEDOUT, for example if the lines are stuck...) */ static inline int bit_doAddress(struct i2c_adapter *i2c_adap, @@ -445,7 +445,7 @@ /* the remaining 8 bit address */ ret = i2c_outb(i2c_adap,msg->addr & 0x7f); if (ret != 1) { - /* the chip did not ack / xmission error occured */ + /* the chip did not ack / xmission error occurred */ printk("died at 2nd address code.\n"); return -EREMOTEIO; } diff -u --recursive --new-file v2.4.2/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c --- v2.4.2/linux/drivers/ide/ide-probe.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/ide/ide-probe.c Fri Mar 2 18:38:38 2001 @@ -614,9 +614,14 @@ { unsigned long flags; unsigned int index; - ide_hwgroup_t *hwgroup; + ide_hwgroup_t *hwgroup, *new_hwgroup; ide_hwif_t *match = NULL; + + /* Allocate the buffer and potentially sleep first */ + + new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL); + save_flags(flags); /* all CPUs */ cli(); /* all CPUs */ @@ -650,10 +655,14 @@ */ if (match) { hwgroup = match->hwgroup; + if(new_hwgroup) + kfree(new_hwgroup); } else { - hwgroup = kmalloc(sizeof(ide_hwgroup_t), GFP_KERNEL); - if (!hwgroup) + hwgroup = new_hwgroup; + if (!hwgroup) { + restore_flags(flags); /* all CPUs */ return 1; + } memset(hwgroup, 0, sizeof(ide_hwgroup_t)); hwgroup->hwif = hwif->next = hwif; hwgroup->rq = NULL; diff -u --recursive --new-file v2.4.2/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.4.2/linux/drivers/ide/ide.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/ide/ide.c Tue Mar 6 19:44:34 2001 @@ -1400,7 +1400,7 @@ if ((handler = hwgroup->handler) == NULL) { /* - * Either a marginal timeout occured + * Either a marginal timeout occurred * (got the interrupt just as timer expired), * or we were "sleeping" to give other devices a chance. * Either way, we don't really want to complain about anything. @@ -2467,8 +2467,7 @@ void ide_delay_50ms (void) { #ifndef CONFIG_BLK_DEV_IDECS - unsigned long timeout = jiffies + ((HZ + 19)/20) + 1; - while (0 < (signed long)(timeout - jiffies)); + mdelay(50); #else __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/20); diff -u --recursive --new-file v2.4.2/linux/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c --- v2.4.2/linux/drivers/ide/pdc4030.c Thu Apr 13 22:54:26 2000 +++ linux/drivers/ide/pdc4030.c Tue Mar 6 19:44:34 2001 @@ -445,9 +445,9 @@ /* * promise_write() transfers a block of one or more sectors of data to a - * drive as part of a disk write operation. All but 4 sectors are transfered + * drive as part of a disk write operation. All but 4 sectors are transferred * in the first attempt, then the interface is polled (nicely!) for completion - * before the final 4 sectors are transfered. There is no interrupt generated + * before the final 4 sectors are transferred. There is no interrupt generated * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY. */ static ide_startstop_t promise_write (ide_drive_t *drive) diff -u --recursive --new-file v2.4.2/linux/drivers/ide/piix.c linux/drivers/ide/piix.c --- v2.4.2/linux/drivers/ide/piix.c Tue Jan 2 16:58:45 2001 +++ linux/drivers/ide/piix.c Tue Mar 6 19:44:34 2001 @@ -226,7 +226,7 @@ /* * Based on settings done by AMI BIOS - * (might be usefull if drive is not registered in CMOS for any reason). + * (might be useful if drive is not registered in CMOS for any reason). */ static void piix_tune_drive (ide_drive_t *drive, byte pio) { diff -u --recursive --new-file v2.4.2/linux/drivers/ide/slc90e66.c linux/drivers/ide/slc90e66.c --- v2.4.2/linux/drivers/ide/slc90e66.c Mon Oct 16 12:21:40 2000 +++ linux/drivers/ide/slc90e66.c Tue Mar 6 19:44:34 2001 @@ -181,7 +181,7 @@ /* * Based on settings done by AMI BIOS - * (might be usefull if drive is not registered in CMOS for any reason). + * (might be useful if drive is not registered in CMOS for any reason). */ static void slc90e66_tune_drive (ide_drive_t *drive, byte pio) { diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/aic5800.c linux/drivers/ieee1394/aic5800.c --- v2.4.2/linux/drivers/ieee1394/aic5800.c Wed Oct 11 16:49:47 2000 +++ linux/drivers/ieee1394/aic5800.c Fri Mar 2 18:38:38 2001 @@ -657,7 +657,7 @@ }; } if ( interruptEvent & INT_BusReset ) { - PRINT(KERN_INFO, aic->id, "bus reset occured"); + PRINT(KERN_INFO, aic->id, "bus reset occurred"); if (!host->in_bus_reset) { hpsb_bus_reset(host); } diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/csr.c linux/drivers/ieee1394/csr.c --- v2.4.2/linux/drivers/ieee1394/csr.c Tue Jan 2 16:45:38 2001 +++ linux/drivers/ieee1394/csr.c Thu Mar 1 16:57:11 2001 @@ -403,31 +403,30 @@ } -struct hpsb_highlevel_ops csr_ops = { +static struct hpsb_highlevel_ops csr_ops = { add_host: add_host, host_reset: host_reset, }; -struct hpsb_address_ops map_ops = { +static struct hpsb_address_ops map_ops = { read: read_maps, }; -struct hpsb_address_ops fcp_ops = { +static struct hpsb_address_ops fcp_ops = { write: write_fcp, }; -struct hpsb_address_ops reg_ops = { +static struct hpsb_address_ops reg_ops = { read: read_regs, write: write_regs, lock: lock_regs, }; +static struct hpsb_highlevel *hl; void init_csr(void) { - struct hpsb_highlevel *hl; - hl = hpsb_register_highlevel("standard registers", &csr_ops); if (hl == NULL) { HPSB_ERR("out of memory during ieee1394 initialization"); @@ -448,4 +447,9 @@ hpsb_register_addrspace(hl, &map_ops, CSR_REGISTER_BASE + CSR_SPEED_MAP, CSR_REGISTER_BASE + CSR_SPEED_MAP_END); +} + +void cleanup_csr(void) +{ + hpsb_unregister_highlevel(hl); } diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/csr.h linux/drivers/ieee1394/csr.h --- v2.4.2/linux/drivers/ieee1394/csr.h Wed Mar 22 00:02:48 2000 +++ linux/drivers/ieee1394/csr.h Thu Mar 1 16:57:11 2001 @@ -50,5 +50,6 @@ void init_csr(void); +void cleanup_csr(void); #endif /* _IEEE1394_CSR_H */ diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/guid.c linux/drivers/ieee1394/guid.c --- v2.4.2/linux/drivers/ieee1394/guid.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/ieee1394/guid.c Thu Mar 1 16:57:11 2001 @@ -219,11 +219,19 @@ host_reset: host_reset, }; +static struct hpsb_highlevel *hl; + void init_ieee1394_guid(void) { atomic_set(&outstanding_requests, 0); - if (!hpsb_register_highlevel("GUID manager", &guid_ops)) { + hl = hpsb_register_highlevel("GUID manager", &guid_ops); + if (!hl) { HPSB_ERR("out of memory during ieee1394 initialization"); } +} + +void cleanup_ieee1394_guid(void) +{ + hpsb_unregister_highlevel(hl); } diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/guid.h linux/drivers/ieee1394/guid.h --- v2.4.2/linux/drivers/ieee1394/guid.h Mon Jun 19 17:59:40 2000 +++ linux/drivers/ieee1394/guid.h Thu Mar 1 16:57:11 2001 @@ -49,6 +49,6 @@ void init_ieee1394_guid(void); - +void cleanup_ieee1394_guid(void); #endif /* _IEEE1394_GUID_H */ diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c --- v2.4.2/linux/drivers/ieee1394/ieee1394_core.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/ieee1394/ieee1394_core.c Thu Mar 1 16:57:11 2001 @@ -269,7 +269,7 @@ } /* set self mapping */ - for (i = nodecount - 1; i; i--) { + for (i = 0; i < nodecount; i++) { map[64*i + i] = speedcap[i]; } @@ -802,6 +802,12 @@ init_ieee1394_guid(); return 0; +} + +void cleanup_module(void) +{ + cleanup_ieee1394_guid(); + cleanup_csr(); } #endif diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c --- v2.4.2/linux/drivers/ieee1394/ohci1394.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/ieee1394/ohci1394.c Fri Mar 2 18:38:38 2001 @@ -1129,7 +1129,7 @@ /* * Problem: How can I ensure that the AT bottom half will be * executed before the AR bottom half (both events may have - * occured within a single irq event) + * occurred within a single irq event) * Quick hack: just launch it within the IRQ handler */ if (event & OHCI1394_reqTxComplete) { diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h --- v2.4.2/linux/drivers/ieee1394/ohci1394.h Wed Feb 21 18:20:22 2001 +++ linux/drivers/ieee1394/ohci1394.h Tue Mar 6 19:28:32 2001 @@ -75,10 +75,6 @@ #define PCI_DEVICE_ID_NEC_UPD72871 0x00ce #endif -#ifndef PCI_DEVICE_ID_APPLE_UNI_N_FW -#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018 -#endif - #ifndef PCI_DEVICE_ID_ALI_OHCI1394_M5251 #define PCI_DEVICE_ID_ALI_OHCI1394_M5251 0x5251 #endif diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c --- v2.4.2/linux/drivers/ieee1394/pcilynx.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/ieee1394/pcilynx.c Fri Mar 2 18:38:38 2001 @@ -1127,7 +1127,7 @@ if (intmask & PCI_INT_1394) { if (linkint & LINK_INT_PHY_TIMEOUT) { - PRINT(KERN_INFO, lynx->id, "PHY timeout occured"); + PRINT(KERN_INFO, lynx->id, "PHY timeout occurred"); } if (linkint & LINK_INT_PHY_BUSRESET) { PRINT(KERN_INFO, lynx->id, "bus reset interrupt"); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v2.4.2/linux/drivers/isdn/Config.in Tue Jan 2 16:45:37 2001 +++ linux/drivers/isdn/Config.in Fri Mar 2 11:12:10 2001 @@ -9,7 +9,7 @@ if [ "$CONFIG_ISDN_PPP" != "n" ]; then bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP - dep_tristate ' Support BSD compression (module only)' CONFIG_ISDN_PPP_BSDCOMP m + dep_tristate ' Support BSD compression' CONFIG_ISDN_PPP_BSDCOMP $CONFIG_ISDN fi fi bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO @@ -23,7 +23,7 @@ mainmenu_option next_comment comment 'ISDN feature submodules' dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN - dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN m + dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN endmenu comment 'low-level hardware drivers' @@ -77,6 +77,9 @@ fi fi fi + +dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA + endmenu ### Active ISDN cards @@ -92,7 +95,7 @@ bool 'Eicon active card support' CONFIG_ISDN_DRV_EICON if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then - dep_tristate ' Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN + dep_tristate ' Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN $CONFIG_PCI fi if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then dep_tristate ' Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v2.4.2/linux/drivers/isdn/Makefile Fri Dec 29 14:40:54 2000 +++ linux/drivers/isdn/Makefile Fri Mar 2 11:12:10 2001 @@ -11,8 +11,7 @@ # Multipart objects. list-multi := isdn.o -isdn-objs := isdn_net.o isdn_tty.o isdn_cards.o isdn_v110.o \ - isdn_common.o +isdn-objs := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o # Optional parts of multipart objects. diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/act2000/act2000.h linux/drivers/isdn/act2000/act2000.h --- v2.4.2/linux/drivers/isdn/act2000/act2000.h Wed Feb 21 18:20:22 2001 +++ linux/drivers/isdn/act2000/act2000.h Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: act2000.h,v 1.8 2000/11/12 16:32:06 kai Exp $ +/* $Id: act2000.h,v 1.8.6.2 2001/02/16 16:43:23 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/act2000/capi.c linux/drivers/isdn/act2000/capi.c --- v2.4.2/linux/drivers/isdn/act2000/capi.c Fri Nov 17 11:16:20 2000 +++ linux/drivers/isdn/act2000/capi.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: capi.c,v 1.9 2000/11/12 16:32:06 kai Exp $ +/* $Id: capi.c,v 1.9.6.1 2001/02/16 16:43:23 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * CAPI encoder/decoder @@ -124,7 +124,7 @@ m->hdr.cmd.cmd = c; \ m->hdr.cmd.subcmd = s; \ m->hdr.msgnum = actcapi_nextsmsg(card); \ - } \ + } else m = NULL;\ } #define ACTCAPI_CHKSKB if (!skb) { \ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/act2000/capi.h linux/drivers/isdn/act2000/capi.h --- v2.4.2/linux/drivers/isdn/act2000/capi.h Fri Nov 17 11:16:20 2000 +++ linux/drivers/isdn/act2000/capi.h Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: capi.h,v 1.6 2000/11/12 16:32:06 kai Exp $ +/* $Id: capi.h,v 1.6.6.1 2001/02/16 16:43:23 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * @@ -44,7 +44,7 @@ char *description; } actcapi_msgdsc; -/* CAPI Adress */ +/* CAPI Address */ typedef struct actcapi_addr { __u8 len; /* Length of element */ __u8 tnp; /* Type/Numbering Plan */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/act2000/module.c linux/drivers/isdn/act2000/module.c --- v2.4.2/linux/drivers/isdn/act2000/module.c Fri Nov 17 11:16:20 2000 +++ linux/drivers/isdn/act2000/module.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: module.c,v 1.14 2000/11/12 16:32:06 kai Exp $ +/* $Id: module.c,v 1.14.6.2 2000/12/18 22:14:10 kai Exp $ * * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000. * @@ -24,6 +24,7 @@ #include "act2000.h" #include "act2000_isa.h" #include "capi.h" +#include static unsigned short act2000_isa_ports[] = { @@ -820,12 +821,7 @@ #define DRIVERNAME "IBM Active 2000 ISDN driver" -#ifdef MODULE -#define act2000_init init_module -#endif - -int -act2000_init(void) +static int __init act2000_init(void) { printk(KERN_INFO "%s\n", DRIVERNAME); if (!cards) @@ -837,9 +833,7 @@ return 0; } -#ifdef MODULE -void -cleanup_module(void) +static void __exit act2000_exit(void) { act2000_card *card = cards; act2000_card *last; @@ -858,34 +852,5 @@ printk(KERN_INFO "%s unloaded\n", DRIVERNAME); } -#else -void -act2000_setup(char *str, int *ints) -{ - int i, j, argc, port, irq, bus; - - argc = ints[0]; - i = 1; - if (argc) - while (argc) { - port = irq = -1; - bus = 0; - if (argc) { - bus = ints[i]; - i++; - argc--; - } - if (argc) { - port = ints[i]; - i++; - argc--; - } - if (argc) { - irq = ints[i]; - i++; - argc--; - } - act2000_addcard(bus, port, irq, act_id); - } -} -#endif +module_init(act2000_init); +module_exit(act2000_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/avm_cs.c linux/drivers/isdn/avmb1/avm_cs.c --- v2.4.2/linux/drivers/isdn/avmb1/avm_cs.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/isdn/avmb1/avm_cs.c Fri Mar 2 11:12:07 2001 @@ -138,6 +138,8 @@ /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) + return NULL; memset(link, 0, sizeof(struct dev_link_t)); link->release.function = &avmcs_release; link->release.data = (u_long)link; @@ -169,6 +171,8 @@ /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) + return NULL; memset(local, 0, sizeof(local_info_t)); link->priv = local; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c --- v2.4.2/linux/drivers/isdn/avmb1/b1.c Tue Nov 28 21:43:13 2000 +++ linux/drivers/isdn/avmb1/b1.c Fri Mar 2 11:12:07 2001 @@ -1,11 +1,14 @@ /* - * $Id: b1.c,v 1.20 2000/11/23 20:45:14 kai Exp $ + * $Id: b1.c,v 1.20.6.1 2001/02/13 11:43:29 kai Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.20.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.20 2000/11/23 20:45:14 kai * fixed module_init/exit stuff * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. @@ -117,7 +120,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.20 $"; +static char *revision = "$Revision: 1.20.6.1 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.4.2/linux/drivers/isdn/avmb1/b1dma.c Tue Nov 28 21:43:13 2000 +++ linux/drivers/isdn/avmb1/b1dma.c Fri Mar 2 11:12:07 2001 @@ -1,11 +1,14 @@ /* - * $Id: b1dma.c,v 1.11 2000/11/19 17:02:47 kai Exp $ + * $Id: b1dma.c,v 1.11.6.1 2001/02/13 11:43:29 kai Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.11.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.11 2000/11/19 17:02:47 kai * compatibility cleanup - part 3 * @@ -62,7 +65,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.11 $"; +static char *revision = "$Revision: 1.11.6.1 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c --- v2.4.2/linux/drivers/isdn/avmb1/b1isa.c Tue Nov 28 21:43:13 2000 +++ linux/drivers/isdn/avmb1/b1isa.c Fri Mar 2 11:12:07 2001 @@ -1,11 +1,17 @@ /* - * $Id: b1isa.c,v 1.10 2000/11/23 20:45:14 kai Exp $ + * $Id: b1isa.c,v 1.10.6.2 2001/02/16 16:43:23 kai Exp $ * * Module for AVM B1 ISA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1isa.c,v $ + * Revision 1.10.6.2 2001/02/16 16:43:23 kai + * Changes from -ac16, little bug fixes, typos and the like + * + * Revision 1.10.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.10 2000/11/23 20:45:14 kai * fixed module_init/exit stuff * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. @@ -24,7 +30,7 @@ * - fixed problem with memory mapping if address is not aligned * * Revision 1.6 2000/01/25 14:37:39 calle - * new message after successfull detection including card revision and + * new message after successful detection including card revision and * used resources. * * Revision 1.5 1999/11/05 16:38:01 calle @@ -83,7 +89,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.10.6.2 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c --- v2.4.2/linux/drivers/isdn/avmb1/b1pcmcia.c Tue Nov 28 21:43:13 2000 +++ linux/drivers/isdn/avmb1/b1pcmcia.c Fri Mar 2 11:12:07 2001 @@ -1,11 +1,17 @@ /* - * $Id: b1pcmcia.c,v 1.12 2000/11/23 20:45:14 kai Exp $ + * $Id: b1pcmcia.c,v 1.12.6.2 2001/02/16 16:43:23 kai Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pcmcia.c,v $ + * Revision 1.12.6.2 2001/02/16 16:43:23 kai + * Changes from -ac16, little bug fixes, typos and the like + * + * Revision 1.12.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.12 2000/11/23 20:45:14 kai * fixed module_init/exit stuff * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. @@ -33,7 +39,7 @@ * - fixed problem with memory mapping if address is not aligned * * Revision 1.6 2000/01/25 14:37:39 calle - * new message after successfull detection including card revision and + * new message after successful detection including card revision and * used resources. * * Revision 1.5 1999/11/05 16:38:01 calle @@ -93,7 +99,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.12 $"; +static char *revision = "$Revision: 1.12.6.2 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.4.2/linux/drivers/isdn/avmb1/c4.c Tue Nov 28 21:44:41 2000 +++ linux/drivers/isdn/avmb1/c4.c Fri Mar 2 11:12:07 2001 @@ -1,11 +1,17 @@ /* - * $Id: c4.c,v 1.20.6.1 2000/11/28 12:02:45 kai Exp $ + * $Id: c4.c,v 1.20.6.3 2001/02/16 16:43:23 kai Exp $ * * Module for AVM C4 card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: c4.c,v $ + * Revision 1.20.6.3 2001/02/16 16:43:23 kai + * Changes from -ac16, little bug fixes, typos and the like + * + * Revision 1.20.6.2 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.20.6.1 2000/11/28 12:02:45 kai * MODULE_DEVICE_TABLE for 2.4 * @@ -75,7 +81,7 @@ * - fixed problem with memory mapping if address is not aligned * * Revision 1.3 2000/01/25 14:37:39 calle - * new message after successfull detection including card revision and + * new message after successful detection including card revision and * used resources. * * Revision 1.2 2000/01/21 20:52:58 keil @@ -106,7 +112,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.20.6.1 $"; +static char *revision = "$Revision: 1.20.6.3 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -1330,7 +1336,6 @@ add_card: 0, /* no add_card function */ }; - static int ncards = 0; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.4.2/linux/drivers/isdn/avmb1/capi.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/isdn/avmb1/capi.c Fri Mar 2 11:12:07 2001 @@ -1,11 +1,17 @@ /* - * $Id: capi.c,v 1.44.6.3 2000/12/17 22:45:08 kai Exp $ + * $Id: capi.c,v 1.44.6.5 2001/02/13 11:43:29 kai Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.44.6.5 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.44.6.4 2001/02/10 14:41:20 kai + * Changes from kernel tree + * * Revision 1.44.6.3 2000/12/17 22:45:08 kai * That's hopefully it for test13-4 * @@ -253,7 +259,7 @@ #include "capifs.h" #endif -static char *revision = "$Revision: 1.44.6.3 $"; +static char *revision = "$Revision: 1.44.6.5 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); @@ -1317,7 +1323,6 @@ #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(THIS_MODULE)); #endif - mp->datahandle = 0; mp->file = file; file->private_data = (void *)mp; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.4.2/linux/drivers/isdn/avmb1/capidrv.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/isdn/avmb1/capidrv.c Fri Mar 2 11:12:07 2001 @@ -1,11 +1,17 @@ /* - * $Id: capidrv.c,v 1.39 2000/11/23 20:45:14 kai Exp $ + * $Id: capidrv.c,v 1.39.6.2 2001/02/13 11:43:29 kai Exp $ * * ISDN4Linux Driver, using capi20 interface (kernelcapi) * * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capidrv.c,v $ + * Revision 1.39.6.2 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.39.6.1 2001/02/10 14:41:20 kai + * Changes from kernel tree + * * Revision 1.39 2000/11/23 20:45:14 kai * fixed module_init/exit stuff * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. @@ -219,7 +225,7 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.39 $"; +static char *revision = "$Revision: 1.39.6.2 $"; static int debugmode = 0; MODULE_AUTHOR("Carsten Paeth "); @@ -488,7 +494,7 @@ } -/* -------- controller managment ------------------------------------- */ +/* -------- controller management ------------------------------------- */ static inline capidrv_contr *findcontrbydriverid(int driverid) { diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c --- v2.4.2/linux/drivers/isdn/avmb1/capifs.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/isdn/avmb1/capifs.c Fri Mar 2 11:12:07 2001 @@ -1,11 +1,17 @@ /* - * $Id: capifs.c,v 1.14.6.1 2000/11/28 12:02:45 kai Exp $ + * $Id: capifs.c,v 1.14.6.3 2001/02/13 11:43:29 kai Exp $ * * (c) Copyright 2000 by Carsten Paeth (calle@calle.de) * * Heavily based on devpts filesystem from H. Peter Anvin * * $Log: capifs.c,v $ + * Revision 1.14.6.3 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * + * Revision 1.14.6.2 2001/02/10 14:41:20 kai + * Changes from kernel tree + * * Revision 1.14.6.1 2000/11/28 12:02:45 kai * MODULE_DEVICE_TABLE for 2.4 * @@ -93,7 +99,7 @@ MODULE_AUTHOR("Carsten Paeth "); -static char *revision = "$Revision: 1.14.6.1 $"; +static char *revision = "$Revision: 1.14.6.3 $"; struct capifs_ncci { struct inode *inode; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c --- v2.4.2/linux/drivers/isdn/avmb1/capiutil.c Tue Nov 28 21:43:13 2000 +++ linux/drivers/isdn/avmb1/capiutil.c Fri Mar 2 11:12:07 2001 @@ -1,5 +1,5 @@ /* - * $Id: capiutil.c,v 1.13 2000/11/23 20:45:14 kai Exp $ + * $Id: capiutil.c,v 1.13.6.1 2001/02/13 11:43:29 kai Exp $ * * CAPI 2.0 convert capi message to capi message struct * @@ -7,6 +7,9 @@ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capiutil.c,v $ + * Revision 1.13.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.13 2000/11/23 20:45:14 kai * fixed module_init/exit stuff * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c --- v2.4.2/linux/drivers/isdn/avmb1/kcapi.c Fri Dec 29 14:07:22 2000 +++ linux/drivers/isdn/avmb1/kcapi.c Fri Mar 2 11:12:08 2001 @@ -1,11 +1,14 @@ /* - * $Id: kcapi.c,v 1.21.6.1 2000/12/10 23:39:19 kai Exp $ + * $Id: kcapi.c,v 1.21.6.2 2001/02/13 11:43:29 kai Exp $ * * Kernel CAPI 2.0 Module * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: kcapi.c,v $ + * Revision 1.21.6.2 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.21.6.1 2000/12/10 23:39:19 kai * in 2.4 we don't have tq_scheduler anymore. * also add one supported card to hfc_pci.c @@ -136,7 +139,7 @@ #include #endif -static char *revision = "$Revision: 1.21.6.1 $"; +static char *revision = "$Revision: 1.21.6.2 $"; /* ------------------------------------------------------------- */ @@ -814,7 +817,7 @@ } } /* - * ncci managment + * ncci management */ static void controllercb_new_ncci(struct capi_ctr * card, diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.4.2/linux/drivers/isdn/avmb1/t1isa.c Tue Nov 28 21:43:13 2000 +++ linux/drivers/isdn/avmb1/t1isa.c Fri Mar 2 11:12:08 2001 @@ -1,11 +1,17 @@ /* - * $Id: t1isa.c,v 1.16 2000/11/23 20:45:14 kai Exp $ + * $Id: t1isa.c,v 1.16.6.2 2001/02/16 16:43:24 kai Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.16.6.2 2001/02/16 16:43:24 kai + * Changes from -ac16, little bug fixes, typos and the like + * + * Revision 1.16.6.1 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.16 2000/11/23 20:45:14 kai * fixed module_init/exit stuff * Note: compiled-in kernel doesn't work pre 2.2.18 anymore. @@ -33,7 +39,7 @@ * - fixed problem with memory mapping if address is not aligned * * Revision 1.9 2000/01/25 14:37:39 calle - * new message after successfull detection including card revision and + * new message after successful detection including card revision and * used resources. * * Revision 1.8 1999/11/05 16:38:01 calle @@ -104,7 +110,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.16 $"; +static char *revision = "$Revision: 1.16.6.2 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c --- v2.4.2/linux/drivers/isdn/avmb1/t1pci.c Tue Nov 28 21:44:41 2000 +++ linux/drivers/isdn/avmb1/t1pci.c Fri Mar 2 11:12:08 2001 @@ -1,11 +1,14 @@ /* - * $Id: t1pci.c,v 1.13.6.1 2000/11/28 12:02:45 kai Exp $ + * $Id: t1pci.c,v 1.13.6.2 2001/02/13 11:43:29 kai Exp $ * * Module for AVM T1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1pci.c,v $ + * Revision 1.13.6.2 2001/02/13 11:43:29 kai + * more compatility changes for 2.2.19 + * * Revision 1.13.6.1 2000/11/28 12:02:45 kai * MODULE_DEVICE_TABLE for 2.4 * @@ -88,7 +91,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.13.6.1 $"; +static char *revision = "$Revision: 1.13.6.2 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/divert/divert_init.c linux/drivers/isdn/divert/divert_init.c --- v2.4.2/linux/drivers/isdn/divert/divert_init.c Fri Nov 17 11:16:20 2000 +++ linux/drivers/isdn/divert/divert_init.c Fri Mar 2 11:12:08 2001 @@ -1,5 +1,5 @@ /* - * $Id: divert_init.c,v 1.5 2000/11/13 22:51:47 kai Exp $ + * $Id: divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $ * * Module init for DSS1 diversion services for i4l. * @@ -23,6 +23,7 @@ #include #include +#include #include "isdn_divert.h" /********************/ @@ -46,7 +47,7 @@ /* Module interface code */ /* no cmd line parms */ /*************************/ -int init_module(void) +static int __init divert_init(void) { int i; if (divert_dev_init()) @@ -63,12 +64,12 @@ #endif printk(KERN_INFO "dss1_divert module successfully installed\n"); return(0); -} /* init_module */ +} /**********************/ /* Module deinit code */ /**********************/ -void cleanup_module(void) +static void __exit divert_exit(void) { int flags; int i; @@ -89,6 +90,8 @@ deleterule(-1); /* delete all rules and free mem */ deleteprocs(); printk(KERN_INFO "dss1_divert module successfully removed \n"); -} /* cleanup_module */ +} +module_init(divert_init); +module_exit(divert_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/divert/isdn_divert.c linux/drivers/isdn/divert/isdn_divert.c --- v2.4.2/linux/drivers/isdn/divert/isdn_divert.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/isdn/divert/isdn_divert.c Fri Mar 2 11:12:08 2001 @@ -1,5 +1,5 @@ /* - * $Id: isdn_divert.c,v 1.6.6.1 2001/02/07 11:31:31 kai Exp $ + * $Id: isdn_divert.c,v 1.6.6.2 2001/02/16 16:43:25 kai Exp $ * * DSS1 main diversion supplementary handling for i4l. * @@ -290,7 +290,7 @@ /* insert a new rule before idx */ /********************************/ int insertrule(int idx, divert_rule *newrule) -{ struct deflect_struc *ds,*ds1; +{ struct deflect_struc *ds,*ds1=NULL; int flags; if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc), diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/Divas_mod.c linux/drivers/isdn/eicon/Divas_mod.c --- v2.4.2/linux/drivers/isdn/eicon/Divas_mod.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/eicon/Divas_mod.c Fri Mar 2 11:12:08 2001 @@ -1,13 +1,6 @@ /* * - * Copyright (C) Eicon Technology Corporation, 2000. - * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * - * Eicon File Revision : 1.15 - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -26,6 +19,7 @@ #include +#include #include #undef N_DATA @@ -40,27 +34,23 @@ #include "adapter.h" #include "uxio.h" + #ifdef MODULE #include "idi.h" void DIVA_DIDD_Write(DESCRIPTOR *, int); EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write); EXPORT_SYMBOL_NOVERS(DivasPrintf); -#define Divas_init init_module -#else -#define Divas_init eicon_init #endif -extern char *file_check(void); - int DivasCardsDiscover(void); -int -Divas_init(void) +static int __init +divas_init(void) { printk(KERN_DEBUG "DIVA Server Driver - initialising\n"); - printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.15 (%s)\n",file_check()); + printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.16\n"); #if !defined(CONFIG_PCI) @@ -85,9 +75,8 @@ return 0; } -#ifdef MODULE -void -cleanup_module(void) +static void __exit +divas_exit(void) { card_t *pCard; word wCardIndex; @@ -156,15 +145,6 @@ unregister_chrdev(Divas_major, "Divas"); } -void mod_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - -void mod_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - -#endif +module_init(divas_init); +module_exit(divas_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/Makefile linux/drivers/isdn/eicon/Makefile --- v2.4.2/linux/drivers/isdn/eicon/Makefile Fri Dec 29 14:40:54 2000 +++ linux/drivers/isdn/eicon/Makefile Fri Mar 2 11:12:08 2001 @@ -12,10 +12,9 @@ list-multi := eicon.o divas.o eicon-objs := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \ - eicon_io.o fcheck.o + eicon_io.o divas-objs := common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \ - fourbri.o lincfg.o linchr.o linsys.o linio.o fcheck.o \ - Divas_mod.o + fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o # Optional parts of multipart objects. diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/adapter.h linux/drivers/isdn/eicon/adapter.h --- v2.4.2/linux/drivers/isdn/eicon/adapter.h Mon Dec 11 13:21:41 2000 +++ linux/drivers/isdn/eicon/adapter.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.7 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/bri.c linux/drivers/isdn/eicon/bri.c --- v2.4.2/linux/drivers/isdn/eicon/bri.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/bri.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.8 * * This program is free software; you can redistribute it and/or modify @@ -63,6 +60,7 @@ void io_inc(ADAPTER *a, void *adr); static int diva_server_bri_test_int(card_t *card); +static int bri_ISR (card_t* card); #define PLX_IOBASE 0 #define DIVAS_IOBASE 1 @@ -80,7 +78,6 @@ void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word); int DivasBRIInitPCI(card_t *card, dia_card_t *cfg); -int bri_ISR (card_t* card); static int diva_server_bri_reset(card_t *card) @@ -361,7 +358,7 @@ UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2); UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10); - UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0); + UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->sig_flags); UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11); UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c --- v2.4.2/linux/drivers/isdn/eicon/common.c Wed Sep 27 13:45:40 2000 +++ linux/drivers/isdn/eicon/common.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.15 * * This program is free software; you can redistribute it and/or modify @@ -101,7 +98,6 @@ return; } -static void DIVA_DIDD_Write(DESCRIPTOR *table, int tablelength) { if (tablelength > sizeof(DIDD_Table)) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/constant.h linux/drivers/isdn/eicon/constant.h --- v2.4.2/linux/drivers/isdn/eicon/constant.h Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/constant.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.0 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/divalog.h linux/drivers/isdn/eicon/divalog.h --- v2.4.2/linux/drivers/isdn/eicon/divalog.h Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/divalog.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.0 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/divas.h linux/drivers/isdn/eicon/divas.h --- v2.4.2/linux/drivers/isdn/eicon/divas.h Mon Dec 11 13:21:41 2000 +++ linux/drivers/isdn/eicon/divas.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.5 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/dsp_defs.h linux/drivers/isdn/eicon/dsp_defs.h --- v2.4.2/linux/drivers/isdn/eicon/dsp_defs.h Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/dsp_defs.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.0 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/dspdids.h linux/drivers/isdn/eicon/dspdids.h --- v2.4.2/linux/drivers/isdn/eicon/dspdids.h Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/dspdids.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.0 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h --- v2.4.2/linux/drivers/isdn/eicon/eicon.h Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/eicon/eicon.h Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.23 2000/06/21 11:28:42 armin Exp $ +/* $Id: eicon.h,v 1.23.6.2 2001/02/13 11:43:30 kai Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * @@ -150,7 +150,6 @@ #include #include - typedef struct { __u16 length __attribute__ ((packed)); /* length of data/parameter field */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.4.2/linux/drivers/isdn/eicon/eicon_idi.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/eicon_idi.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.41 2000/08/12 18:00:47 armin Exp $ +/* $Id: eicon_idi.c,v 1.41.6.1 2001/02/10 14:44:09 kai Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -36,7 +36,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.41 $"; +char *eicon_idi_revision = "$Revision: 1.41.6.1 $"; eicon_manifbuf *manbuf; @@ -2506,7 +2506,7 @@ case ISDN_PROTO_L2_TRANS: idi_do_req(ccard, chan, N_CONNECT, 1); break; - default: + default:; /* On most incoming calls we use automatic connect */ /* idi_do_req(ccard, chan, N_CONNECT, 1); */ } diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon_io.c linux/drivers/isdn/eicon/eicon_io.c --- v2.4.2/linux/drivers/isdn/eicon/eicon_io.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/eicon_io.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_io.c,v 1.13 2000/05/07 08:51:04 armin Exp $ +/* $Id: eicon_io.c,v 1.13.6.1 2001/02/16 09:09:50 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Code for communicating with hardware. @@ -6,7 +6,7 @@ * Copyright 1999,2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.4.2/linux/drivers/isdn/eicon/eicon_mod.c Wed Sep 27 13:45:40 2000 +++ linux/drivers/isdn/eicon/eicon_mod.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.37 2000/09/02 11:16:47 armin Exp $ +/* $Id: eicon_mod.c,v 1.37.6.4 2001/02/16 09:09:50 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -6,7 +6,7 @@ * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * * Deutsche Mailbox Saar-Lor-Lux GmbH @@ -32,7 +32,7 @@ #define DRIVERNAME "Eicon active ISDN driver" #define DRIVERRELEASE "2.0" -#define DRIVERPATCH ".15" +#define DRIVERPATCH ".16" #include @@ -55,7 +55,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.37 $"; +static char *eicon_revision = "$Revision: 1.37.6.4 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -64,9 +64,6 @@ extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, unsigned int command, unsigned long arg); extern void eicon_pci_init_conf(eicon_card *card); -void mod_inc_use_count(void); -void mod_dec_use_count(void); -extern char *file_check(void); #ifdef MODULE #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) @@ -377,7 +374,7 @@ #ifdef MODULE case EICON_IOCTL_FREEIT: while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT; - mod_inc_use_count(); + MOD_INC_USE_COUNT; return 0; #endif case EICON_IOCTL_LOADPCI: @@ -573,14 +570,10 @@ eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n"); return 0; case ISDN_CMD_LOCK: -#ifdef MODULE - mod_inc_use_count(); -#endif + MOD_INC_USE_COUNT; return 0; case ISDN_CMD_UNLOCK: -#ifdef MODULE - mod_dec_use_count(); -#endif + MOD_DEC_USE_COUNT; return 0; #ifdef CONFIG_ISDN_TTY_FAX case ISDN_CMD_FAXCMD: @@ -1177,8 +1170,7 @@ return 0; } -#ifdef MODULE -static void +static void __exit unregister_card(eicon_card * card) { isdn_ctrl cmd; @@ -1204,7 +1196,6 @@ break; } } -#endif /* MODULE */ static void eicon_freecard(eicon_card *card) { @@ -1311,11 +1302,7 @@ } -#ifdef MODULE -#define eicon_init init_module -#endif - -int +static int __init eicon_init(void) { int card_count = 0; @@ -1341,8 +1328,8 @@ #endif strcpy(tmprev, eicon_idi_revision); printk("%s\n", eicon_getrev(tmprev)); - printk(KERN_INFO "%s Release: %s%s (%s)\n", DRIVERNAME, - DRIVERRELEASE, DRIVERPATCH, file_check()); + printk(KERN_INFO "%s Release: %s%s\n", DRIVERNAME, + DRIVERRELEASE, DRIVERPATCH); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA @@ -1391,19 +1378,6 @@ return 0; } - -#ifdef MODULE - -void mod_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - -void mod_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - #ifdef CONFIG_ISDN_DRV_EICON_PCI void DIVA_DIDD_Write(DESCRIPTOR *, int); EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); @@ -1414,8 +1388,8 @@ card_t DivasCards[1]; #endif -void -cleanup_module(void) +static void __exit +eicon_exit(void) { #if CONFIG_PCI #ifdef CONFIG_ISDN_DRV_EICON_PCI @@ -1499,7 +1473,7 @@ printk(KERN_INFO "%s unloaded\n", DRIVERNAME); } -#else /* no module */ +#ifndef MODULE static int __init eicon_setup(char *line) @@ -1712,3 +1686,5 @@ #endif /* CONFIG_MCA */ #endif /* CONFIG_ISDN_DRV_EICON_ISA */ +module_init(eicon_init); +module_exit(eicon_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c --- v2.4.2/linux/drivers/isdn/eicon/eicon_pci.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/eicon_pci.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.c,v 1.15 2000/06/12 12:44:02 armin Exp $ +/* $Id: eicon_pci.c,v 1.15.6.2 2001/02/16 09:09:50 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -6,7 +6,7 @@ * Copyright 1998-2000 by Armin Schindler (mac@melware.de) * Copyright 1999,2000 Cytronics & Melware (info@melware.de) * - * Thanks to Eicon Technology GmbH & Co. oHG for + * Thanks to Eicon Networks for * documents, informations and hardware. * * This program is free software; you can redistribute it and/or modify @@ -35,7 +35,7 @@ #include "adapter.h" #include "uxio.h" -char *eicon_pci_revision = "$Revision: 1.15 $"; +char *eicon_pci_revision = "$Revision: 1.15.6.2 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ #ifdef CONFIG_ISDN_DRV_EICON_PCI @@ -86,7 +86,7 @@ printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n", eicon_ctype_name[ctype], did, card_id); } -err: +err:; } pCard++; } diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/fcheck.c linux/drivers/isdn/eicon/fcheck.c --- v2.4.2/linux/drivers/isdn/eicon/fcheck.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/fcheck.c Wed Dec 31 16:00:00 1969 @@ -1,31 +0,0 @@ -/* $Id: fcheck.c,v 1.3 2000/06/12 12:44:02 armin Exp $ - * - * (c) 2000 Cytronics & Melware - * - * This file is (c) under GNU PUBLIC LICENSE - * For changes and modifications please read - * ../../../Documentation/isdn/README.eicon - * - * - */ - -#include - -char * -file_check(void) { - -#ifdef FILECHECK -#if FILECHECK == 0 - return("verified"); -#endif -#if FILECHECK == 1 - return("modified"); -#endif -#if FILECHECK == 127 - return("verification failed"); -#endif -#else - return("not verified"); -#endif -} - diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/fourbri.c linux/drivers/isdn/eicon/fourbri.c --- v2.4.2/linux/drivers/isdn/eicon/fourbri.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/fourbri.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.7 * * This program is free software; you can redistribute it and/or modify @@ -67,7 +64,7 @@ void mem_inc(ADAPTER *a, void *adr); int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg); -int fourbri_ISR (card_t* card); +static int fourbri_ISR (card_t* card); int FPGA_Download(word, dword, byte *, byte *, int); extern byte FPGA_Bytes[]; @@ -113,7 +110,7 @@ UxCardMemOut(card->hw, &shared[ 8], config->tei); UxCardMemOut(card->hw, &shared[ 9], config->nt2); - UxCardMemOut(card->hw, &shared[10], 0); + UxCardMemOut(card->hw, &shared[10], config->sig_flags); UxCardMemOut(card->hw, &shared[11], config->watchdog); UxCardMemOut(card->hw, &shared[12], config->permanent); UxCardMemOut(card->hw, &shared[13], config->x_interface); @@ -561,23 +558,16 @@ }*/ -int fourbri_ISR (card_t* card) +static int fourbri_ISR (card_t* card) { - int served = 0; byte *ctl; - byte *reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY); - if (UxCardPortIoIn(card->hw, reg, PLX9054_INTCSR) & 0x80) - { - served = 1; - card->int_pend += 1; - DivasDpcSchedule(); /* ISR DPC */ + card->int_pend += 1; + DivasDpcSchedule(); /* ISR DPC */ - ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); - UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); - UxCardMemDetach(card->hw, ctl); - } + ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY); + UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF); + UxCardMemDetach(card->hw, ctl); - UxCardMemDetach(card->hw, reg); - return (served != 0); + return (1); } diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/fpga.c linux/drivers/isdn/eicon/fpga.c --- v2.4.2/linux/drivers/isdn/eicon/fpga.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/fpga.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.2 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/idi.c linux/drivers/isdn/eicon/idi.c --- v2.4.2/linux/drivers/isdn/eicon/idi.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/idi.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.8 * * This program is free software; you can redistribute it and/or modify @@ -248,13 +245,13 @@ /* * IDI request function for active cards */ - static void request(card_t *card, ENTITY *e) { word *special_req; int i; int ipl; + if (card->log_types & DIVAS_LOG_IDI) { diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/idi.h linux/drivers/isdn/eicon/idi.h --- v2.4.2/linux/drivers/isdn/eicon/idi.h Mon Dec 11 13:21:41 2000 +++ linux/drivers/isdn/eicon/idi.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.0 * * This program is free software; you can redistribute it and/or modify @@ -65,7 +62,7 @@ struct postcall_s { word command; /* command = 0x0300 */ word dummy; /* not used */ - IDI_CALL callback; /* routine adress to call back */ + IDI_CALL callback; /* routine address to call back */ ENTITY *contxt; /* ptr to entity to use */ }; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/kprintf.c linux/drivers/isdn/eicon/kprintf.c --- v2.4.2/linux/drivers/isdn/eicon/kprintf.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/kprintf.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.3 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/lincfg.c linux/drivers/isdn/eicon/lincfg.c --- v2.4.2/linux/drivers/isdn/eicon/lincfg.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/lincfg.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.9 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/linchr.c linux/drivers/isdn/eicon/linchr.c --- v2.4.2/linux/drivers/isdn/eicon/linchr.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/eicon/linchr.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.12 * * This program is free software; you can redistribute it and/or modify @@ -24,6 +21,8 @@ * */ +#define __NO_VERSION__ +#include #include #include @@ -240,14 +239,12 @@ return 0; } -int private_usage_count; -extern void mod_inc_use_count(void); -extern void mod_dec_use_count(void); +static int private_usage_count; int do_open(struct inode *pInode, struct file *pFile) { -#if defined(MODULE) - mod_inc_use_count(); + MOD_INC_USE_COUNT; +#ifdef MODULE private_usage_count++; #endif return 0; @@ -255,8 +252,8 @@ int do_release(struct inode *pInode, struct file *pFile) { -#if defined(MODULE) - mod_dec_use_count(); + MOD_DEC_USE_COUNT; +#ifdef MODULE private_usage_count--; #endif return 0; @@ -267,8 +264,6 @@ while (private_usage_count > 0) { private_usage_count--; -#if defined(MODULE) - mod_dec_use_count(); -#endif + MOD_DEC_USE_COUNT; } } diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/linio.c linux/drivers/isdn/eicon/linio.c --- v2.4.2/linux/drivers/isdn/eicon/linio.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/eicon/linio.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.16 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/linsys.c linux/drivers/isdn/eicon/linsys.c --- v2.4.2/linux/drivers/isdn/eicon/linsys.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/linsys.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.10 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/log.c linux/drivers/isdn/eicon/log.c --- v2.4.2/linux/drivers/isdn/eicon/log.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/log.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.5 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/md5sums.asc linux/drivers/isdn/eicon/md5sums.asc --- v2.4.2/linux/drivers/isdn/eicon/md5sums.asc Wed Sep 27 13:45:40 2000 +++ linux/drivers/isdn/eicon/md5sums.asc Wed Dec 31 16:00:00 1969 @@ -1,16 +0,0 @@ -# These are valid md5sums to detect modifications -# in eicon driver files provided by Eicon Technology. -# For changes and modifications in these files please -# read ../../../Documentation/isdn/README.eicon -# -34bfe8d08d337a97c699ac8326f1d9b6 common.c -dbb92cba52db31ff8325a252b3f595c3 idi.c -15687687ef82f099966ed42772001cd3 bri.c -c3e3b720c3351b66635bd548195e29e8 pri.c -b0a6d2ab49bcfcfd1825860f178a84b4 log.c -673746176316b72271a09c0a27287a01 xlog.c -07e1bbabdb4d69880db196ef31bfb241 kprintf.c -b60b40ad630f26b7923369df95b4d1b9 fpga.c -5013ecca0a38a8fcc4a61642754f2076 fourbri.c -1501ae468a0c5eaab1e60720fa723a67 fcheck.c -# end of md5sums diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/pc.h linux/drivers/isdn/eicon/pc.h --- v2.4.2/linux/drivers/isdn/eicon/pc.h Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/pc.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.2 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/pc_maint.h linux/drivers/isdn/eicon/pc_maint.h --- v2.4.2/linux/drivers/isdn/eicon/pc_maint.h Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/pc_maint.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.0 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/pr_pc.h linux/drivers/isdn/eicon/pr_pc.h --- v2.4.2/linux/drivers/isdn/eicon/pr_pc.h Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/pr_pc.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.0 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/pri.c linux/drivers/isdn/eicon/pri.c --- v2.4.2/linux/drivers/isdn/eicon/pri.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/pri.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.5 * * This program is free software; you can redistribute it and/or modify @@ -82,7 +79,7 @@ void mem_inc(ADAPTER *a, void *adr); int DivasPRIInitPCI(card_t *card, dia_card_t *cfg); -int pri_ISR (card_t* card); +static int pri_ISR (card_t* card); static int diva_server_reset(card_t *card) { @@ -156,7 +153,7 @@ UxCardMemOut(card->hw, &shared[ 8], config->tei); UxCardMemOut(card->hw, &shared[ 9], config->nt2); - UxCardMemOut(card->hw, &shared[10], 0); + UxCardMemOut(card->hw, &shared[10], config->sig_flags); UxCardMemOut(card->hw, &shared[11], config->watchdog); UxCardMemOut(card->hw, &shared[12], config->permanent); UxCardMemOut(card->hw, &shared[13], config->x_interface); @@ -509,7 +506,7 @@ } -int pri_ISR (card_t* card) +static int pri_ISR (card_t* card) { int served = 0; byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/sys.h linux/drivers/isdn/eicon/sys.h --- v2.4.2/linux/drivers/isdn/eicon/sys.h Mon Dec 11 13:21:41 2000 +++ linux/drivers/isdn/eicon/sys.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.2 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/uxio.h linux/drivers/isdn/eicon/uxio.h --- v2.4.2/linux/drivers/isdn/eicon/uxio.h Mon Dec 11 13:21:41 2000 +++ linux/drivers/isdn/eicon/uxio.h Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.6 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/xlog.c linux/drivers/isdn/eicon/xlog.c --- v2.4.2/linux/drivers/isdn/eicon/xlog.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/xlog.c Fri Mar 2 11:12:08 2001 @@ -3,9 +3,6 @@ * * Copyright (C) Eicon Technology Corporation, 2000. * - * This source file is supplied for the exclusive use with Eicon - * Technology Corporation's range of DIVA Server Adapters. - * * Eicon File Revision : 1.2 * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile --- v2.4.2/linux/drivers/isdn/hisax/Makefile Sat Feb 3 19:51:27 2001 +++ linux/drivers/isdn/hisax/Makefile Fri Mar 2 11:12:08 2001 @@ -34,6 +34,7 @@ hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o +hisax-objs-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o hisax-objs-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c --- v2.4.2/linux/drivers/isdn/hisax/amd7930.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/amd7930.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: amd7930.c,v 1.5 2000/11/24 17:05:37 kai Exp $ +/* $Id: amd7930.c,v 1.5.6.1 2001/02/16 16:43:25 kai Exp $ * * HiSax ISDN driver - chip specific routines for AMD 7930 * @@ -14,7 +14,7 @@ * * The code is unreliable enough to be consider alpha * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the * SparcStation 1+. The chip provides microphone and speaker interfaces @@ -94,7 +94,7 @@ #include "rawhdlc.h" #include -static const char *amd7930_revision = "$Revision: 1.5 $"; +static const char *amd7930_revision = "$Revision: 1.5.6.1 $"; #define RCV_BUFSIZE 1024 /* Size of raw receive buffer in bytes */ #define RCV_BUFBLKS 4 /* Number of blocks to divide buffer into diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c --- v2.4.2/linux/drivers/isdn/hisax/arcofi.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/arcofi.c Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: arcofi.c,v 1.12 2000/11/25 17:01:00 kai Exp $ +/* $Id: arcofi.c,v 1.12.6.1 2001/02/16 16:43:25 kai Exp $ * * arcofi.c Ansteuerung ARCOFI 2165 * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/arcofi.h linux/drivers/isdn/hisax/arcofi.h --- v2.4.2/linux/drivers/isdn/hisax/arcofi.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/arcofi.h Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: arcofi.h,v 1.6 2000/06/26 08:59:12 keil Exp $ +/* $Id: arcofi.h,v 1.6.6.1 2001/02/16 16:43:25 kai Exp $ * * arcofi.h Ansteuerung ARCOFI 2165 * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c --- v2.4.2/linux/drivers/isdn/hisax/asuscom.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/asuscom.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: asuscom.c,v 1.11 2000/11/24 17:05:37 kai Exp $ +/* $Id: asuscom.c,v 1.11.6.1 2001/02/16 16:43:25 kai Exp $ * * asuscom.c low level stuff for ASUSCOM NETWORK INC. ISDNLink cards * @@ -6,7 +6,7 @@ * * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for informations * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -20,7 +20,7 @@ extern const char *CardType[]; -const char *Asuscom_revision = "$Revision: 1.11 $"; +const char *Asuscom_revision = "$Revision: 1.11.6.1 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c --- v2.4.2/linux/drivers/isdn/hisax/avm_a1.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/avm_a1.c Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: avm_a1.c,v 2.13 2000/11/24 17:05:37 kai Exp $ +/* $Id: avm_a1.c,v 2.13.6.1 2001/02/16 16:43:25 kai Exp $ * * avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ @@ -15,7 +15,7 @@ #include "isdnl1.h" extern const char *CardType[]; -static const char *avm_revision = "$Revision: 2.13 $"; +static const char *avm_revision = "$Revision: 2.13.6.1 $"; #define AVM_A1_STAT_ISAC 0x01 #define AVM_A1_STAT_HSCX 0x02 diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/avm_a1p.c linux/drivers/isdn/hisax/avm_a1p.c --- v2.4.2/linux/drivers/isdn/hisax/avm_a1p.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/avm_a1p.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: avm_a1p.c,v 2.7 2000/11/24 17:05:37 kai Exp $ +/* $Id: avm_a1p.c,v 2.7.6.1 2001/02/16 16:43:25 kai Exp $ * * avm_a1p.c low level stuff for the following AVM cards: * A1 PCMCIA @@ -7,7 +7,7 @@ * * Author Carsten Paeth (calle@calle.in-berlin.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License */ #define __NO_VERSION__ #include @@ -53,7 +53,7 @@ #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) -static const char *avm_revision = "$Revision: 2.7 $"; +static const char *avm_revision = "$Revision: 2.7.6.1 $"; static inline u_char ReadISAC(struct IsdnCardState *cs, u_char offset) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c --- v2.4.2/linux/drivers/isdn/hisax/avm_pci.c Wed Nov 29 10:12:29 2000 +++ linux/drivers/isdn/hisax/avm_pci.c Fri Mar 2 11:12:08 2001 @@ -1,11 +1,11 @@ -/* $Id: avm_pci.c,v 1.22.6.2 2000/11/29 16:00:14 kai Exp $ +/* $Id: avm_pci.c,v 1.22.6.4 2001/02/16 16:43:25 kai Exp $ * * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ @@ -18,7 +18,7 @@ #include extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.22.6.2 $"; +static const char *avm_pci_rev = "$Revision: 1.22.6.4 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c --- v2.4.2/linux/drivers/isdn/hisax/bkm_a4t.c Wed Nov 29 10:12:29 2000 +++ linux/drivers/isdn/hisax/bkm_a4t.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: bkm_a4t.c,v 1.13.6.2 2000/11/29 16:00:14 kai Exp $ +/* $Id: bkm_a4t.c,v 1.13.6.4 2001/02/16 16:43:25 kai Exp $ * bkm_a4t.c low level stuff for T-Berkom A4T * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -6,7 +6,7 @@ * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -24,7 +24,7 @@ extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.13.6.2 $"; +const char *bkm_a4t_revision = "$Revision: 1.13.6.4 $"; static inline u_char diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c --- v2.4.2/linux/drivers/isdn/hisax/bkm_a8.c Wed Nov 29 10:12:29 2000 +++ linux/drivers/isdn/hisax/bkm_a8.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.14.6.2 2000/11/29 16:00:14 kai Exp $ +/* $Id: bkm_a8.c,v 1.14.6.4 2001/02/16 16:43:25 kai Exp $ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -6,7 +6,7 @@ * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ @@ -27,7 +27,7 @@ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.14.6.2 $"; +const char sct_quadro_revision[] = "$Revision: 1.14.6.4 $"; static const char *sct_quadro_subtypes[] = { diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/bkm_ax.h linux/drivers/isdn/hisax/bkm_ax.h --- v2.4.2/linux/drivers/isdn/hisax/bkm_ax.h Tue Nov 28 21:44:41 2000 +++ linux/drivers/isdn/hisax/bkm_ax.h Fri Mar 2 18:38:37 2001 @@ -1,9 +1,9 @@ -/* $Id: bkm_ax.h,v 1.5.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: bkm_ax.h,v 1.5.6.2 2001/02/16 16:43:25 kai Exp $ * bkm_ax.h low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c --- v2.4.2/linux/drivers/isdn/hisax/callc.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/callc.c Fri Mar 2 11:12:08 2001 @@ -1,9 +1,9 @@ -/* $Id: callc.c,v 2.51 2000/11/24 17:05:37 kai Exp $ +/* $Id: callc.c,v 2.51.6.1 2001/02/16 16:43:25 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -20,7 +20,7 @@ #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module)) #endif /* MODULE */ -const char *lli_revision = "$Revision: 2.51 $"; +const char *lli_revision = "$Revision: 2.51.6.1 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -337,7 +337,7 @@ * RESUME */ -/* incomming call */ +/* incoming call */ static void lli_deliver_call(struct FsmInst *fi, int event, void *arg) @@ -1026,9 +1026,11 @@ printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg); } -static void +static int init_PStack(struct PStack **stp) { *stp = kmalloc(sizeof(struct PStack), GFP_ATOMIC); + if (!*stp) + return -ENOMEM; (*stp)->next = NULL; (*stp)->l1.l1l2 = dummy_pstack; (*stp)->l1.l1hw = dummy_pstack; @@ -1041,16 +1043,20 @@ (*stp)->l3.l3l4 = dummy_pstack; (*stp)->lli.l4l3 = dummy_pstack; (*stp)->ma.layer = dummy_pstack; + return 0; } -static void +static int init_d_st(struct Channel *chanp) { struct PStack *st; struct IsdnCardState *cs = chanp->cs; char tmp[16]; + int err; - init_PStack(&chanp->d_st); + err = init_PStack(&chanp->d_st); + if (err) + return err; st = chanp->d_st; st->next = NULL; HiSax_addlist(cs, st); @@ -1075,6 +1081,8 @@ st->lli.userdata = chanp; st->lli.l2writewakeup = NULL; st->l3.l3l4 = dchan_l3l4; + + return 0; } static void @@ -1090,10 +1098,11 @@ va_end(args); } -static void +static int init_chan(int chan, struct IsdnCardState *csta) { struct Channel *chanp = csta->channel + chan; + int err; chanp->cs = csta; chanp->bcs = csta->bcs + chan; @@ -1102,7 +1111,9 @@ chanp->debug = 0; chanp->Flags = 0; chanp->leased = 0; - init_PStack(&chanp->b_st); + err = init_PStack(&chanp->b_st); + if (err) + return err; chanp->b_st->l1.delay = DEFAULT_B_DELAY; chanp->fi.fsm = &callcfsm; chanp->fi.state = ST_NULL; @@ -1112,31 +1123,41 @@ FsmInitTimer(&chanp->fi, &chanp->dial_timer); FsmInitTimer(&chanp->fi, &chanp->drel_timer); if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) { - init_d_st(chanp); + err = init_d_st(chanp); + if (err) + return err; } else { chanp->d_st = csta->channel->d_st; } chanp->data_open = 0; + return 0; } int CallcNewChan(struct IsdnCardState *csta) { - int i; + int i, err; chancount += 2; - init_chan(0, csta); - init_chan(1, csta); + err = init_chan(0, csta); + if (err) + return err; + err = init_chan(1, csta); + if (err) + return err; printk(KERN_INFO "HiSax: 2 channels added\n"); - for (i = 0; i < MAX_WAITING_CALLS; i++) - init_chan(i+2,csta); + for (i = 0; i < MAX_WAITING_CALLS; i++) { + err = init_chan(i+2,csta); + if (err) + return err; + } printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n"); if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) { printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); csta->channel->d_st->lli.l4l3(csta->channel->d_st, DL_ESTABLISH | REQUEST, NULL); } - return (2); + return (0); } static void diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/cert.c linux/drivers/isdn/hisax/cert.c --- v2.4.2/linux/drivers/isdn/hisax/cert.c Mon Aug 21 07:49:02 2000 +++ linux/drivers/isdn/hisax/cert.c Fri Mar 2 11:12:08 2001 @@ -1,8 +1,8 @@ -/* $Id: cert.c,v 2.3 2000/06/26 08:59:12 keil Exp $ +/* $Id: cert.c,v 2.3.6.1 2001/02/16 16:43:25 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.4.2/linux/drivers/isdn/hisax/config.c Sat Feb 3 19:51:27 2001 +++ linux/drivers/isdn/hisax/config.c Fri Mar 2 11:12:08 2001 @@ -1,9 +1,9 @@ -/* $Id: config.c,v 2.57.6.6 2000/12/10 23:39:19 kai Exp $ +/* $Id: config.c,v 2.57.6.10 2001/02/16 16:43:25 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #include @@ -11,7 +11,6 @@ #include #include #include -#include #include "hisax.h" #include #include @@ -1195,7 +1194,12 @@ return (0); } init_tei(cs, cs->protocol); - CallcNewChan(cs); + ret = CallcNewChan(cs); + if (ret) { + closecard(cardnr); + restore_flags(flags); + return 0; + } /* ISAR needs firmware download first */ if (!test_bit(HW_ISAR, &cs->HW_Flags)) ll_run(cs, 0); @@ -1326,8 +1330,7 @@ #endif } -int __init -HiSax_init(void) +static int __init HiSax_init(void) { int i,j; int nzproto = 0; @@ -1497,11 +1500,7 @@ } } -#ifdef MODULE -int init_module(void) { return HiSax_init(); } - -void -cleanup_module(void) +static void __exit HiSax_exit(void) { int cardnr = nrcards -1; long flags; @@ -1518,7 +1517,6 @@ restore_flags(flags); printk(KERN_INFO "HiSax module removed\n"); } -#endif #ifdef CONFIG_HISAX_ELSA int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot) @@ -1707,6 +1705,8 @@ return (ret); } +#include + static struct pci_device_id hisax_pci_tbl[] __initdata = { #ifdef CONFIG_HISAX_FRITZPCI {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID}, @@ -1770,3 +1770,6 @@ }; MODULE_DEVICE_TABLE(pci, hisax_pci_tbl); + +module_init(HiSax_init); +module_exit(HiSax_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.4.2/linux/drivers/isdn/hisax/diva.c Wed Nov 29 10:12:29 2000 +++ linux/drivers/isdn/hisax/diva.c Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: diva.c,v 1.25.6.2 2000/11/29 16:00:14 kai Exp $ +/* $Id: diva.c,v 1.25.6.4 2001/02/16 16:43:25 kai Exp $ * * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -24,7 +24,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.25.6.2 $"; +const char *Diva_revision = "$Revision: 1.25.6.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.4.2/linux/drivers/isdn/hisax/elsa.c Tue Nov 28 21:44:41 2000 +++ linux/drivers/isdn/hisax/elsa.c Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: elsa.c,v 2.26.6.1 2000/11/28 12:02:46 kai Exp $ +/* $Id: elsa.c,v 2.26.6.3 2001/02/16 16:43:25 kai Exp $ * * elsa.c low level stuff for Elsa isdn cards * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -30,7 +30,7 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.26.6.1 $"; +const char *Elsa_revision = "$Revision: 2.26.6.3 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/elsa_ser.c linux/drivers/isdn/hisax/elsa_ser.c --- v2.4.2/linux/drivers/isdn/hisax/elsa_ser.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/elsa_ser.c Fri Mar 2 11:12:08 2001 @@ -1,8 +1,8 @@ -/* $Id: elsa_ser.c,v 2.10 2000/11/19 17:02:47 kai Exp $ +/* $Id: elsa_ser.c,v 2.10.6.1 2001/02/16 16:43:26 kai Exp $ * * stuff for the serial modem on ELSA cards * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #include diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c --- v2.4.2/linux/drivers/isdn/hisax/fsm.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/fsm.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: fsm.c,v 1.14 2000/11/24 17:05:37 kai Exp $ +/* $Id: fsm.c,v 1.14.6.1 2001/02/16 16:43:26 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -6,7 +6,7 @@ * Thanks to Jan den Ouden * Fritz Elfert * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c --- v2.4.2/linux/drivers/isdn/hisax/gazel.c Wed Nov 29 10:12:29 2000 +++ linux/drivers/isdn/hisax/gazel.c Fri Mar 2 11:12:08 2001 @@ -1,11 +1,11 @@ -/* $Id: gazel.c,v 2.11.6.2 2000/11/29 16:00:14 kai Exp $ +/* $Id: gazel.c,v 2.11.6.4 2001/02/16 16:43:26 kai Exp $ * * gazel.c low level stuff for Gazel isdn cards * * Author BeWan Systems * based on source code from Karsten Keil * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #include @@ -19,7 +19,7 @@ #include extern const char *CardType[]; -const char *gazel_revision = "$Revision: 2.11.6.2 $"; +const char *gazel_revision = "$Revision: 2.11.6.4 $"; #define R647 1 #define R685 2 diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c --- v2.4.2/linux/drivers/isdn/hisax/hfc_2bds0.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/hfc_2bds0.c Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: hfc_2bds0.c,v 1.15 2000/11/24 17:05:37 kai Exp $ +/* $Id: hfc_2bds0.c,v 1.15.6.1 2001/02/16 16:43:26 kai Exp $ * * specific routines for CCD's HFC 2BDS0 * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_2bds0.h linux/drivers/isdn/hisax/hfc_2bds0.h --- v2.4.2/linux/drivers/isdn/hisax/hfc_2bds0.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/hfc_2bds0.h Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: hfc_2bds0.h,v 1.4 2000/06/26 08:59:12 keil Exp $ +/* $Id: hfc_2bds0.h,v 1.4.6.1 2001/02/16 16:43:27 kai Exp $ * * specific defines for CCD's HFC 2BDS0 * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c --- v2.4.2/linux/drivers/isdn/hisax/hfc_2bs0.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/hfc_2bs0.c Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: hfc_2bs0.c,v 1.17 2000/11/24 17:05:37 kai Exp $ +/* $Id: hfc_2bs0.c,v 1.17.6.1 2001/02/16 16:43:27 kai Exp $ * * specific routines for CCD's HFC 2BS0 * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_2bs0.h linux/drivers/isdn/hisax/hfc_2bs0.h --- v2.4.2/linux/drivers/isdn/hisax/hfc_2bs0.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/hfc_2bs0.h Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: hfc_2bs0.h,v 1.3 2000/06/26 08:59:13 keil Exp $ +/* $Id: hfc_2bs0.h,v 1.3.6.1 2001/02/16 16:43:27 kai Exp $ * * specific defines for CCD's HFC 2BS0 * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.4.2/linux/drivers/isdn/hisax/hfc_pci.c Fri Dec 29 14:07:22 2000 +++ linux/drivers/isdn/hisax/hfc_pci.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.34.6.3 2000/12/10 23:39:19 kai Exp $ +/* $Id: hfc_pci.c,v 1.34.6.4 2001/02/13 10:33:58 kai Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -35,7 +35,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.34.6.3 $"; +static const char *hfcpci_revision = "$Revision: 1.34.6.4 $"; /* table entry in the PCI devices list */ typedef struct { diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfcscard.c linux/drivers/isdn/hisax/hfcscard.c --- v2.4.2/linux/drivers/isdn/hisax/hfcscard.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/hfcscard.c Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: hfcscard.c,v 1.8 2000/11/24 17:05:37 kai Exp $ +/* $Id: hfcscard.c,v 1.8.6.1 2001/02/16 16:43:27 kai Exp $ * * hfcscard.c low level stuff for hfcs based cards (Teles3c, ACER P10) * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -16,7 +16,7 @@ extern const char *CardType[]; -static const char *hfcs_revision = "$Revision: 1.8 $"; +static const char *hfcs_revision = "$Revision: 1.8.6.1 $"; static void hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.4.2/linux/drivers/isdn/hisax/hisax.h Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/hisax/hisax.h Fri Mar 2 11:12:08 2001 @@ -1,8 +1,8 @@ -/* $Id: hisax.h,v 2.52.6.1 2000/12/06 16:59:19 kai Exp $ +/* $Id: hisax.h,v 2.52.6.3 2001/02/16 16:43:27 kai Exp $ * * Basic declarations, defines and prototypes * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #include @@ -126,13 +126,13 @@ #define l3dss1_process #include "l3dss1.h" #undef l3dss1_process -#endif CONFIG_HISAX_EURO +#endif /* CONFIG_HISAX_EURO */ #ifdef CONFIG_HISAX_NI1 #define l3ni1_process #include "l3ni1.h" #undef l3ni1_process -#endif CONFIG_HISAX_NI1 +#endif /* CONFIG_HISAX_NI1 */ #define MAX_DFRAME_LEN 260 #define MAX_DFRAME_LEN_L1 300 @@ -318,10 +318,10 @@ { u_char uuuu; /* only as dummy */ #ifdef CONFIG_HISAX_EURO dss1_stk_priv dss1; /* private dss1 data */ -#endif CONFIG_HISAX_EURO +#endif /* CONFIG_HISAX_EURO */ #ifdef CONFIG_HISAX_NI1 ni1_stk_priv ni1; /* private ni1 data */ -#endif CONFIG_HISAX_NI1 +#endif /* CONFIG_HISAX_NI1 */ } prot; }; @@ -342,10 +342,10 @@ { u_char uuuu; /* only when euro not defined, avoiding empty union */ #ifdef CONFIG_HISAX_EURO dss1_proc_priv dss1; /* private dss1 data */ -#endif CONFIG_HISAX_EURO +#endif /* CONFIG_HISAX_EURO */ #ifdef CONFIG_HISAX_NI1 ni1_proc_priv ni1; /* private ni1 data */ -#endif CONFIG_HISAX_NI1 +#endif /* CONFIG_HISAX_NI1 */ } prot; }; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hscx.c linux/drivers/isdn/hisax/hscx.c --- v2.4.2/linux/drivers/isdn/hisax/hscx.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/hscx.c Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: hscx.c,v 1.21 2000/11/24 17:05:37 kai Exp $ +/* $Id: hscx.c,v 1.21.6.1 2001/02/16 16:43:27 kai Exp $ * * hscx.c HSCX specific routines * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hscx.h linux/drivers/isdn/hisax/hscx.h --- v2.4.2/linux/drivers/isdn/hisax/hscx.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/hscx.h Fri Mar 2 11:12:08 2001 @@ -1,10 +1,10 @@ -/* $Id: hscx.h,v 1.6 2000/06/26 08:59:13 keil Exp $ +/* $Id: hscx.h,v 1.6.6.1 2001/02/16 16:43:27 kai Exp $ * * hscx.h HSCX specific defines * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hscx_irq.c linux/drivers/isdn/hisax/hscx_irq.c --- v2.4.2/linux/drivers/isdn/hisax/hscx_irq.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/hscx_irq.c Fri Mar 2 11:12:08 2001 @@ -1,4 +1,4 @@ -/* $Id: hscx_irq.c,v 1.16 2000/11/19 17:02:47 kai Exp $ +/* $Id: hscx_irq.c,v 1.16.6.1 2001/02/16 16:43:27 kai Exp $ * * hscx_irq.c low level b-channel stuff for Siemens HSCX * @@ -6,7 +6,7 @@ * * This is an include file for fast inline IRQ stuff * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/icc.c linux/drivers/isdn/hisax/icc.c --- v2.4.2/linux/drivers/isdn/hisax/icc.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/icc.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -// $Id: icc.c,v 1.5 2000/11/24 17:05:37 kai Exp $ +// $Id: icc.c,v 1.5.6.1 2001/02/16 16:43:27 kai Exp $ //----------------------------------------------------------------------------- // // ICC specific routines @@ -7,10 +7,10 @@ // www.traverse.com.au // // 1999.6.25 Initial implementation of routines for Siemens ISDN -// Communication Controler PEB 2070 based on the ISAC routines +// Communication Controller PEB 2070 based on the ISAC routines // written by Karsten Keil. // -// This file is (c) under GNU PUBLIC LICENSE +// This file is (c) under GNU General Public License // //----------------------------------------------------------------------------- diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/icc.h linux/drivers/isdn/hisax/icc.h --- v2.4.2/linux/drivers/isdn/hisax/icc.h Mon Aug 21 07:49:03 2000 +++ linux/drivers/isdn/hisax/icc.h Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -// $Id: icc.h,v 1.2 2000/06/26 08:59:13 keil Exp $ +// $Id: icc.h,v 1.2.6.1 2001/02/16 16:43:27 kai Exp $ //----------------------------------------------------------------------------- // // ICC specific routines @@ -7,10 +7,10 @@ // www.traverse.com.au // // 1999.7.14 Initial implementation of routines for Siemens ISDN -// Communication Controler PEB 2070 based on the ISAC routines +// Communication Controller PEB 2070 based on the ISAC routines // written by Karsten Keil. // -// This file is (c) under GNU PUBLIC LICENSE +// This file is (c) under GNU General Public License // //----------------------------------------------------------------------------- diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/ipac.h linux/drivers/isdn/hisax/ipac.h --- v2.4.2/linux/drivers/isdn/hisax/ipac.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/ipac.h Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: ipac.h,v 1.5 2000/06/26 08:59:13 keil Exp $ +/* $Id: ipac.h,v 1.5.6.1 2001/02/16 16:43:27 kai Exp $ * * ipac.h IPAC specific defines * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c --- v2.4.2/linux/drivers/isdn/hisax/isac.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/isac.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: isac.c,v 1.28 2000/11/24 17:05:37 kai Exp $ +/* $Id: isac.c,v 1.28.6.1 2001/02/16 16:43:27 kai Exp $ * * isac.c ISAC specific routines * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert */ @@ -445,7 +445,7 @@ if (cs->debug & L1_DEB_MONITOR) debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]); } - AfterMOX1: + AfterMOX1:; #endif } } diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isac.h linux/drivers/isdn/hisax/isac.h --- v2.4.2/linux/drivers/isdn/hisax/isac.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/isac.h Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: isac.h,v 1.7 2000/06/26 08:59:13 keil Exp $ +/* $Id: isac.h,v 1.7.6.1 2001/02/16 16:43:27 kai Exp $ * * isac.h ISAC specific defines * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c --- v2.4.2/linux/drivers/isdn/hisax/isar.c Mon Nov 27 16:56:09 2000 +++ linux/drivers/isdn/hisax/isar.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: isar.c,v 1.17 2000/11/24 17:05:37 kai Exp $ +/* $Id: isar.c,v 1.17.6.1 2001/02/16 16:43:27 kai Exp $ * * isar.c ISAR (Siemens PSB 7110) specific routines * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isar.h linux/drivers/isdn/hisax/isar.h --- v2.4.2/linux/drivers/isdn/hisax/isar.h Mon Aug 21 07:49:03 2000 +++ linux/drivers/isdn/hisax/isar.h Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: isar.h,v 1.9 2000/06/26 08:59:13 keil Exp $ +/* $Id: isar.h,v 1.9.6.1 2001/02/16 16:43:27 kai Exp $ * * isar.h ISAR (Siemens PSB 7110) specific defines * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c --- v2.4.2/linux/drivers/isdn/hisax/isdnl1.c Fri Dec 29 14:07:22 2000 +++ linux/drivers/isdn/hisax/isdnl1.c Fri Mar 2 11:12:09 2001 @@ -1,11 +1,11 @@ -/* $Id: isdnl1.c,v 2.41.6.1 2000/12/10 22:01:04 kai Exp $ +/* $Id: isdnl1.c,v 2.41.6.2 2001/02/16 16:43:27 kai Exp $ * * isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards * based on the teles driver from Jan den Ouden * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -15,7 +15,7 @@ * */ -const char *l1_revision = "$Revision: 2.41.6.1 $"; +const char *l1_revision = "$Revision: 2.41.6.2 $"; #define __NO_VERSION__ #include diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h --- v2.4.2/linux/drivers/isdn/hisax/isdnl1.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/isdnl1.h Fri Mar 2 11:12:09 2001 @@ -1,8 +1,8 @@ -/* $Id: isdnl1.h,v 2.9 2000/06/26 08:59:13 keil Exp $ +/* $Id: isdnl1.h,v 2.9.6.1 2001/02/16 16:43:27 kai Exp $ * * Layer 1 defines * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c --- v2.4.2/linux/drivers/isdn/hisax/isdnl2.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/isdnl2.c Fri Mar 2 11:12:09 2001 @@ -1,9 +1,9 @@ -/* $Id: isdnl2.c,v 2.25 2000/11/24 17:05:38 kai Exp $ +/* $Id: isdnl2.c,v 2.25.6.1 2001/02/16 16:43:27 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -16,7 +16,7 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.25 $"; +const char *l2_revision = "$Revision: 2.25.6.1 $"; static void l2m_debug(struct FsmInst *fi, char *fmt, ...); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl2.h linux/drivers/isdn/hisax/isdnl2.h --- v2.4.2/linux/drivers/isdn/hisax/isdnl2.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/isdnl2.h Fri Mar 2 11:12:09 2001 @@ -1,8 +1,8 @@ -/* $Id: isdnl2.h,v 1.3 2000/06/26 08:59:13 keil Exp $ +/* $Id: isdnl2.h,v 1.3.6.1 2001/02/16 16:43:27 kai Exp $ * * Layer 2 defines * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c --- v2.4.2/linux/drivers/isdn/hisax/isdnl3.c Sat Feb 3 19:51:27 2001 +++ linux/drivers/isdn/hisax/isdnl3.c Fri Mar 2 11:12:09 2001 @@ -1,9 +1,9 @@ -/* $Id: isdnl3.c,v 2.17 2000/11/24 17:05:38 kai Exp $ +/* $Id: isdnl3.c,v 2.17.6.2 2001/02/16 16:43:27 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -18,7 +18,7 @@ #include "isdnl3.h" #include -const char *l3_revision = "$Revision: 2.17 $"; +const char *l3_revision = "$Revision: 2.17.6.2 $"; static struct Fsm l3fsm; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl3.h linux/drivers/isdn/hisax/isdnl3.h --- v2.4.2/linux/drivers/isdn/hisax/isdnl3.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/isdnl3.h Fri Mar 2 11:12:09 2001 @@ -1,6 +1,6 @@ -/* $Id: isdnl3.h,v 2.6 2000/06/26 08:59:13 keil Exp $ +/* $Id: isdnl3.h,v 2.6.6.1 2001/02/16 16:43:27 kai Exp $ * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c --- v2.4.2/linux/drivers/isdn/hisax/isurf.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/isurf.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: isurf.c,v 1.10 2000/11/24 17:05:38 kai Exp $ +/* $Id: isurf.c,v 1.10.6.1 2001/02/16 16:43:27 kai Exp $ * * isurf.c low level stuff for Siemens I-Surf/I-Talk cards * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -17,7 +17,7 @@ extern const char *CardType[]; -static const char *ISurf_revision = "$Revision: 1.10 $"; +static const char *ISurf_revision = "$Revision: 1.10.6.1 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c --- v2.4.2/linux/drivers/isdn/hisax/ix1_micro.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/ix1_micro.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: ix1_micro.c,v 2.10 2000/11/24 17:05:38 kai Exp $ +/* $Id: ix1_micro.c,v 2.10.6.1 2001/02/16 16:43:27 kai Exp $ * * ix1_micro.c low level stuff for ITK ix1-micro Rev.2 isdn cards * derived from the original file teles3.c from Karsten Keil @@ -14,7 +14,7 @@ /* For the modification done by the author the following terms and conditions - apply (GNU PUBLIC LICENSE) + apply (GNU General Public License) This program is free software; you can redistribute it and/or modify @@ -50,7 +50,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *ix1_revision = "$Revision: 2.10 $"; +const char *ix1_revision = "$Revision: 2.10.6.1 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/jade.c linux/drivers/isdn/hisax/jade.c --- v2.4.2/linux/drivers/isdn/hisax/jade.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/jade.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: jade.c,v 1.6 2000/11/24 17:05:38 kai Exp $ +/* $Id: jade.c,v 1.6.6.1 2001/02/16 16:43:27 kai Exp $ * * jade.c JADE stuff (derived from original hscx.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/jade.h linux/drivers/isdn/hisax/jade.h --- v2.4.2/linux/drivers/isdn/hisax/jade.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/jade.h Fri Mar 2 11:12:09 2001 @@ -1,9 +1,9 @@ -/* $Id: jade.h,v 1.3 2000/06/26 08:59:14 keil Exp $ +/* $Id: jade.h,v 1.3.6.1 2001/02/16 16:43:27 kai Exp $ * jade.h JADE specific defines * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/jade_irq.c linux/drivers/isdn/hisax/jade_irq.c --- v2.4.2/linux/drivers/isdn/hisax/jade_irq.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/jade_irq.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: jade_irq.c,v 1.5 2000/11/19 17:02:48 kai Exp $ +/* $Id: jade_irq.c,v 1.5.6.1 2001/02/16 16:43:27 kai Exp $ * * jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c --- v2.4.2/linux/drivers/isdn/hisax/l3_1tr6.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/l3_1tr6.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: l3_1tr6.c,v 2.13 2000/11/19 17:02:48 kai Exp $ +/* $Id: l3_1tr6.c,v 2.13.6.1 2001/02/16 16:43:27 kai Exp $ * * German 1TR6 D-channel protocol * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -17,7 +17,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *l3_1tr6_revision = "$Revision: 2.13 $"; +const char *l3_1tr6_revision = "$Revision: 2.13.6.1 $"; #define MsgHead(ptr, cref, mty, dis) \ *ptr++ = dis; \ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3_1tr6.h linux/drivers/isdn/hisax/l3_1tr6.h --- v2.4.2/linux/drivers/isdn/hisax/l3_1tr6.h Sun Aug 6 12:43:41 2000 +++ linux/drivers/isdn/hisax/l3_1tr6.h Fri Mar 2 11:12:09 2001 @@ -1,8 +1,8 @@ -/* $Id: l3_1tr6.h,v 2.2 2000/06/26 08:59:14 keil Exp $ +/* $Id: l3_1tr6.h,v 2.2.6.1 2001/02/16 16:43:27 kai Exp $ * * German 1TR6 D-channel protocol defines * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #ifndef l3_1tr6 diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.4.2/linux/drivers/isdn/hisax/l3dss1.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/l3dss1.c Fri Mar 2 11:12:09 2001 @@ -1,11 +1,11 @@ -/* $Id: l3dss1.c,v 2.30 2000/11/19 17:02:48 kai Exp $ +/* $Id: l3dss1.c,v 2.30.6.1 2001/02/16 16:43:27 kai Exp $ * * EURO/DSS1 D-channel protocol * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -22,7 +22,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.30 $"; +const char *dss1_revision = "$Revision: 2.30.6.1 $"; #define EXT_BEARER_CAPS 1 @@ -426,9 +426,9 @@ #undef FOO1 } -#else not HISAX_DE_AOC +#else /* not HISAX_DE_AOC */ l3_debug(st, "invoke break"); -#endif not HISAX_DE_AOC +#endif /* not HISAX_DE_AOC */ break; case 2: /* return result */ /* if no process available handle separately */ @@ -438,12 +438,12 @@ return; } if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) - { /* Diversion successfull */ + { /* Diversion successful */ free_invoke_id(st,pc->prot.dss1.invoke_id); pc->prot.dss1.remote_result = 0; /* success */ pc->prot.dss1.invoke_id = 0; pc->redir_result = pc->prot.dss1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */ + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ else l3_debug(st,"return error unknown identifier"); break; @@ -2112,7 +2112,7 @@ MsgHead(p, pc->callref, MT_FACILITY); for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ - if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ + if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */ *p++ = 0x1c; /* Facility info element */ *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ @@ -2138,7 +2138,7 @@ *p++ = pc->chan->setup.phone[l]; if (len_sub) - { *p++ = 0x04; /* called party subadress */ + { *p++ = 0x04; /* called party subaddress */ *p++ = len_sub - 2; while (*subp) *p++ = *subp++; } diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3dss1.h linux/drivers/isdn/hisax/l3dss1.h --- v2.4.2/linux/drivers/isdn/hisax/l3dss1.h Sun Aug 6 12:43:42 2000 +++ linux/drivers/isdn/hisax/l3dss1.h Fri Mar 2 11:12:09 2001 @@ -1,8 +1,8 @@ -/* $Id: l3dss1.h,v 1.10 2000/06/26 08:59:14 keil Exp $ +/* $Id: l3dss1.h,v 1.10.6.1 2001/02/16 16:43:28 kai Exp $ * * DSS1 (Euro) D-channel protocol defines * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3ni1.c linux/drivers/isdn/hisax/l3ni1.c --- v2.4.2/linux/drivers/isdn/hisax/l3ni1.c Fri Dec 29 14:07:22 2000 +++ linux/drivers/isdn/hisax/l3ni1.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -// $Id: l3ni1.c,v 2.5.6.1 2000/12/06 16:59:19 kai Exp $ +// $Id: l3ni1.c,v 2.5.6.2 2001/02/16 16:43:28 kai Exp $ // //----------------------------------------------------------------------------- // @@ -16,7 +16,7 @@ // Will Scales - beta tester extraordinaire // Brett Whittacre - beta tester and remote devel system in Vegas // -// This file is (c) under GNU PUBLIC LICENSE +// This file is (c) under GNU General Public License // //----------------------------------------------------------------------------- #define __NO_VERSION__ @@ -26,7 +26,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *ni1_revision = "$Revision: 2.5.6.1 $"; +const char *ni1_revision = "$Revision: 2.5.6.2 $"; #define EXT_BEARER_CAPS 1 @@ -372,12 +372,12 @@ return; } if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) - { /* Diversion successfull */ + { /* Diversion successful */ free_invoke_id(st,pc->prot.ni1.invoke_id); pc->prot.ni1.remote_result = 0; /* success */ pc->prot.ni1.invoke_id = 0; pc->redir_result = pc->prot.ni1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successfull */ + st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ else l3_debug(st,"return error unknown identifier"); break; @@ -1973,7 +1973,7 @@ MsgHead(p, pc->callref, MT_FACILITY); for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ - if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ + if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */ *p++ = 0x1c; /* Facility info element */ *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ @@ -1999,7 +1999,7 @@ *p++ = pc->chan->setup.phone[l]; if (len_sub) - { *p++ = 0x04; /* called party subadress */ + { *p++ = 0x04; /* called party subaddress */ *p++ = len_sub - 2; while (*subp) *p++ = *subp++; } diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3ni1.h linux/drivers/isdn/hisax/l3ni1.h --- v2.4.2/linux/drivers/isdn/hisax/l3ni1.h Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/l3ni1.h Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -// $Id: l3ni1.h,v 2.3 2000/11/16 13:50:43 keil Exp $ +// $Id: l3ni1.h,v 2.3.6.1 2001/02/16 16:43:28 kai Exp $ //----------------------------------------------------------------------------- // // NI1 D-channel protocol @@ -12,7 +12,7 @@ // code provided by Ragnar Paulson. // // -// This file is (c) under GNU PUBLIC LICENSE +// This file is (c) under GNU General Public License // //----------------------------------------------------------------------------- diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/lmgr.c linux/drivers/isdn/hisax/lmgr.c --- v2.4.2/linux/drivers/isdn/hisax/lmgr.c Sun Aug 6 12:43:42 2000 +++ linux/drivers/isdn/hisax/lmgr.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: lmgr.c,v 1.7 2000/06/26 08:59:14 keil Exp $ +/* $Id: lmgr.c,v 1.7.6.1 2001/02/16 16:43:28 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * * Layermanagement module * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c --- v2.4.2/linux/drivers/isdn/hisax/mic.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/mic.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: mic.c,v 1.10 2000/11/24 17:05:38 kai Exp $ +/* $Id: mic.c,v 1.10.6.1 2001/02/16 16:43:28 kai Exp $ * * mic.c low level stuff for mic cards * @@ -6,7 +6,7 @@ * * Author Stephan von Krawczynski * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -19,7 +19,7 @@ extern const char *CardType[]; -const char *mic_revision = "$Revision: 1.10 $"; +const char *mic_revision = "$Revision: 1.10.6.1 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.4.2/linux/drivers/isdn/hisax/netjet.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/hisax/netjet.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: netjet.c,v 1.24.6.2 2000/12/17 22:45:11 kai Exp $ +/* $Id: netjet.c,v 1.24.6.4 2001/02/16 16:43:28 kai Exp $ * * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * @@ -6,7 +6,7 @@ * * Thanks to Traverse Technologie Australia for documents and informations * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -22,7 +22,7 @@ #include #include "netjet.h" -const char *NETjet_revision = "$Revision: 1.24.6.2 $"; +const char *NETjet_revision = "$Revision: 1.24.6.4 $"; /* Interface functions */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/netjet.h linux/drivers/isdn/hisax/netjet.h --- v2.4.2/linux/drivers/isdn/hisax/netjet.h Tue Nov 28 21:44:41 2000 +++ linux/drivers/isdn/hisax/netjet.h Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -// $Id: netjet.h,v 2.5.6.1 2000/11/28 12:02:46 kai Exp $ +// $Id: netjet.h,v 2.5.6.2 2001/02/16 16:43:28 kai Exp $ //----------------------------------------------------------------------------- // // NETjet common header file @@ -6,7 +6,7 @@ // Author Kerstern Keil repackaged by // Matt Henderson - Traverse Technologies P/L www.traverse.com.au // -// This file is (c) under GNU PUBLIC LICENSE +// This file is (c) under GNU General Public License // //----------------------------------------------------------------------------- diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c --- v2.4.2/linux/drivers/isdn/hisax/niccy.c Wed Nov 29 10:12:29 2000 +++ linux/drivers/isdn/hisax/niccy.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: niccy.c,v 1.15.6.2 2000/11/29 16:00:14 kai Exp $ +/* $Id: niccy.c,v 1.15.6.4 2001/02/16 16:43:28 kai Exp $ * * niccy.c low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and * compatible (SAGEM cybermodem) @@ -7,7 +7,7 @@ * * Thanks to Dr. Neuhaus and SAGEM for informations * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -22,7 +22,7 @@ #include extern const char *CardType[]; -const char *niccy_revision = "$Revision: 1.15.6.2 $"; +const char *niccy_revision = "$Revision: 1.15.6.4 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/nj_s.c linux/drivers/isdn/hisax/nj_s.c --- v2.4.2/linux/drivers/isdn/hisax/nj_s.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/hisax/nj_s.c Fri Mar 2 11:12:09 2001 @@ -1,6 +1,6 @@ -// $Id: nj_s.c,v 2.7.6.2 2001/02/07 11:31:31 kai Exp $ +// $Id: nj_s.c,v 2.7.6.4 2001/02/16 16:43:28 kai Exp $ // -// This file is (c) under GNU PUBLIC LICENSE +// This file is (c) under GNU General Public License // #define __NO_VERSION__ @@ -14,7 +14,7 @@ #include #include "netjet.h" -const char *NETjet_S_revision = "$Revision: 2.7.6.2 $"; +const char *NETjet_S_revision = "$Revision: 2.7.6.4 $"; static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) { diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/nj_u.c linux/drivers/isdn/hisax/nj_u.c --- v2.4.2/linux/drivers/isdn/hisax/nj_u.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/hisax/nj_u.c Fri Mar 2 11:12:09 2001 @@ -1,6 +1,6 @@ -/* $Id: nj_u.c,v 2.8.6.2 2001/02/07 11:31:31 kai Exp $ +/* $Id: nj_u.c,v 2.8.6.4 2001/02/16 16:43:28 kai Exp $ * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -15,7 +15,7 @@ #include #include "netjet.h" -const char *NETjet_U_revision = "$Revision: 2.8.6.2 $"; +const char *NETjet_U_revision = "$Revision: 2.8.6.4 $"; static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) { diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c --- v2.4.2/linux/drivers/isdn/hisax/q931.c Mon Aug 21 07:49:03 2000 +++ linux/drivers/isdn/hisax/q931.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: q931.c,v 1.10 2000/06/26 08:59:14 keil Exp $ +/* $Id: q931.c,v 1.10.6.1 2001/02/16 16:43:28 kai Exp $ * * q931.c code to decode ITU Q.931 call control messages * * Author Jan den Ouden * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * * Changelog * @@ -1228,7 +1228,7 @@ finish = 1; } } else if (sapi == TEI_SAPI) { - dp += sprintf(dp, "tei managment\n"); + dp += sprintf(dp, "tei management\n"); finish = 1; } else { dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/rawhdlc.c linux/drivers/isdn/hisax/rawhdlc.c --- v2.4.2/linux/drivers/isdn/hisax/rawhdlc.c Sun Aug 6 12:43:42 2000 +++ linux/drivers/isdn/hisax/rawhdlc.c Fri Mar 2 11:12:09 2001 @@ -1,11 +1,11 @@ -/* $Id: rawhdlc.c,v 1.5 2000/06/26 08:59:14 keil Exp $ +/* $Id: rawhdlc.c,v 1.5.6.1 2001/02/16 16:43:28 kai Exp $ * * rawhdlc.c support routines for cards that don't support HDLC * * Author Karsten Keil (keil@isdn4linux.de) * Brent Baccala * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930, * don't perform HDLC encapsulation over the B channel. Drivers for diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/rawhdlc.h linux/drivers/isdn/hisax/rawhdlc.h --- v2.4.2/linux/drivers/isdn/hisax/rawhdlc.h Sun Aug 6 12:43:42 2000 +++ linux/drivers/isdn/hisax/rawhdlc.h Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: rawhdlc.h,v 1.3 2000/06/26 08:59:14 keil Exp $ +/* $Id: rawhdlc.h,v 1.3.6.1 2001/02/16 16:43:29 kai Exp $ * * rawhdlc.h support routines for cards that don't support HDLC * * Author Brent Baccala * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/s0box.c linux/drivers/isdn/hisax/s0box.c --- v2.4.2/linux/drivers/isdn/hisax/s0box.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/s0box.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: s0box.c,v 2.4 2000/11/24 17:05:38 kai Exp $ +/* $Id: s0box.c,v 2.4.6.1 2001/02/16 16:43:29 kai Exp $ * * s0box.c low level stuff for Creatix S0BOX * * Author S0BOX specific stuff: Enrik Berkhan (enrik@starfleet.inka.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ @@ -15,7 +15,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *s0box_revision = "$Revision: 2.4 $"; +const char *s0box_revision = "$Revision: 2.4.6.1 $"; static inline void writereg(unsigned int padr, signed int addr, u_char off, u_char val) { diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c --- v2.4.2/linux/drivers/isdn/hisax/saphir.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/saphir.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: saphir.c,v 1.8 2000/11/24 17:05:38 kai Exp $ +/* $Id: saphir.c,v 1.8.6.1 2001/02/16 16:43:29 kai Exp $ * * saphir.c low level stuff for HST Saphir 1 * @@ -6,7 +6,7 @@ * * Thanks to HST High Soft Tech GmbH * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -19,7 +19,7 @@ #include "isdnl1.h" extern const char *CardType[]; -static char *saphir_rev = "$Revision: 1.8 $"; +static char *saphir_rev = "$Revision: 1.8.6.1 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.4.2/linux/drivers/isdn/hisax/sedlbauer.c Wed Nov 29 10:35:15 2000 +++ linux/drivers/isdn/hisax/sedlbauer.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.25.6.2 2000/11/29 17:48:59 kai Exp $ +/* $Id: sedlbauer.c,v 1.25.6.4 2001/02/16 16:43:29 kai Exp $ * * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -16,7 +16,7 @@ * Sedlbauer AG for informations * Edgar Toernig * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -52,7 +52,7 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.25.6.2 $"; +const char *Sedlbauer_revision = "$Revision: 1.25.6.4 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/sedlbauer_cs.c linux/drivers/isdn/hisax/sedlbauer_cs.c --- v2.4.2/linux/drivers/isdn/hisax/sedlbauer_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/isdn/hisax/sedlbauer_cs.c Fri Mar 2 11:12:09 2001 @@ -0,0 +1,682 @@ +/*====================================================================== + + A Sedlbauer PCMCIA client driver + + This driver is for the Sedlbauer Speed Star and Speed Star II, + which are ISDN PCMCIA Cards. + + sedlbauer_cs.c 1.1a 2001/01/28 15:04:04 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann + . All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +static char *version = +"sedlbauer_cs.c 1.1a 2001/01/28 15:04:04 (M.Niemann)"; +#else +#define DEBUG(n, args...) +#endif + + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_int irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +static int protocol = 2; /* EURO-ISDN Default */ +MODULE_PARM(protocol, "i"); + +extern int sedl_init_pcmcia(int, int, int*, int); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card + insertion and ejection events. They are invoked from the sedlbauer + event handler. +*/ + +static void sedlbauer_config(dev_link_t *link); +static void sedlbauer_release(u_long arg); +static int sedlbauer_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *sedlbauer_attach(void); +static void sedlbauer_detach(dev_link_t *); + +/* + You'll also need to prototype all the functions that will actually + be used to talk to your device. See 'memory_cs' for a good example + of a fully self-sufficient driver; the other drivers rely more or + less on other parts of the kernel. +*/ + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "sedlbauer_cs"; + +/* + A linked list of "instances" of the sedlbauer device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + To simplify the data structure handling, we actually include the + dev_link_t structure in the device's private data structure. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally shouldn't be allocated dynamically. + + In this case, we also provide a flag to indicate if a device is + "stopped" due to a power management event, or card ejection. The + device IO routines can use a flag like this to throttle IO to a + card that is not ready to accept it. + + The bus_operations pointer is used on platforms for which we need + to use special socket-specific versions of normal IO primitives + (inb, outb, readb, writeb, etc) for card IO. +*/ + +typedef struct local_info_t { + dev_link_t link; + dev_node_t node; + int stop; + struct bus_operations *bus; +} local_info_t; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + sedlbauer_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + +======================================================================*/ + +static dev_link_t *sedlbauer_attach(void) +{ + local_info_t *local; + dev_link_t *link; + client_reg_t client_reg; + int ret, i; + + DEBUG(0, "sedlbauer_attach()\n"); + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) return NULL; + memset(local, 0, sizeof(local_info_t)); + link = &local->link; link->priv = local; + + /* Initialize the dev_link_t structure */ + link->release.function = &sedlbauer_release; + link->release.data = (u_long)link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + + /* from old sedl_cs + */ + /* The io structure describes IO port mapping */ + link->io.NumPorts1 = 8; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = 3; + + + link->conf.Attributes = 0; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &sedlbauer_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + sedlbauer_detach(link); + return NULL; + } + + return link; +} /* sedlbauer_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void sedlbauer_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "sedlbauer_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + /* + If the device is currently configured and active, we won't + actually delete it yet. Instead, it is marked so that when + the release() function is called, that will trigger a proper + detach(). + */ + if (link->state & DEV_CONFIG) { +#ifdef PCMCIA_DEBUG + printk(KERN_DEBUG "sedlbauer_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + return; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, and free it */ + *linkp = link->next; + /* This points to the parent local_info_t struct */ + kfree(link->priv); +} /* sedlbauer_detach */ + +/*====================================================================== + + sedlbauer_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + +======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +static void sedlbauer_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + local_info_t *dev = link->priv; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + u_char buf[64]; + config_info_t conf; + win_req_t req; + memreq_t map; + + + DEBUG(0, "sedlbauer_config(0x%p)\n", link); + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; + if (cfg->index == 0) goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<vcc.param[CISTPL_POWER_VNOM]/10000) + goto next_entry; + } else if (dflt.vcc.present & (1<vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; +/* new in dummy.cs 2001/01/28 MN + link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; +*/ + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + } + + /* + Now set up a common memory window, if needed. There is room + in the dev_link_t structure for one memory window handle, + but if the base addresses need to be saved, or if multiple + windows are needed, the info should go in the private data + structure for this device. + + Note that the memory window base is a physical address, and + needs to be mapped to virtual space with ioremap() before it + is used. + */ + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + cistpl_mem_t *mem = + (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; + req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req.Attributes |= WIN_ENABLE; + req.Base = mem->win[0].host_addr; + req.Size = mem->win[0].len; +/* new in dummy.cs 2001/01/28 MN + if (req.Size < 0x1000) + req.Size = 0x1000; +*/ + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + CFG_CHECK(RequestWindow, &link->win, &req); + map.Page = 0; map.CardOffset = mem->win[0].card_addr; + CFG_CHECK(MapMemPage, link->win, &map); + } + /* If we got this far, we're cool! */ + break; + + next_entry: +/* new in dummy.cs 2001/01/28 MN + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); +*/ + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, link->handle, &link->irq); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + sprintf(dev->node.dev_name, "sedlbauer"); + dev->node.major = dev->node.minor = 0; + link->dev = &dev->node; + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + dev->node.dev_name, link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + if (link->win) + printk(", mem 0x%06lx-0x%06lx", req.Base, + req.Base+req.Size-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + + sedl_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ, + &(((local_info_t*)link->priv)->stop), + protocol); + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + sedlbauer_release((u_long)link); + +} /* sedlbauer_config */ + +/*====================================================================== + + After a card is removed, sedlbauer_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + +======================================================================*/ + +static void sedlbauer_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + DEBUG(0, "sedlbauer_release(0x%p)\n", link); + + /* + If the device is currently in use, we won't release until it + is actually closed, because until then, we can't be sure that + no one will try to access the device or its data structures. + */ + if (link->open) { + DEBUG(1, "sedlbauer_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ + link->dev = NULL; + + /* + In a normal driver, additional code may be needed to release + other kernel data structures associated with this device. + */ + + /* Don't bother checking to see if these succeed or not */ + if (link->win) + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + sedlbauer_detach(link); + +} /* sedlbauer_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private flag to block future accesses to this device. All the + functions that actually access the device should check this flag + to make sure the card is still present. + +======================================================================*/ + +static int sedlbauer_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + local_info_t *dev = link->priv; + + DEBUG(1, "sedlbauer_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + ((local_info_t *)link->priv)->stop = 1; + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dev->bus = args->bus; + sedlbauer_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + /* Mark the device as stopped, to block IO until later */ + dev->stop = 1; + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + CardServices(RequestConfiguration, link->handle, &link->conf); + dev->stop = 0; + /* + In a normal driver, additional code may go here to restore + the device state and restart IO. + */ + break; + } + return 0; +} /* sedlbauer_event */ + +/*====================================================================*/ + +static int __init init_sedlbauer_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "sedlbauer_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &sedlbauer_attach, &sedlbauer_detach); + return 0; +} + +static void __exit exit_sedlbauer_cs(void) +{ + DEBUG(0, "sedlbauer_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) { + del_timer(&dev_list->release); + if (dev_list->state & DEV_CONFIG) + sedlbauer_release((u_long)dev_list); + sedlbauer_detach(dev_list); + } +} + +module_init(init_sedlbauer_cs); +module_exit(exit_sedlbauer_cs); + diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c --- v2.4.2/linux/drivers/isdn/hisax/sportster.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/sportster.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: sportster.c,v 1.14 2000/11/24 17:05:38 kai Exp $ +/* $Id: sportster.c,v 1.14.6.1 2001/02/16 16:43:29 kai Exp $ * * sportster.c low level stuff for USR Sportster internal TA * @@ -6,7 +6,7 @@ * * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ @@ -17,7 +17,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *sportster_revision = "$Revision: 1.14 $"; +const char *sportster_revision = "$Revision: 1.14.6.1 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c --- v2.4.2/linux/drivers/isdn/hisax/tei.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/tei.c Fri Mar 2 11:12:09 2001 @@ -1,9 +1,9 @@ -/* $Id: tei.c,v 2.17 2000/11/24 17:05:38 kai Exp $ +/* $Id: tei.c,v 2.17.6.1 2001/02/16 16:43:29 kai Exp $ * * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * For changes and modifications please read * ../../../Documentation/isdn/HiSax.cert * @@ -17,7 +17,7 @@ #include #include -const char *tei_revision = "$Revision: 2.17 $"; +const char *tei_revision = "$Revision: 2.17.6.1 $"; #define ID_REQUEST 1 #define ID_ASSIGNED 2 diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c --- v2.4.2/linux/drivers/isdn/hisax/teleint.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/teleint.c Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: teleint.c,v 1.14 2000/11/24 17:05:38 kai Exp $ +/* $Id: teleint.c,v 1.14.6.1 2001/02/16 16:43:29 kai Exp $ * * teleint.c low level stuff for TeleInt isdn cards * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -17,7 +17,7 @@ extern const char *CardType[]; -const char *TeleInt_revision = "$Revision: 1.14 $"; +const char *TeleInt_revision = "$Revision: 1.14.6.1 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c --- v2.4.2/linux/drivers/isdn/hisax/teles0.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/teles0.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: teles0.c,v 2.13 2000/11/24 17:05:38 kai Exp $ +/* $Id: teles0.c,v 2.13.6.1 2001/02/16 16:43:29 kai Exp $ * * teles0.c low level stuff for Teles Memory IO isdn cards * based on the teles driver from Jan den Ouden @@ -9,7 +9,7 @@ * Fritz Elfert * Beat Doebeli * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ @@ -21,7 +21,7 @@ extern const char *CardType[]; -const char *teles0_revision = "$Revision: 2.13 $"; +const char *teles0_revision = "$Revision: 2.13.6.1 $"; #define TELES_IOMEM_SIZE 0x400 #define byteout(addr,val) outb(val,addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c --- v2.4.2/linux/drivers/isdn/hisax/teles3.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hisax/teles3.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: teles3.c,v 2.17 2000/11/24 17:05:38 kai Exp $ +/* $Id: teles3.c,v 2.17.6.1 2001/02/16 16:43:29 kai Exp $ * * teles3.c low level stuff for Teles 16.3 & PNP isdn cards * @@ -10,7 +10,7 @@ * Fritz Elfert * Beat Doebeli * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ @@ -21,7 +21,7 @@ #include "isdnl1.h" extern const char *CardType[]; -const char *teles3_revision = "$Revision: 2.17 $"; +const char *teles3_revision = "$Revision: 2.17.6.1 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c --- v2.4.2/linux/drivers/isdn/hisax/telespci.c Wed Nov 29 10:12:29 2000 +++ linux/drivers/isdn/hisax/telespci.c Fri Mar 2 11:12:09 2001 @@ -1,11 +1,11 @@ -/* $Id: telespci.c,v 2.16.6.2 2000/11/29 16:00:14 kai Exp $ +/* $Id: telespci.c,v 2.16.6.4 2001/02/16 16:43:29 kai Exp $ * * telespci.c low level stuff for Teles PCI isdn cards * * Author Ton van Rosmalen * Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ #define __NO_VERSION__ @@ -18,7 +18,7 @@ #include extern const char *CardType[]; -const char *telespci_revision = "$Revision: 2.16.6.2 $"; +const char *telespci_revision = "$Revision: 2.16.6.4 $"; #define ZORAN_PO_RQ_PEN 0x02000000 #define ZORAN_PO_WR 0x00800000 diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c --- v2.4.2/linux/drivers/isdn/hisax/w6692.c Wed Nov 29 10:12:29 2000 +++ linux/drivers/isdn/hisax/w6692.c Fri Mar 2 11:12:09 2001 @@ -1,11 +1,11 @@ -/* $Id: w6692.c,v 1.12.6.2 2000/11/29 16:00:14 kai Exp $ +/* $Id: w6692.c,v 1.12.6.4 2001/02/16 16:43:29 kai Exp $ * * w6692.c Winbond W6692 specific routines * * Author Petr Novak * (based on HiSax driver by Karsten Keil) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ @@ -35,7 +35,7 @@ extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.12.6.2 $"; +const char *w6692_revision = "$Revision: 1.12.6.4 $"; #define DBUSY_TIMER_VALUE 80 diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/w6692.h linux/drivers/isdn/hisax/w6692.h --- v2.4.2/linux/drivers/isdn/hisax/w6692.h Sun Aug 6 12:43:42 2000 +++ linux/drivers/isdn/hisax/w6692.h Fri Mar 2 11:12:09 2001 @@ -1,10 +1,10 @@ -/* $Id: w6692.h,v 1.2 2000/06/26 08:59:15 keil Exp $ +/* $Id: w6692.h,v 1.2.6.1 2001/02/16 16:43:29 kai Exp $ * * w6692.h Winbond W6692 specific defines * * Author Petr Novak * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU General Public License * */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c --- v2.4.2/linux/drivers/isdn/hysdn/boardergo.c Fri Dec 29 14:07:22 2000 +++ linux/drivers/isdn/hysdn/boardergo.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: boardergo.c,v 1.5.6.1 2000/12/10 22:01:04 kai Exp $ +/* $Id: boardergo.c,v 1.5.6.2 2001/02/16 16:43:30 kai Exp $ * Linux driver for HYSDN cards, specific routines for ergo type boards. * @@ -270,7 +270,7 @@ return (-ERR_BOOTIMG_FAIL); } } /* start_boot_img */ - return (0); /* successfull */ + return (0); /* successful */ } /* ergo_writebootimg */ /********************************************************************************/ @@ -337,7 +337,7 @@ /***********************************************************************************/ /* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */ -/* boot process. If the process has been successfull 0 is returned otherwise a */ +/* boot process. If the process has been successful 0 is returned otherwise a */ /* negative error code is returned. */ /***********************************************************************************/ static int @@ -361,7 +361,7 @@ (dpr->ToPcSize < MIN_RDY_MSG_SIZE) || (dpr->ToPcSize > MAX_RDY_MSG_SIZE) || ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC)) - break; /* an error occured */ + break; /* an error occurred */ /* Check for additional data delivered during SysReady */ msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c --- v2.4.2/linux/drivers/isdn/hysdn/hycapi.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hysdn/hycapi.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: hycapi.c,v 1.8 2000/11/22 17:13:13 kai Exp $ +/* $Id: hycapi.c,v 1.8.6.1 2001/02/16 16:43:30 kai Exp $ * * Linux driver for HYSDN cards, CAPI2.0-Interface. * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH @@ -41,7 +41,7 @@ #include "hysdn_defs.h" #include -static char hycapi_revision[]="$Revision: 1.8 $"; +static char hycapi_revision[]="$Revision: 1.8.6.1 $"; typedef struct _hycapi_appl { unsigned int ctrl_mask; @@ -522,7 +522,7 @@ /****************************************************************** hycapi_rx_capipkt -Recieve a capi-message. +Receive a capi-message. All B3_DATA_IND are converted to 64K-extension compatible format. New nccis are created if neccessary. diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_boot.c linux/drivers/isdn/hysdn/hysdn_boot.c --- v2.4.2/linux/drivers/isdn/hysdn/hysdn_boot.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/hysdn/hysdn_boot.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_boot.c,v 1.4 2000/11/13 22:51:47 kai Exp $ +/* $Id: hysdn_boot.c,v 1.4.6.2 2001/02/16 16:43:30 kai Exp $ * Linux driver for HYSDN cards, specific routines for booting and pof handling. * @@ -49,7 +49,7 @@ uchar pof_state; /* actual state of read handler */ uchar is_crypted; /* card data is crypted */ int BufSize; /* actual number of bytes bufferd */ - int last_error; /* last occured error */ + int last_error; /* last occurred error */ word pof_recid; /* actual pof recid */ ulong pof_reclen; /* total length of pof record data */ ulong pof_recoffset; /* actual offset inside pof record */ @@ -62,7 +62,7 @@ }; /*****************************************************/ -/* start decryption of sucessive POF file chuncks. */ +/* start decryption of successive POF file chuncks. */ /* */ /* to be called at start of POF file reading, */ /* before starting any decryption on any POF record. */ @@ -93,7 +93,7 @@ /********************************************************************************/ /* pof_handle_data executes the required actions dependant on the active record */ -/* id. If successfull 0 is returned, a negative value shows an error. */ +/* id. If successful 0 is returned, a negative value shows an error. */ /********************************************************************************/ static int pof_handle_data(hysdn_card * card, int datlen) @@ -182,7 +182,7 @@ /* number of data bytes. The number delivered is additionally supplied for */ /* verification. The functions handles the data and returns the needed number */ /* of bytes for the next action. If the returned value is 0 or less an error */ -/* occured and booting must be aborted. */ +/* occurred and booting must be aborted. */ /******************************************************************************/ int pof_write_buffer(hysdn_card * card, int datlen) @@ -253,7 +253,7 @@ break; } if ((boot->last_error = pof_handle_data(card, datlen)) < 0) - return (boot->last_error); /* an error occured */ + return (boot->last_error); /* an error occurred */ boot->pof_recoffset += datlen; if (boot->pof_recoffset >= boot->pof_reclen) { boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ @@ -346,7 +346,7 @@ /*********************************************************************************/ /* EvalSysrTokData checks additional records delivered with the Sysready Message */ -/* when POF has been booted. A return value of 0 is used if no error occured. */ +/* when POF has been booted. A return value of 0 is used if no error occurred. */ /*********************************************************************************/ int EvalSysrTokData(hysdn_card * card, uchar * cp, int len) diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_init.c linux/drivers/isdn/hysdn/hysdn_init.c --- v2.4.2/linux/drivers/isdn/hysdn/hysdn_init.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/hysdn/hysdn_init.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_init.c,v 1.6.6.1 2000/11/28 12:02:47 kai Exp $ +/* $Id: hysdn_init.c,v 1.6.6.5 2001/02/16 16:43:30 kai Exp $ * Linux driver for HYSDN cards, init functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -32,7 +32,7 @@ #include "hysdn_defs.h" -static char *hysdn_init_revision = "$Revision: 1.6.6.1 $"; +static char *hysdn_init_revision = "$Revision: 1.6.6.5 $"; int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ @@ -89,6 +89,7 @@ akt_pcidev)) != NULL) { if (pci_enable_device(akt_pcidev)) continue; + if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) { printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); return; @@ -173,7 +174,6 @@ /* image becomes smaller and the driver code is only loaded when needed. */ /* Additionally newer versions may be activated without rebooting. */ /****************************************************************************/ -#ifdef CONFIG_MODULES /******************************************************/ /* extract revision number from string for log output */ @@ -197,12 +197,12 @@ /****************************************************************************/ /* init_module is called once when the module is loaded to do all necessary */ /* things like autodetect... */ -/* If the return value of this function is 0 the init has been successfull */ +/* If the return value of this function is 0 the init has been successful */ /* and the module is added to the list in /proc/modules, otherwise an error */ /* is assumed and the module will not be kept in memory. */ /****************************************************************************/ -int -init_module(void) +static int __init +hysdn_init(void) { char tmp[50]; @@ -235,14 +235,14 @@ /***********************************************************************/ /* cleanup_module is called when the module is released by the kernel. */ -/* The routine is only called if init_module has been successfull and */ +/* The routine is only called if init_module has been successful and */ /* the module counter has a value of 0. Otherwise this function will */ /* not be called. This function must release all resources still allo- */ /* cated as after the return from this function the module code will */ /* be removed from memory. */ /***********************************************************************/ -void -cleanup_module(void) +static void __exit +hysdn_exit(void) { #ifdef CONFIG_HYSDN_CAPI hysdn_card *card; @@ -261,4 +261,5 @@ printk(KERN_NOTICE "HYSDN: module unloaded\n"); } /* cleanup_module */ -#endif /* CONFIG_MODULES */ +module_init(hysdn_init); +module_exit(hysdn_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c --- v2.4.2/linux/drivers/isdn/hysdn/hysdn_net.c Fri Nov 17 11:16:20 2000 +++ linux/drivers/isdn/hysdn/hysdn_net.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_net.c,v 1.8 2000/11/13 22:51:47 kai Exp $ +/* $Id: hysdn_net.c,v 1.8.6.1 2001/02/16 16:43:30 kai Exp $ * Linux driver for HYSDN cards, net (ethernet type) handling routines. * @@ -38,7 +38,7 @@ #include "hysdn_defs.h" /* store the actual version for log reporting */ -char *hysdn_net_revision = "$Revision: 1.8 $"; +char *hysdn_net_revision = "$Revision: 1.8.6.1 $"; #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ @@ -350,7 +350,7 @@ if (card->debug_flags & LOG_NET_INIT) hysdn_addlog(card, "network device deleted"); - return (0); /* always successfull */ + return (0); /* always successful */ } /* hysdn_net_release */ /*****************************************************************************/ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c --- v2.4.2/linux/drivers/isdn/hysdn/hysdn_procconf.c Fri Nov 17 11:16:20 2000 +++ linux/drivers/isdn/hysdn/hysdn_procconf.c Fri Mar 2 11:12:10 2001 @@ -56,7 +56,7 @@ /***********************************************************************/ /* process_line parses one config line and transfers it to the card if */ /* necessary. */ -/* if the return value is negative an error occured. */ +/* if the return value is negative an error occurred. */ /***********************************************************************/ static int process_line(struct conf_writedata *cnf) @@ -130,7 +130,7 @@ if (ch == 0x1A) { /* we detected a pof file */ if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0) - return (cnf->needed_size); /* an error occured -> exit */ + return (cnf->needed_size); /* an error occurred -> exit */ cnf->buf_size = 0; /* buffer is empty */ cnf->state = CONF_STATE_POF; /* new state */ } else { @@ -158,7 +158,7 @@ cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */ if (cnf->needed_size <= 0) { cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */ - return (cnf->needed_size); /* an error occured */ + return (cnf->needed_size); /* an error occurred */ } cnf->buf_size = 0; /* buffer is empty again */ } diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_procfs.c linux/drivers/isdn/hysdn/hysdn_procfs.c --- v2.4.2/linux/drivers/isdn/hysdn/hysdn_procfs.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/isdn/hysdn/hysdn_procfs.c Fri Mar 2 11:12:10 2001 @@ -139,7 +139,7 @@ return (-ESPIPE); if ((retval = pof_boot_write(card, buf, count)) < 0) - retval = -EFAULT; /* an error occured */ + retval = -EFAULT; /* an error occurred */ return (retval); } /* hysdn_log_write */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c --- v2.4.2/linux/drivers/isdn/hysdn/hysdn_sched.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/hysdn/hysdn_sched.c Fri Mar 2 11:12:10 2001 @@ -141,7 +141,7 @@ /*****************************************************************************/ -/* send one config line to the card and return 0 if successfull, otherwise a */ +/* send one config line to the card and return 0 if successful, otherwise a */ /* negative error code. */ /* The function works with timeouts perhaps not giving the greatest speed */ /* sending the line, but this should be meaningless beacuse only some lines */ diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.4.2/linux/drivers/isdn/icn/icn.c Fri Nov 17 11:16:20 2000 +++ linux/drivers/isdn/icn/icn.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.65 2000/11/13 22:51:48 kai Exp $ +/* $Id: icn.c,v 1.65.6.3 2001/02/16 16:43:31 kai Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -21,6 +21,7 @@ */ #include "icn.h" +#include /* * Verbose bootcode- and protocol-downloading. @@ -33,7 +34,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.65 $"; +*revision = "$Revision: 1.65.6.3 $"; static int icn_addcard(int, char *, char *); @@ -867,7 +868,7 @@ SLEEP(1); memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Bootloader transfered\n"); + printk(KERN_DEBUG "Bootloader transferred\n"); #endif if (card->doubleS0) { SLEEP(1); @@ -883,7 +884,7 @@ SLEEP(1); memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG - printk(KERN_DEBUG "Bootloader transfered\n"); + printk(KERN_DEBUG "Bootloader transferred\n"); #endif } kfree(codebuf); @@ -1638,10 +1639,7 @@ return 0; } -#ifdef MODULE -#define icn_init init_module -#else -#include +#ifndef MODULE static int __init icn_setup(char *line) { @@ -1667,10 +1665,9 @@ return(1); } __setup("icn=", icn_setup); -#endif /* MODULES */ +#endif /* MODULE */ -int -icn_init(void) +static int __init icn_init(void) { char *p; char rev[10]; @@ -1681,9 +1678,6 @@ dev.mcard = NULL; dev.firstload = 1; - /* No symbols to export, hide all symbols */ - EXPORT_NO_SYMBOLS; - if ((p = strchr(revision, ':'))) { strcpy(rev, p + 1); p = strchr(rev, '$'); @@ -1695,9 +1689,7 @@ return (icn_addcard(portbase, icn_id, icn_id2)); } -#ifdef MODULE -void -cleanup_module(void) +static void __exit icn_exit(void) { isdn_ctrl cmd; icn_card *card = cards; @@ -1731,4 +1723,6 @@ release_shmem((ulong) dev.shmem, 0x4000); printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n"); } -#endif + +module_init(icn_init); +module_exit(icn_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v2.4.2/linux/drivers/isdn/icn/icn.h Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/icn/icn.h Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: icn.h,v 1.30 2000/11/13 22:51:48 kai Exp $ +/* $Id: icn.h,v 1.30.6.2 2001/02/16 16:43:31 kai Exp $ * ISDN lowlevel-module for the ICN active ISDN-Card. * @@ -217,9 +217,9 @@ #ifdef MODULE MODULE_AUTHOR("Fritz Elfert"); MODULE_PARM(portbase, "i"); -MODULE_PARM_DESC(portbase, "Port adress of first card"); +MODULE_PARM_DESC(portbase, "Port address of first card"); MODULE_PARM(membase, "i"); -MODULE_PARM_DESC(membase, "Shared memory adress of all cards"); +MODULE_PARM_DESC(membase, "Shared memory address of all cards"); MODULE_PARM(icn_id, "s"); MODULE_PARM_DESC(icn_id, "ID-String of first card"); MODULE_PARM(icn_id2, "s"); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_bsdcomp.c linux/drivers/isdn/isdn_bsdcomp.c --- v2.4.2/linux/drivers/isdn/isdn_bsdcomp.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/isdn_bsdcomp.c Fri Mar 2 11:12:09 2001 @@ -47,12 +47,8 @@ * SUCH DAMAGE. */ -#ifndef MODULE -#error This file must be compiled as a module. -#endif - #include - +#include #include #include #include @@ -919,7 +915,7 @@ * Module support routines *************************************************************/ -int init_module(void) +static int __init isdn_bsdcomp_init(void) { int answer = isdn_ppp_register_compressor (&ippp_bsd_compress); if (answer == 0) @@ -927,7 +923,10 @@ return answer; } -void cleanup_module(void) +static void __exit isdn_bsdcomp_exit(void) { isdn_ppp_unregister_compressor (&ippp_bsd_compress); } + +module_init(isdn_bsdcomp_init); +module_exit(isdn_bsdcomp_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c --- v2.4.2/linux/drivers/isdn/isdn_cards.c Fri Dec 29 14:40:54 2000 +++ linux/drivers/isdn/isdn_cards.c Wed Dec 31 16:00:00 1969 @@ -1,63 +0,0 @@ -/* $Id: isdn_cards.c,v 1.14 2000/11/23 20:45:14 kai Exp $ - - * Linux ISDN subsystem, initialization for non-modularized drivers. - * - * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include - -#ifdef CONFIG_ISDN_DRV_ICN -extern void icn_init(void); -#endif - -#ifdef CONFIG_ISDN_DRV_HISAX -extern void HiSax_init(void); -#endif - -#ifdef CONFIG_ISDN_DRV_PCBIT -extern void pcbit_init(void); -#endif - -#if defined(CONFIG_ISDN_DRV_EICON_OLD) || defined(CONFIG_ISDN_DRV_EICON_DIVAS) -extern void eicon_init(void); -#endif - -#if CONFIG_ISDN_DRV_ACT2000 -extern void act2000_init(void); -#endif - -void -isdn_cards_init(void) -{ -#if CONFIG_ISDN_DRV_ICN - icn_init(); -#endif -#ifdef CONFIG_ISDN_DRV_HISAX - HiSax_init(); -#endif -#if CONFIG_ISDN_DRV_PCBIT - pcbit_init(); -#endif -#if CONFIG_ISDN_DRV_ACT2000 - act2000_init(); -#endif -#if defined(CONFIG_ISDN_DRV_EICON_OLD) || defined(CONFIG_ISDN_DRV_EICON_DIVAS) - eicon_init(); -#endif -} diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_cards.h linux/drivers/isdn/isdn_cards.h --- v2.4.2/linux/drivers/isdn/isdn_cards.h Sun Aug 6 12:43:42 2000 +++ linux/drivers/isdn/isdn_cards.h Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* $Id: isdn_cards.h,v 1.4 2000/05/11 22:29:20 kai Exp $ - - * Linux ISDN subsystem, initialization for non-modularized drivers. - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -extern void isdn_cards_init(void); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.4.2/linux/drivers/isdn/isdn_common.c Wed Feb 21 18:20:23 2001 +++ linux/drivers/isdn/isdn_common.c Fri Mar 2 11:12:10 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.114.6.6 2001/02/07 11:31:30 kai Exp $ +/* $Id: isdn_common.c,v 1.114.6.8 2001/02/16 16:43:22 kai Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -42,9 +42,8 @@ #endif #ifdef CONFIG_ISDN_DIVERSION #include -#endif CONFIG_ISDN_DIVERSION +#endif /* CONFIG_ISDN_DIVERSION */ #include "isdn_v110.h" -#include "isdn_cards.h" #include /* Debugflags */ @@ -52,7 +51,7 @@ isdn_dev *dev; -static char *isdn_revision = "$Revision: 1.114.6.6 $"; +static char *isdn_revision = "$Revision: 1.114.6.8 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -70,7 +69,7 @@ #ifdef CONFIG_ISDN_DIVERSION static isdn_divert_if *divert_if; /* = NULL */ -#endif CONFIG_ISDN_DIVERSION +#endif /* CONFIG_ISDN_DIVERSION */ static int isdn_writebuf_stub(int, int, const u_char *, int, int); @@ -520,7 +519,7 @@ if (divert_if) if ((retval = divert_if->stat_callback(c))) return(retval); /* processed */ -#endif CONFIG_ISDN_DIVERSION +#endif /* CONFIG_ISDN_DIVERSION */ if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) { /* No tty responding */ cmd.driver = di; @@ -593,7 +592,7 @@ #ifdef CONFIG_ISDN_DIVERSION if (divert_if) divert_if->stat_callback(c); -#endif CONFIG_ISDN_DIVERSION +#endif /* CONFIG_ISDN_DIVERSION */ break; case ISDN_STAT_DISPLAY: #ifdef ISDN_DEBUG_STATCALLB @@ -603,7 +602,7 @@ #ifdef CONFIG_ISDN_DIVERSION if (divert_if) divert_if->stat_callback(c); -#endif CONFIG_ISDN_DIVERSION +#endif /* CONFIG_ISDN_DIVERSION */ break; case ISDN_STAT_DCONN: if (i < 0) @@ -645,7 +644,7 @@ #ifdef CONFIG_ISDN_DIVERSION if (divert_if) divert_if->stat_callback(c); -#endif CONFIG_ISDN_DIVERSION +#endif /* CONFIG_ISDN_DIVERSION */ break; break; case ISDN_STAT_BCONN: @@ -774,7 +773,7 @@ case ISDN_STAT_REDIR: if (divert_if) return(divert_if->stat_callback(c)); -#endif CONFIG_ISDN_DIVERSION +#endif /* CONFIG_ISDN_DIVERSION */ default: return -1; } @@ -2160,7 +2159,7 @@ EXPORT_SYMBOL(DIVERT_REG_NAME); -#endif CONFIG_ISDN_DIVERSION +#endif /* CONFIG_ISDN_DIVERSION */ EXPORT_SYMBOL(register_isdn); @@ -2409,7 +2408,6 @@ printk(" loaded\n"); #else printk("\n"); - isdn_cards_init(); #endif isdn_info_update(); return 0; diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.4.2/linux/drivers/isdn/isdn_tty.c Mon Nov 27 16:53:43 2000 +++ linux/drivers/isdn/isdn_tty.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.94 2000/11/25 17:00:59 kai Exp $ +/* $Id: isdn_tty.c,v 1.94.6.1 2001/02/16 16:43:22 kai Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -66,7 +66,7 @@ static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.94 $"; +char *isdn_tty_revision = "$Revision: 1.94.6.1 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -3773,7 +3773,7 @@ sprintf(ds, "\r\n%d", info->emu.charge); isdn_tty_at_cout(ds, info); break; - default: + default:; } break; #ifdef DUMMY_HAYES_AT diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_v110.c linux/drivers/isdn/isdn_v110.c --- v2.4.2/linux/drivers/isdn/isdn_v110.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/isdn/isdn_v110.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: isdn_v110.c,v 1.5.6.1 2001/01/23 17:45:02 kai Exp $ +/* $Id: isdn_v110.c,v 1.5.6.3 2001/02/16 16:43:23 kai Exp $ * Linux ISDN subsystem, V.110 related functions (linklevel). * @@ -30,7 +30,7 @@ #undef ISDN_V110_DEBUG -char *isdn_v110_revision = "$Revision: 1.5.6.1 $"; +char *isdn_v110_revision = "$Revision: 1.5.6.3 $"; #define V110_38400 255 #define V110_19200 15 @@ -70,7 +70,7 @@ * FlipBits reorders sequences of keylen bits in one byte. * E.g. source order 7654321 will be converted to 45670123 when keylen = 4, * and to 67452301 when keylen = 2. This is necessary because ordering on - * the isdn line is the the other way. + * the isdn line is the other way. */ static __inline unsigned char FlipBits(unsigned char c, int keylen) @@ -600,7 +600,7 @@ case ISDN_PROTO_L2_V11038: dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize); break; - default: + default:; } if ((v = dev->v110[idx])) { while (v->SyncInit) { diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c --- v2.4.2/linux/drivers/isdn/isdnloop/isdnloop.c Fri Nov 17 11:16:21 2000 +++ linux/drivers/isdn/isdnloop/isdnloop.c Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: isdnloop.c,v 1.11 2000/11/13 22:51:50 kai Exp $ +/* $Id: isdnloop.c,v 1.11.6.2 2001/02/16 16:43:32 kai Exp $ * ISDN low-level module implementing a dummy loop driver. * @@ -21,10 +21,12 @@ */ #include +#include +#include #include "isdnloop.h" static char -*revision = "$Revision: 1.11 $"; +*revision = "$Revision: 1.11.6.2 $"; static int isdnloop_addcard(char *); @@ -975,7 +977,7 @@ * user = flag: 1 = called form userlevel, 0 called from kernel. * card = pointer to card struct. * Return: - * number of bytes transfered (currently always equals len). + * number of bytes transferred (currently always equals len). */ static int isdnloop_writecmd(const u_char * buf, int len, int user, isdnloop_card * card) @@ -1534,22 +1536,7 @@ return 0; } -#ifdef MODULE -#define isdnloop_init init_module -#else -void -isdnloop_setup(char *str, int *ints) -{ - static char sid[20]; - - if (strlen(str)) { - strcpy(sid, str); - isdnloop_id = sid; - } -} -#endif - -int +static int __init isdnloop_init(void) { char *p; @@ -1568,9 +1555,8 @@ return (isdnloop_addcard(isdnloop_id)); } -#ifdef MODULE -void -cleanup_module(void) +static void __exit +isdnloop_exit(void) { isdn_ctrl cmd; isdnloop_card *card = cards; @@ -1598,4 +1584,6 @@ } printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n"); } -#endif + +module_init(isdnloop_init); +module_exit(isdnloop_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h --- v2.4.2/linux/drivers/isdn/isdnloop/isdnloop.h Wed Feb 21 18:20:24 2001 +++ linux/drivers/isdn/isdnloop/isdnloop.h Fri Mar 2 11:12:09 2001 @@ -1,4 +1,4 @@ -/* $Id: isdnloop.h,v 1.5 2000/11/13 22:51:50 kai Exp $ +/* $Id: isdnloop.h,v 1.5.6.1 2001/02/10 14:41:23 kai Exp $ * Loopback lowlevel module for testing of linklevel. * diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/callbacks.c linux/drivers/isdn/pcbit/callbacks.c --- v2.4.2/linux/drivers/isdn/pcbit/callbacks.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/isdn/pcbit/callbacks.c Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/callbacks.h linux/drivers/isdn/pcbit/callbacks.h --- v2.4.2/linux/drivers/isdn/pcbit/callbacks.h Tue Apr 23 02:31:35 1996 +++ linux/drivers/isdn/pcbit/callbacks.h Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/capi.c linux/drivers/isdn/pcbit/capi.c --- v2.4.2/linux/drivers/isdn/pcbit/capi.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/isdn/pcbit/capi.c Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/capi.h linux/drivers/isdn/pcbit/capi.h --- v2.4.2/linux/drivers/isdn/pcbit/capi.h Sat Jun 29 10:36:22 1996 +++ linux/drivers/isdn/pcbit/capi.h Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v2.4.2/linux/drivers/isdn/pcbit/drv.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/isdn/pcbit/drv.c Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/edss1.c linux/drivers/isdn/pcbit/edss1.c --- v2.4.2/linux/drivers/isdn/pcbit/edss1.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/isdn/pcbit/edss1.c Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/edss1.h linux/drivers/isdn/pcbit/edss1.h --- v2.4.2/linux/drivers/isdn/pcbit/edss1.h Tue Apr 23 02:31:35 1996 +++ linux/drivers/isdn/pcbit/edss1.h Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/layer2.c linux/drivers/isdn/pcbit/layer2.c --- v2.4.2/linux/drivers/isdn/pcbit/layer2.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/isdn/pcbit/layer2.c Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/layer2.h linux/drivers/isdn/pcbit/layer2.h --- v2.4.2/linux/drivers/isdn/pcbit/layer2.h Mon Dec 11 13:21:16 2000 +++ linux/drivers/isdn/pcbit/layer2.h Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c --- v2.4.2/linux/drivers/isdn/pcbit/module.c Mon Aug 21 07:49:03 2000 +++ linux/drivers/isdn/pcbit/module.c Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* @@ -12,7 +12,7 @@ */ #include - +#include #include #include #include @@ -26,21 +26,12 @@ static int irq[MAX_PCBIT_CARDS] = {0, }; static int num_boards; -struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0}; - -int init_module(void); -void cleanup_module(void); +struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, }; extern void pcbit_terminate(int board); extern int pcbit_init_dev(int board, int mem_base, int irq); -#ifdef MODULE -MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); -#define pcbit_init init_module -#endif - -int pcbit_init(void) +static int __init pcbit_init(void) { int board; @@ -83,15 +74,10 @@ else return -EIO; } - - /* No symbols to export, hide all symbols */ - EXPORT_NO_SYMBOLS; - return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit pcbit_exit(void) { int board; @@ -101,9 +87,8 @@ "PCBIT-D module unloaded\n"); } -#else +#ifndef MODULE #define MAX_PARA (MAX_PCBIT_CARDS * 2) -#include static int __init pcbit_setup(char *line) { int i, j, argc; @@ -134,5 +119,9 @@ __setup("pcbit=", pcbit_setup); #endif +MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i"); +module_init(pcbit_init); +module_exit(pcbit_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/pcbit.h linux/drivers/isdn/pcbit/pcbit.h --- v2.4.2/linux/drivers/isdn/pcbit/pcbit.h Thu Nov 18 21:03:01 1999 +++ linux/drivers/isdn/pcbit/pcbit.h Fri Mar 2 11:12:09 2001 @@ -4,7 +4,7 @@ * Written by Pedro Roque Marques (roque@di.fc.ul.pt) * * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. */ /* diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/sc/init.c linux/drivers/isdn/sc/init.c --- v2.4.2/linux/drivers/isdn/sc/init.c Thu Oct 12 14:19:32 2000 +++ linux/drivers/isdn/sc/init.c Fri Mar 2 11:12:10 2001 @@ -1,3 +1,5 @@ +#include +#include #include "includes.h" #include "hardware.h" #include "card.h" @@ -37,23 +39,12 @@ return 0; } -#ifdef MODULE MODULE_PARM(io, "1-4i"); MODULE_PARM(irq, "1-4i"); MODULE_PARM(ram, "1-4i"); MODULE_PARM(do_reset, "i"); -#define init_sc init_module -#else -/* -Initialization code for non-module version to be included -void sc_setup(char *str, int *ints) -{ -} -*/ -#endif - -int init_sc(void) +static int __init sc_init(void) { int b = -1; int i, j; @@ -410,8 +401,7 @@ return status; } -#ifdef MODULE -void cleanup_module(void) +static void __exit sc_exit(void) { int i, j; @@ -463,7 +453,6 @@ } pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n"); } -#endif int identify_board(unsigned long rambase, unsigned int iobase) { @@ -579,3 +568,6 @@ return -1; } + +module_init(sc_init); +module_exit(sc_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/sc/interrupt.c linux/drivers/isdn/sc/interrupt.c --- v2.4.2/linux/drivers/isdn/sc/interrupt.c Wed Apr 1 16:21:04 1998 +++ linux/drivers/isdn/sc/interrupt.c Fri Mar 2 11:12:10 2001 @@ -141,7 +141,7 @@ } else if(callid>=0x0000 && callid<=0x7FFF) { - pr_debug("%s: Got Incomming Call\n", adapter[card]->devicename); + pr_debug("%s: Got Incoming Call\n", adapter[card]->devicename); strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4])); strcpy(setup.eazmsn,adapter[card]->channel[rcvmsg.phy_link_no-1].dn); setup.si1 = 7; diff -u --recursive --new-file v2.4.2/linux/drivers/md/md.c linux/drivers/md/md.c --- v2.4.2/linux/drivers/md/md.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/md/md.c Mon Mar 12 18:13:28 2001 @@ -682,6 +682,8 @@ rdev->bdev = NULL; } +void md_autodetect_dev (kdev_t dev); + static void export_rdev (mdk_rdev_t * rdev) { printk("export_rdev(%s)\n",partition_name(rdev->dev)); @@ -696,6 +698,9 @@ md_list_del(&rdev->pending); MD_INIT_LIST_HEAD(&rdev->pending); } +#ifndef MODULE + md_autodetect_dev(rdev->dev); +#endif rdev->dev = 0; rdev->faulty = 0; kfree(rdev); @@ -3525,6 +3530,7 @@ int md__init md_init (void) { static char * name = "mdrecoveryd"; + int minor; printk (KERN_INFO "md driver %d.%d.%d MAX_MD_DEVS=%d, MD_SB_DISKS=%d\n", MD_MAJOR_VERSION, MD_MINOR_VERSION, @@ -3536,9 +3542,14 @@ return (-1); } devfs_handle = devfs_mk_dir (NULL, "md", NULL); - devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT, - MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, - &md_fops, NULL); + /* we don't use devfs_register_series because we want to fill md_hd_struct */ + for (minor=0; minor < MAX_MD_DEVS; ++minor) { + char devname[128]; + sprintf (devname, "%u", minor); + md_hd_struct[minor].de = devfs_register (devfs_handle, + devname, DEVFS_FL_DEFAULT, MAJOR_NR, minor, + S_IFBLK | S_IRUSR | S_IWUSR, &md_fops, NULL); + } /* forward all md request to md_make_request */ blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_make_request); @@ -3581,10 +3592,10 @@ * Searches all registered partitions for autorun RAID arrays * at boot time. */ -static int detected_devices[128] md__initdata; +static int detected_devices[128]; static int dev_cnt; -void md_autodetect_dev(kdev_t dev) +void md_autodetect_dev (kdev_t dev) { if (dev_cnt >= 0 && dev_cnt < 127) detected_devices[dev_cnt++] = dev; @@ -3598,7 +3609,7 @@ printk(KERN_INFO "autodetecting RAID arrays\n"); - for (i=0; ipending, &pending_raid_disks); } + dev_cnt = 0; autorun_devices(-1); } @@ -3656,7 +3668,7 @@ kdev_t device; char *devnames, *pername = ""; - if(get_option(&str, &minor) != 2) { /* MD Number */ + if (get_option(&str, &minor) != 2) { /* MD Number */ printk("md: Too few arguments supplied to md=.\n"); return 0; } @@ -3667,7 +3679,7 @@ printk ("md: Warning - md=%d,... has been specified twice;\n" " will discard the first definition.\n", minor); } - switch(get_option(&str, &level)) { /* RAID Personality */ + switch (get_option(&str, &level)) { /* RAID Personality */ case 2: /* could be 0 or -1.. */ if (level == 0 || level == -1) { if (get_option(&str, &factor) != 2 || /* Chunk Size */ @@ -3820,7 +3832,6 @@ printk(KERN_INFO "skipping autodetection of RAID arrays\n"); else autostart_arrays(); - dev_cnt = -1; /* make sure further calls to md_autodetect_dev are ignored */ md_setup_drive(); return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in --- v2.4.2/linux/drivers/media/radio/Config.in Tue Sep 19 08:01:34 2000 +++ linux/drivers/media/radio/Config.in Fri Mar 2 11:12:10 2001 @@ -21,6 +21,7 @@ if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi +dep_tristate ' Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV dep_tristate ' Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile --- v2.4.2/linux/drivers/media/radio/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/media/radio/Makefile Fri Mar 2 11:12:10 2001 @@ -31,6 +31,7 @@ obj-$(CONFIG_RADIO_CADET) += radio-cadet.o obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o +obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-aimslab.c linux/drivers/media/radio/radio-aimslab.c --- v2.4.2/linux/drivers/media/radio/radio-aimslab.c Mon Jan 1 10:14:31 2001 +++ linux/drivers/media/radio/radio-aimslab.c Fri Mar 2 11:12:10 2001 @@ -308,20 +308,19 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void rt_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct rt_device rtrack_unit; static struct video_device rtrack_radio= { + owner: THIS_MODULE, name: "RadioTrack radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_RTRACK, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-aztech.c linux/drivers/media/radio/radio-aztech.c --- v2.4.2/linux/drivers/media/radio/radio-aztech.c Mon Jan 1 10:14:31 2001 +++ linux/drivers/media/radio/radio-aztech.c Fri Mar 2 11:12:10 2001 @@ -259,20 +259,19 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void az_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct az_device aztech_unit; static struct video_device aztech_radio= { + owner: THIS_MODULE, name: "Aztech radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_AZTECH, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-cadet.c linux/drivers/media/radio/radio-cadet.c --- v2.4.2/linux/drivers/media/radio/radio-cadet.c Mon Nov 27 17:47:38 2000 +++ linux/drivers/media/radio/radio-cadet.c Fri Mar 2 11:12:10 2001 @@ -16,6 +16,10 @@ * 2000-04-29 Russell Kroll * Added ISAPnP detection for Linux 2.3/2.4 * + * 2001-01-10 Russell Kroll + * Removed dead CONFIG_RADIO_CADET_PORT code + * PnP detection on load is now default (no args necessary) + * */ #include /* Modules */ @@ -25,16 +29,12 @@ #include /* outb, outb_p */ #include /* copy to/from user */ #include /* kernel radio structs */ -#include /* CONFIG_RADIO_CADET_PORT */ #include #include -#ifndef CONFIG_RADIO_CADET_PORT -#define CONFIG_RADIO_CADET_PORT 0x330 -#endif #define RDS_BUFFER 256 -static int io=CONFIG_RADIO_CADET_PORT; +static int io=-1; /* default to isapnp activation */ static int users=0; static int curtuner=0; static int tunestat=0; @@ -518,7 +518,6 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; init_waitqueue_head(&readq); return 0; } @@ -530,12 +529,12 @@ rdsstat=0; } users--; - MOD_DEC_USE_COUNT; } static struct video_device cadet_radio= { + owner: THIS_MODULE, name: "Cadet radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_CADET, @@ -587,6 +586,11 @@ return -1; } + /* + * io should only be set if the user has used something like + * isapnp (the userspace program) to initialize this card for us + */ + static int __init cadet_init(void) { /* @@ -626,6 +630,14 @@ MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); MODULE_PARM(io, "i"); MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); + +static struct isapnp_device_id id_table[] __devinitdata = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('M','S','M'), ISAPNP_FUNCTION(0x0c24), 0 }, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, id_table); EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-gemtek.c linux/drivers/media/radio/radio-gemtek.c --- v2.4.2/linux/drivers/media/radio/radio-gemtek.c Sat Dec 30 11:19:13 2000 +++ linux/drivers/media/radio/radio-gemtek.c Fri Mar 2 11:12:10 2001 @@ -235,20 +235,19 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void gemtek_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct gemtek_device gemtek_unit; static struct video_device gemtek_radio= { + owner: THIS_MODULE, name: "GemTek radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_GEMTEK, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-maestro.c linux/drivers/media/radio/radio-maestro.c --- v2.4.2/linux/drivers/media/radio/radio-maestro.c Fri Nov 17 17:56:51 2000 +++ linux/drivers/media/radio/radio-maestro.c Fri Mar 2 11:12:10 2001 @@ -69,6 +69,7 @@ static struct video_device maestro_radio= { + owner: THIS_MODULE, name: "Maestro radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_SF16MI, @@ -282,14 +283,12 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void radio_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-maxiradio.c linux/drivers/media/radio/radio-maxiradio.c --- v2.4.2/linux/drivers/media/radio/radio-maxiradio.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-maxiradio.c Fri Mar 2 11:12:10 2001 @@ -0,0 +1,388 @@ +/* + * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux + * (C) 2001 Dimitromanolakis Apostolos + * + * Based in the radio Maestro PCI driver. Actually it uses the same chip + * for radio but different pci controller. + * + * I didn't have any specs I reversed engineered the protocol from + * the windows driver (radio.dll). + * + * The card uses the TEA5757 chip that includes a search function but it + * is useless as I haven't found any way to read back the frequency. If + * anybody does please mail me. + * + * For the pdf file see: + * http://www.semiconductors.philips.com/pip/TEA5757H/V1 + * + * + * CHANGES: + * 0.75b + * - better pci interface thanks to Francois Romieu + * + * 0.75 + * - tiding up + * - removed support for multiple devices as it didn't work anyway + * + * BUGS: + * - card unmutes if you change frequency + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* version 0.75 Sun Feb 4 22:51:27 EET 2001 */ +#define DRIVER_VERSION "0.75" + +#ifndef PCI_VENDOR_ID_GUILLEMOT +#define PCI_VENDOR_ID_GUILLEMOT 0x5046 +#endif + +#ifndef PCI_DEVICE_ID_GUILLEMOT +#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 +#endif + + +/* TEA5757 pin mappings */ +const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ; + + +#define FREQ_LO 50*16000 +#define FREQ_HI 150*16000 + +#define FREQ_IF 171200 /* 10.7*16000 */ +#define FREQ_STEP 200 /* 12.5*16 */ + +#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\ + /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */ + +#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) + + +static int radio_open(struct video_device *, int); +static int radio_ioctl(struct video_device *, unsigned int, void *); +static void radio_close(struct video_device *); + +static struct video_device maxiradio_radio= +{ + owner: THIS_MODULE, + name: "Maxi Radio FM2000 radio", + type: VID_TYPE_TUNER, + hardware: VID_HARDWARE_SF16MI, + open: radio_open, + close: radio_close, + ioctl: radio_ioctl, +}; + +static struct radio_device +{ + __u16 io, /* base of radio io */ + muted, /* VIDEO_AUDIO_MUTE */ + stereo, /* VIDEO_TUNER_STEREO_ON */ + tuned; /* signal strength (0 or 0xffff) */ + + unsigned long freq; + + struct semaphore lock; +} radio_unit = {0, 0, 0, 0, }; + + +static void sleep_125ms(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ >> 3); +} + + +static void outbit(unsigned long bit, __u16 io) +{ + if(bit != 0) + { + outb( power|wren|data ,io); udelay(4); + outb( power|wren|data|clk ,io); udelay(4); + outb( power|wren|data ,io); udelay(4); + } + else + { + outb( power|wren ,io); udelay(4); + outb( power|wren|clk ,io); udelay(4); + outb( power|wren ,io); udelay(4); + } +} + +static void turn_power(__u16 io, int p) +{ + if(p != 0) outb(power, io); else outb(0,io); +} + + +static void set_freq(__u16 io, __u32 data) +{ + unsigned long int si; + int bl; + + /* TEA5757 shift register bits (see pdf) */ + + outbit(0,io); // 24 search + outbit(1,io); // 23 search up/down + + outbit(0,io); // 22 stereo/mono + + outbit(0,io); // 21 band + outbit(0,io); // 20 band (only 00=FM works I think) + + outbit(0,io); // 19 port ? + outbit(0,io); // 18 port ? + + outbit(0,io); // 17 search level + outbit(0,io); // 16 search level + + si = 0x8000; + for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; } + + outb(power,io); +} + +static int get_stereo(__u16 io) +{ + outb(power,io); udelay(4); + return !(inb(io) & mo_st); +} + +static int get_tune(__u16 io) +{ + outb(power+clk,io); udelay(4); + return !(inb(io) & mo_st); +} + + +inline static int radio_function(struct video_device *dev, + unsigned int cmd, void *arg) +{ + struct radio_device *card=dev->priv; + switch(cmd) { + case VIDIOCGCAP: { + struct video_capability v; + + strcpy(v.name, "Maxi Radio FM2000 radio"); + v.type=VID_TYPE_TUNER; + v.channels=v.audios=1; + v.maxwidth=v.maxheight=v.minwidth=v.minheight=0; + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCGTUNER: { + struct video_tuner v; + + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + + if(v.tuner) + return -EINVAL; + + card->stereo = 0xffff * get_stereo(card->io); + card->tuned = 0xffff * get_tune(card->io); + + v.flags = VIDEO_TUNER_LOW | card->stereo; + v.signal = card->tuned; + + strcpy(v.name, "FM"); + + v.rangelow = FREQ_LO; + v.rangehigh = FREQ_HI; + v.mode = VIDEO_MODE_AUTO; + + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + + return 0; + } + case VIDIOCSTUNER: { + struct video_tuner v; + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if(v.tuner!=0) + return -EINVAL; + + return 0; + } + case VIDIOCGFREQ: { + unsigned long tmp=card->freq; + + if(copy_to_user(arg, &tmp, sizeof(tmp))) + return -EFAULT; + + return 0; + } + + case VIDIOCSFREQ: { + unsigned long tmp; + + if(copy_from_user(&tmp, arg, sizeof(tmp))) + return -EFAULT; + + if ( tmpFREQ_HI ) + return -EINVAL; + + card->freq = tmp; + + set_freq(card->io, FREQ2BITS(card->freq)); + sleep_125ms(); + + return 0; + } + case VIDIOCGAUDIO: { + struct video_audio v; + strcpy(v.name, "Radio"); + v.audio=v.volume=v.bass=v.treble=v.balance=v.step=0; + v.flags=VIDEO_AUDIO_MUTABLE | card->muted; + v.mode=VIDEO_SOUND_STEREO; + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + + case VIDIOCSAUDIO: { + struct video_audio v; + + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if(v.audio) + return -EINVAL; + + + card->muted = v.flags & VIDEO_AUDIO_MUTE; + + if(card->muted) + turn_power(card->io, 0); + else + set_freq(card->io, FREQ2BITS(card->freq)); + + return 0; + } + + case VIDIOCGUNIT: { + struct video_unit v; + v.video=VIDEO_NO_UNIT; + v.vbi=VIDEO_NO_UNIT; + v.radio=dev->minor; + v.audio=0; + v.teletext=VIDEO_NO_UNIT; + if(copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + default: return -ENOIOCTLCMD; + } +} + +static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct radio_device *card=dev->priv; + int ret; + down(&card->lock); + ret = radio_function(dev, cmd, arg); + up(&card->lock); + return ret; +} + +static int radio_open(struct video_device *dev, int flags) +{ + return 0; +} + +static void radio_close(struct video_device *dev) +{ +} + +MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); +MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); + +EXPORT_NO_SYMBOLS; + +static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + if(!request_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { + printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n"); + goto err_out; + } + + if (pci_enable_device(pdev)) + goto err_out_free_region; + + radio_unit.io = pci_resource_start(pdev, 0); + init_MUTEX(&radio_unit.lock); + maxiradio_radio.priv = &radio_unit; + + if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO)==-1) { + printk("radio-maxiradio: can't register device!"); + goto err_out_free_region; + } + + printk(KERN_INFO "radio-maxiradio: version " + DRIVER_VERSION + " time " + __TIME__ " " + __DATE__ + "\n"); + + printk(KERN_INFO "radio-maxiradio: found Guillemot MAXI Radio device (io = 0x%x)\n", + radio_unit.io); + return 0; + +err_out_free_region: + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +err_out: + return -ENODEV; +} + +static void __devexit maxiradio_remove_one(struct pci_dev *pdev) +{ + video_unregister_device(&maxiradio_radio); + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +} + +static struct pci_device_id maxiradio_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0,} +}; + +MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl); + +static struct pci_driver maxiradio_driver = { + name: "radio-maxiradio", + id_table: maxiradio_pci_tbl, + probe: maxiradio_init_one, + remove: maxiradio_remove_one, +}; + +int __init maxiradio_radio_init(void) +{ + return pci_module_init(&maxiradio_driver); +} + +void __exit maxiradio_radio_exit(void) +{ + pci_unregister_driver(&maxiradio_driver); +} + +module_init(maxiradio_radio_init); +module_exit(maxiradio_radio_exit); diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-miropcm20.c linux/drivers/media/radio/radio-miropcm20.c --- v2.4.2/linux/drivers/media/radio/radio-miropcm20.c Fri Nov 17 17:56:51 2000 +++ linux/drivers/media/radio/radio-miropcm20.c Fri Mar 2 11:12:10 2001 @@ -178,20 +178,19 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void pcm20_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct pcm20_device pcm20_unit; static struct video_device pcm20_radio= { + owner: THIS_MODULE, name: "Miro PCM 20 radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_RTRACK, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-rtrack2.c linux/drivers/media/radio/radio-rtrack2.c --- v2.4.2/linux/drivers/media/radio/radio-rtrack2.c Mon Jan 1 10:14:31 2001 +++ linux/drivers/media/radio/radio-rtrack2.c Fri Mar 2 11:12:10 2001 @@ -201,20 +201,19 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void rt_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct rt_device rtrack2_unit; static struct video_device rtrack2_radio= { + owner: THIS_MODULE, name: "RadioTrack II radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_RTRACK2, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c --- v2.4.2/linux/drivers/media/radio/radio-sf16fmi.c Mon Jan 1 10:14:31 2001 +++ linux/drivers/media/radio/radio-sf16fmi.c Fri Mar 2 11:12:10 2001 @@ -41,7 +41,7 @@ static struct semaphore lock; /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ -/* It is only usefull to give freq in intervall of 800 (=0.05Mhz), +/* It is only useful to give freq in intervall of 800 (=0.05Mhz), * other bits will be truncated, e.g 92.7400016 -> 92.7, but * 92.7400017 -> 92.75 */ @@ -262,20 +262,19 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void fmi_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct fmi_device fmi_unit; static struct video_device fmi_radio= { + owner: THIS_MODULE, name: "SF16FMx radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_SF16MI, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-terratec.c linux/drivers/media/radio/radio-terratec.c --- v2.4.2/linux/drivers/media/radio/radio-terratec.c Mon Jan 1 10:14:31 2001 +++ linux/drivers/media/radio/radio-terratec.c Fri Mar 2 11:12:10 2001 @@ -280,20 +280,19 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void tt_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct tt_device terratec_unit; static struct video_device terratec_radio= { + owner: THIS_MODULE, name: "TerraTec ActiveRadio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_TERRATEC, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-trust.c linux/drivers/media/radio/radio-trust.c --- v2.4.2/linux/drivers/media/radio/radio-trust.c Mon Jan 1 10:14:31 2001 +++ linux/drivers/media/radio/radio-trust.c Fri Mar 2 11:12:10 2001 @@ -274,18 +274,17 @@ if(users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void tr_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct video_device trust_radio= { + owner: THIS_MODULE, name: "Trust FM Radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_TRUST, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-typhoon.c linux/drivers/media/radio/radio-typhoon.c --- v2.4.2/linux/drivers/media/radio/radio-typhoon.c Mon Jan 1 10:14:31 2001 +++ linux/drivers/media/radio/radio-typhoon.c Fri Mar 2 11:12:10 2001 @@ -260,7 +260,6 @@ if (typhoon->users) return -EBUSY; typhoon->users++; - MOD_INC_USE_COUNT; return 0; } @@ -268,7 +267,6 @@ { struct typhoon_device *typhoon = dev->priv; typhoon->users--; - MOD_DEC_USE_COUNT; } static struct typhoon_device typhoon_unit = @@ -280,6 +278,7 @@ static struct video_device typhoon_radio = { + owner: THIS_MODULE, name: "Typhoon Radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_TYPHOON, diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-zoltrix.c linux/drivers/media/radio/radio-zoltrix.c --- v2.4.2/linux/drivers/media/radio/radio-zoltrix.c Mon Jan 1 10:14:31 2001 +++ linux/drivers/media/radio/radio-zoltrix.c Fri Mar 2 11:12:10 2001 @@ -327,20 +327,19 @@ if (users) return -EBUSY; users++; - MOD_INC_USE_COUNT; return 0; } static void zol_close(struct video_device *dev) { users--; - MOD_DEC_USE_COUNT; } static struct zol_device zoltrix_unit; static struct video_device zoltrix_radio = { + owner: THIS_MODULE, name: "Zoltrix Radio Plus", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_ZOLTRIX, diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c --- v2.4.2/linux/drivers/media/video/bttv-driver.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/bttv-driver.c Fri Mar 2 11:12:10 2001 @@ -1352,7 +1352,6 @@ if (bttv_debug) printk("bttv%d: open called\n",btv->nr); - MOD_INC_USE_COUNT; down(&btv->lock); if (btv->user) goto out_unlock; @@ -1378,7 +1377,6 @@ out_unlock: up(&btv->lock); - MOD_DEC_USE_COUNT; return ret; } @@ -1423,7 +1421,6 @@ rvfree((void *) btv->fbuffer, gbuffers*gbufsize); btv->fbuffer=0; up(&btv->lock); - MOD_DEC_USE_COUNT; } @@ -2053,6 +2050,7 @@ static struct video_device bttv_template= { + owner: THIS_MODULE, name: "UNSET", type: VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT, hardware: VID_HARDWARE_BT848, @@ -2140,7 +2138,6 @@ struct bttv *btv=(struct bttv *)(dev-2); unsigned long irq_flags; - MOD_INC_USE_COUNT; down(&btv->lock); if (btv->needs_restart) bt848_restart(btv); @@ -2164,7 +2161,6 @@ btv->vbi_on = 0; bt848_set_risc_jmps(btv,-1); spin_unlock_irqrestore(&btv->s_lock, irq_flags); - MOD_DEC_USE_COUNT; } static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) @@ -2202,6 +2198,7 @@ static struct video_device vbi_template= { + owner: THIS_MODULE, name: "bttv vbi", type: VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, hardware: VID_HARDWARE_BT848, @@ -2220,7 +2217,6 @@ struct bttv *btv = (struct bttv *)(dev-1); unsigned long v; - MOD_INC_USE_COUNT; down(&btv->lock); if (btv->user) goto busy_unlock; @@ -2237,7 +2233,6 @@ busy_unlock: up(&btv->lock); - MOD_DEC_USE_COUNT; return -EBUSY; } @@ -2249,7 +2244,6 @@ btv->user--; btv->radio = 0; up(&btv->lock); - MOD_DEC_USE_COUNT; } static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock) @@ -2320,6 +2314,7 @@ static struct video_device radio_template= { + owner: THIS_MODULE, name: "bttv radio", type: VID_TYPE_TUNER, hardware: VID_HARDWARE_BT848, diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h --- v2.4.2/linux/drivers/media/video/bttv.h Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/bttv.h Tue Mar 6 19:44:34 2001 @@ -151,7 +151,7 @@ /* returns card type + card ID (for bt878-based ones) for possible values see lines below beginning with #define BTTV_UNKNOWN - returns negative value if error ocurred + returns negative value if error occurred */ extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid); @@ -160,19 +160,19 @@ /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: data | (current_GPOE_value & ~mask) - returns negative value if error ocurred + returns negative value if error occurred */ extern int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data); /* fills data with GPDATA register contents - returns negative value if error ocurred + returns negative value if error occurred */ extern int bttv_read_gpio(unsigned int card, unsigned long *data); /* sets GPDATA register to new value: (data & mask) | (current_GPDATA_value & ~mask) - returns negative value if error ocurred + returns negative value if error occurred */ extern int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data); @@ -182,7 +182,7 @@ in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated (wake_up_interruptible) and following call to the function bttv_read_gpio should return new value of GPDATA, - returns NULL value if error ocurred or queue is not available + returns NULL value if error occurred or queue is not available WARNING: because there is no buffer for GPIO data, one MUST process data ASAP */ @@ -190,6 +190,9 @@ /* i2c */ #define I2C_CLIENTS_MAX 8 +extern struct i2c_algo_bit_data bttv_i2c_algo_template; +extern struct i2c_adapter bttv_i2c_adap_template; +extern struct i2c_client bttv_i2c_client_template; extern void bttv_bit_setscl(void *data, int state); extern void bttv_bit_setsda(void *data, int state); extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg); diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/buz.c linux/drivers/media/video/buz.c --- v2.4.2/linux/drivers/media/video/buz.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/buz.c Tue Mar 6 19:44:35 2001 @@ -1,4 +1,3 @@ -#define MAX_KMALLOC_MEM (512*1024) /* buz - Iomega Buz driver version 1.0 @@ -114,12 +113,12 @@ or set in in a VIDIOCSFBUF ioctl */ -static unsigned long vidmem = 0; /* Video memory base address */ +static unsigned long vidmem; /* Video memory base address (default 0) */ /* Special purposes only: */ -static int triton = 0; /* 0=no, 1=yes */ -static int natoma = 0; /* 0=no, 1=yes */ +static int triton; /* 0=no (default), 1=yes */ +static int natoma; /* 0=no (default), 1=yes */ /* Number and size of grab buffers for Video 4 Linux @@ -145,8 +144,8 @@ Default input and video norm at startup of the driver. */ -static int default_input = 0; /* 0=Composite, 1=S-VHS */ -static int default_norm = 0; /* 0=PAL, 1=NTSC */ +static int default_input; /* 0=Composite (default), 1=S-VHS */ +static int default_norm; /* 0=PAL (default), 1=NTSC */ MODULE_PARM(vidmem, "i"); MODULE_PARM(triton, "i"); @@ -174,7 +173,7 @@ * Allocate the V4L grab buffers * * These have to be pysically contiguous. - * If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc + * If v4l_bufsize <= KMALLOC_MAXSIZE we use kmalloc */ static int v4l_fbuffer_alloc(struct zoran *zr) @@ -186,7 +185,7 @@ if (zr->v4l_gbuf[i].fbuffer) printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i); - if (v4l_bufsize <= MAX_KMALLOC_MEM) { + if (v4l_bufsize <= KMALLOC_MAXSIZE) { /* Use kmalloc */ mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL); @@ -231,7 +230,7 @@ /* * Allocate the MJPEG grab buffers. * - * If the requested buffer size is smaller than MAX_KMALLOC_MEM, + * If the requested buffer size is smaller than KMALLOC_MAXSIZE, * kmalloc is used to request a physically contiguous area, * else we allocate the memory in framgents with get_free_page. * @@ -240,7 +239,7 @@ * (RJ: This statement is from Dave Perks' original driver, * I could never check it because I have a zr36067) * The driver cares about this because it reduces the buffer - * size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation). + * size to KMALLOC_MAXSIZE in that case (which forces contiguous allocation). * * RJ: The contents grab buffers needs never be accessed in the driver. * Therefore there is no need to allocate them with vmalloc in order @@ -260,7 +259,7 @@ /* Decide if we should alloc contiguous or fragmented memory */ /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ - alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); + alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE); for (i = 0; i < zr->jpg_nbufs; i++) { if (zr->jpg_gbuf[i].frag_tab) @@ -320,7 +319,7 @@ /* Decide if we should alloc contiguous or fragmented memory */ /* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */ - alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM); + alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE); for (i = 0; i < zr->jpg_nbufs; i++) { if (!zr->jpg_gbuf[i].frag_tab) @@ -388,21 +387,16 @@ DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id)); } -static struct i2c_bus zoran_i2c_bus_template = -{ - "zr36057", - I2C_BUSID_BT848, - NULL, - - SPIN_LOCK_UNLOCKED, +static struct i2c_bus zoran_i2c_bus_template = { + name: "zr36057", + id: I2C_BUSID_BT848, + bus_lock: SPIN_LOCK_UNLOCKED, - attach_inform, - detach_inform, + attach_inform: attach_inform, + detach_inform: detach_inform, - i2c_setlines, - i2c_getdataline, - NULL, - NULL, + i2c_setlines: i2c_setlines, + i2c_getdataline: i2c_getdataline, }; @@ -2267,7 +2261,6 @@ return -EBUSY; } - MOD_INC_USE_COUNT; return 0; } @@ -2295,7 +2288,6 @@ jpg_fbuffer_free(zr); zr->jpg_nbufs = 0; - MOD_DEC_USE_COUNT; DEBUG(printk(KERN_INFO ": zoran_close done\n")); } @@ -2580,7 +2572,7 @@ #endif #endif - /* Check for vaild parameters */ + /* Check for valid parameters */ if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT || vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) { return -EINVAL; @@ -2842,8 +2834,8 @@ /* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */ if (br.size > (512 * 1024)) br.size = (512 * 1024); /* 512 K should be enough */ - if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM) - br.size = MAX_KMALLOC_MEM; + if (zr->need_contiguous && br.size > KMALLOC_MAXSIZE) + br.size = KMALLOC_MAXSIZE; zr->jpg_nbufs = br.count; zr->jpg_bufsize = br.size; @@ -3029,6 +3021,7 @@ static struct video_device zoran_template = { + owner: THIS_MODULE, name: BUZ_NAME, type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, @@ -3343,7 +3336,7 @@ zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000); if (!zr->zr36057_mem) { printk(KERN_ERR "%s: ioremap failed\n", zr->name); - /* XXX handle error */ + break; } /* set PCI latency timer */ diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/bw-qcam.c linux/drivers/media/video/bw-qcam.c --- v2.4.2/linux/drivers/media/video/bw-qcam.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/bw-qcam.c Fri Mar 2 11:12:10 2001 @@ -696,13 +696,11 @@ static int qcam_open(struct video_device *dev, int flags) { - MOD_INC_USE_COUNT; return 0; } static void qcam_close(struct video_device *dev) { - MOD_DEC_USE_COUNT; } static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock) @@ -918,6 +916,7 @@ static struct video_device qcam_template= { + owner: THIS_MODULE, name: "Connectix Quickcam", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_QCAM_BW, diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c --- v2.4.2/linux/drivers/media/video/c-qcam.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/c-qcam.c Fri Mar 2 11:12:10 2001 @@ -500,13 +500,11 @@ static int qcam_open(struct video_device *dev, int flags) { - MOD_INC_USE_COUNT; return 0; } static void qcam_close(struct video_device *dev) { - MOD_DEC_USE_COUNT; } static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock) @@ -725,6 +723,7 @@ /* video device template */ static struct video_device qcam_template= { + owner: THIS_MODULE, name: "Colour QuickCam", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_QCAM_C, diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c --- v2.4.2/linux/drivers/media/video/cpia.c Fri Nov 17 17:56:51 2000 +++ linux/drivers/media/video/cpia.c Fri Mar 2 11:12:10 2001 @@ -2499,9 +2499,6 @@ cam->mmap_kludge = 0; ++cam->open_count; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif return 0; } @@ -2554,9 +2551,6 @@ } -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif return; } @@ -3031,6 +3025,7 @@ } static struct video_device cpia_template = { + owner: THIS_MODULE, name: "CPiA Camera", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_CPIA, /* FIXME */ diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/cpia.h linux/drivers/media/video/cpia.h --- v2.4.2/linux/drivers/media/video/cpia.h Mon Dec 11 13:15:37 2000 +++ linux/drivers/media/video/cpia.h Fri Mar 2 11:12:10 2001 @@ -62,7 +62,7 @@ /* transferCmd sends commands to the camera. command MUST point to * an 8 byte buffer in kernel space. data can be NULL if no extra * data is needed. The size of the data is given by the last 2 - * bytes of comand. data must also point to memory in kernel space. + * bytes of command. data must also point to memory in kernel space. * Returns negative value on error, otherwise 0. */ int (*transferCmd)(void *privdata, u8 *command, u8 *data); diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/cpia_pp.c linux/drivers/media/video/cpia_pp.c --- v2.4.2/linux/drivers/media/video/cpia_pp.c Mon Mar 27 10:22:31 2000 +++ linux/drivers/media/video/cpia_pp.c Fri Mar 2 11:12:10 2001 @@ -34,9 +34,7 @@ #include #include -#ifdef CONFIG_KMOD #include -#endif /* #define _CPIA_DEBUG_ define for verbose debug output */ #include "cpia.h" @@ -502,9 +500,6 @@ ++cam->open_count; -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif return 0; } @@ -535,9 +530,6 @@ static int cpia_pp_close(void *privdata) { struct pp_cam_entry *cam = privdata; -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif if (--cam->open_count == 0) { parport_release(cam->pdev); } diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/msp3400.c linux/drivers/media/video/msp3400.c --- v2.4.2/linux/drivers/media/video/msp3400.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/msp3400.c Tue Mar 6 19:44:35 2001 @@ -1189,7 +1189,7 @@ DECLARE_MUTEX_LOCKED(sem); struct msp3400c *msp; struct i2c_client *c; - int rev1,rev2,i; + int rev1,rev2=0,i; client_template.adapter = adap; client_template.addr = addr; @@ -1517,7 +1517,7 @@ (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c)); break; #endif - default: + default:; /* nothing */ } return 0; diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c --- v2.4.2/linux/drivers/media/video/planb.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/planb.c Fri Mar 2 11:12:10 2001 @@ -2037,6 +2037,7 @@ static struct video_device planb_template= { + owner: THIS_MODULE, name: PLANB_DEVICE_NAME, type: VID_TYPE_OVERLAY, hardware: VID_HARDWARE_PLANB, diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/pms.c linux/drivers/media/video/pms.c --- v2.4.2/linux/drivers/media/video/pms.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/pms.c Fri Mar 2 11:12:10 2001 @@ -672,13 +672,11 @@ static int pms_open(struct video_device *dev, int flags) { - MOD_INC_USE_COUNT; return 0; } static void pms_close(struct video_device *dev) { - MOD_DEC_USE_COUNT; } static long pms_write(struct video_device *v, const char *buf, unsigned long count, int noblock) @@ -902,6 +900,7 @@ struct video_device pms_template= { + owner: THIS_MODULE, name: "Mediavision PMS", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_PMS, @@ -935,14 +934,15 @@ 0xE4 }; - if(check_region(0x9A01,1)) + if (!request_region(0x9A01, 1, "Mediavision PMS config")) { printk(KERN_WARNING "mediavision: unable to detect: 0x9A01 in use.\n"); return -EBUSY; } - if(check_region(io_port,3)) + if (!request_region(io_port, 3, "Mediavision PMS")) { printk(KERN_WARNING "mediavision: I/O port %d in use.\n", io_port); + release_region(0x9A01, 1); return -EBUSY; } outb(0xB8, 0x9A01); /* Unlock */ @@ -961,16 +961,16 @@ else idec=0; - printk(KERN_INFO "PMS type is %d\n", idec); - if(idec==0) - return -ENODEV; + printk(KERN_INFO "PMS type is %d\n", idec); + if(idec == 0) { + release_region(io_port, 3); + release_region(0x9A01, 1); + return -ENODEV; + } /* * Ok we have a PMS of some sort */ - - request_region(io_port,3, "Mediavision PMS"); - request_region(0x9A01, 1, "Mediavision PMS config"); mvv_write(0x04, mem_base>>12); /* Set the memory area */ diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/stradis.c linux/drivers/media/video/stradis.c --- v2.4.2/linux/drivers/media/video/stradis.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/stradis.c Fri Mar 2 11:12:10 2001 @@ -672,7 +672,7 @@ /* auto mute off, power on, no de-emphasis */ /* I2S data up to 24-bit 64xFs internal SCLK */ I2CWrite(&(saa->i2c), 0x22, 0x01, 0x11, 2); - /* ATAPI mixer setings */ + /* ATAPI mixer settings */ I2CWrite(&(saa->i2c), 0x22, 0x02, 0x49, 2); /* attenuation left 3db */ I2CWrite(&(saa->i2c), 0x22, 0x03, 0x00, 2); @@ -1988,6 +1988,7 @@ /* template for video_device-structure */ static struct video_device saa_template = { + owner: THIS_MODULE, name: "SAA7146A", type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY, hardware: VID_HARDWARE_SAA7146, diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c --- v2.4.2/linux/drivers/media/video/videodev.c Tue Jan 2 16:45:37 2001 +++ linux/drivers/media/video/videodev.c Fri Mar 2 11:12:10 2001 @@ -166,6 +166,9 @@ goto error_out; } vfl->busy=1; /* In case vfl->open sleeps */ + + if(vfl->owner) + __MOD_INC_USE_COUNT(vfl->owner); unlock_kernel(); if(vfl->open) @@ -174,6 +177,9 @@ if(err) { vfl->busy=0; + if(vfl->owner) + __MOD_DEC_USE_COUNT(vfl->owner); + return err; } } @@ -195,6 +201,8 @@ if(vfl->close) vfl->close(vfl); vfl->busy=0; + if(vfl->owner) + __MOD_DEC_USE_COUNT(vfl->owner); unlock_kernel(); return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/vino.c linux/drivers/media/video/vino.c --- v2.4.2/linux/drivers/media/video/vino.c Fri Nov 17 17:56:51 2000 +++ linux/drivers/media/video/vino.c Fri Mar 2 11:12:10 2001 @@ -203,13 +203,11 @@ static int vino_open(struct video_device *dev, int flags) { - MOD_INC_USE_COUNT; return 0; } static void vino_close(struct video_device *dev) { - MOD_DEC_USE_COUNT; } static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg) @@ -224,6 +222,7 @@ } static struct video_device vino_dev = { + owner: THIS_MODULE, name: "Vino IndyCam/TV", type: VID_TYPE_CAPTURE, hardware: VID_HARDWARE_VINO, diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c --- v2.4.2/linux/drivers/media/video/zr36120.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/media/video/zr36120.c Fri Mar 2 11:12:10 2001 @@ -788,7 +788,6 @@ /* do the common part of all open's */ zoran_common_open(ztv, flags); - MOD_INC_USE_COUNT; return 0; } @@ -820,7 +819,6 @@ kfree( ztv->overinfo.overlay ); ztv->overinfo.overlay = 0; - MOD_DEC_USE_COUNT; } /* @@ -1482,6 +1480,7 @@ static struct video_device zr36120_template= { + owner: THIS_MODULE, name: "UNSET", type: VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, hardware: VID_HARDWARE_ZR36120, @@ -1541,7 +1540,6 @@ /* start read-ahead */ zoran_cap(ztv, 1); - MOD_INC_USE_COUNT; return 0; } @@ -1573,7 +1571,6 @@ item->memadr = 0; } - MOD_DEC_USE_COUNT; } /* @@ -1819,6 +1816,7 @@ static struct video_device vbi_template= { + owner: THIS_MODULE, name: "UNSET", type: VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, hardware: VID_HARDWARE_ZR36120, diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c503.c linux/drivers/net/3c503.c --- v2.4.2/linux/drivers/net/3c503.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/net/3c503.c Tue Mar 6 19:28:33 2001 @@ -53,8 +53,8 @@ #define WRD_COUNT 4 int el2_probe(struct net_device *dev); -int el2_pio_probe(struct net_device *dev); -int el2_probe1(struct net_device *dev, int ioaddr); +static int el2_pio_probe(struct net_device *dev); +static int el2_probe1(struct net_device *dev, int ioaddr); /* A zero-terminated list of I/O addresses to be probed in PIO mode. */ static unsigned int netcard_portlist[] __initdata = @@ -115,7 +115,7 @@ /* Try all of the locations that aren't obviously empty. This touches a lot of locations, and is much riskier than the code above. */ -int __init +static int __init el2_pio_probe(struct net_device *dev) { int i; @@ -136,13 +136,14 @@ /* Probe for the Etherlink II card at I/O port base IOADDR, returning non-zero on success. If found, set the station address and memory parameters in DEVICE. */ -int __init +static int __init el2_probe1(struct net_device *dev, int ioaddr) { int i, iobase_reg, membase_reg, saved_406, wordlength, retval; static unsigned version_printed; unsigned long vendor_id; + /* FIXME: code reads ioaddr + 0x400, we request ioaddr + 16 */ if (!request_region(ioaddr, EL2_IO_EXTENT, dev->name)) return -EBUSY; @@ -250,7 +251,8 @@ } #endif /* EL2MEMTEST */ - dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE; + if (dev->mem_start) + dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE; if (wordlength) { /* No Tx pages to skip over to get to Rx */ dev->rmem_start = dev->mem_start; diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.4.2/linux/drivers/net/3c509.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/3c509.c Mon Mar 12 18:13:28 2001 @@ -72,9 +72,9 @@ #include #ifdef EL3_DEBUG -int el3_debug = EL3_DEBUG; +static int el3_debug = EL3_DEBUG; #else -int el3_debug = 2; +static int el3_debug = 2; #endif /* To minimize the size of the driver source I only define operating @@ -158,7 +158,7 @@ int id; }; -struct el3_mca_adapters_struct el3_mca_adapters[] = { +static struct el3_mca_adapters_struct el3_mca_adapters[] = { { "3Com 3c529 EtherLink III (10base2)", 0x627c }, { "3Com 3c529 EtherLink III (10baseT)", 0x627d }, { "3Com 3c529 EtherLink III (test mode)", 0x62db }, @@ -166,27 +166,36 @@ { "3Com 3c529 EtherLink III (TP)", 0x62f7 }, { NULL, 0 }, }; -#endif +#endif /* CONFIG_MCA */ -#ifdef __ISAPNP__ -struct el3_isapnp_adapters_struct { - unsigned short vendor, function; - char *name; -}; -static struct el3_isapnp_adapters_struct el3_isapnp_adapters[] = { - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), "3Com Etherlink III (TP)"}, - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091), "3Com Etherlink III"}, - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094), "3Com Etherlink III (combo)"}, - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095), "3Com Etherlink III (TPO)"}, - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098), "3Com Etherlink III (TPC)"}, - {ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8), "3Com Etherlink III compatible"}, - {0, } +#ifdef CONFIG_ISAPNP +static struct isapnp_device_id el3_isapnp_adapters[] = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), + (long) "3Com Etherlink III (TP)" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091), + (long) "3Com Etherlink III" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094), + (long) "3Com Etherlink III (combo)" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095), + (long) "3Com Etherlink III (TPO)" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098), + (long) "3Com Etherlink III (TPC)" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8), + (long) "3Com Etherlink III compatible" }, + { } /* terminate list */ }; + +MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters); + static u16 el3_isapnp_phys_addr[8][3]; -#endif /* CONFIG_ISAPNP */ -#ifdef __ISAPNP__ static int nopnp; -#endif +#endif /* CONFIG_ISAPNP */ int el3_probe(struct net_device *dev) { @@ -196,9 +205,9 @@ u16 phys_addr[3]; static int current_tag = 0; int mca_slot = -1; -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP static int pnp_cards = 0; -#endif /* __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ if (dev) SET_MODULE_OWNER(dev); @@ -294,7 +303,7 @@ } #endif /* CONFIG_MCA */ -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP if (nopnp == 1) goto no_pnp; @@ -318,7 +327,7 @@ irq = idev->irq_resource[0].start; if (el3_debug > 3) printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n", - el3_isapnp_adapters[i].name, ioaddr, irq); + (char*) el3_isapnp_adapters[i].driver_data, ioaddr, irq); EL3WINDOW(0); for (j = 0; j < 3; j++) el3_isapnp_phys_addr[pnp_cards][j] = @@ -330,7 +339,7 @@ } } no_pnp: -#endif /* __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ /* Select an open I/O location at 0x1*0 to do contention select. */ for ( ; id_port < 0x200; id_port += 0x10) { @@ -376,7 +385,7 @@ phys_addr[i] = htons(id_read_eeprom(i)); } -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP if (nopnp == 0) { /* The ISA PnP 3c509 cards respond to the ID sequence. This check is needed in order not to register them twice. */ @@ -396,7 +405,7 @@ } } } -#endif /* __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ { unsigned int iobase = id_read_eeprom(8); @@ -984,7 +993,7 @@ MODULE_PARM(irq,"1-8i"); MODULE_PARM(xcvr,"1-8i"); MODULE_PARM(max_interrupt_work, "i"); -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP MODULE_PARM(nopnp, "i"); #endif diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.4.2/linux/drivers/net/3c515.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/3c515.c Wed Mar 7 14:08:05 2001 @@ -105,9 +105,9 @@ #define CORKSCREW_TOTAL_SIZE 0x20 #ifdef DRIVER_DEBUG -int corkscrew_debug = DRIVER_DEBUG; +static int corkscrew_debug = DRIVER_DEBUG; #else -int corkscrew_debug = 1; +static int corkscrew_debug = 1; #endif #define CORKSCREW_ID 10 @@ -351,21 +351,20 @@ { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; -#ifdef __ISAPNP__ -struct corkscrew_isapnp_adapters_struct { - unsigned short vendor, function; - char *name; -}; -struct corkscrew_isapnp_adapters_struct corkscrew_isapnp_adapters[] = { - {ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051), "3Com Fast EtherLink ISA"}, - {0, } -}; -int corkscrew_isapnp_phys_addr[3] = { - 0, 0, 0 +#ifdef CONFIG_ISAPNP +static struct isapnp_device_id corkscrew_isapnp_adapters[] = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051), + (long) "3Com Fast EtherLink ISA" }, + { } /* terminate list */ }; +MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters); + +static int corkscrew_isapnp_phys_addr[3]; + static int nopnp; -#endif +#endif /* CONFIG_ISAPNP */ static int corkscrew_scan(struct net_device *dev); static struct net_device *corkscrew_found_device(struct net_device *dev, @@ -443,12 +442,12 @@ { int cards_found = 0; static int ioaddr; -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP short i; static int pnp_cards = 0; #endif -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP if(nopnp == 1) goto no_pnp; for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) { @@ -475,7 +474,7 @@ irq = idev->irq_resource[0].start; if(corkscrew_debug) printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", - corkscrew_isapnp_adapters[i].name,ioaddr, irq); + (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq); if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) continue; @@ -506,17 +505,17 @@ } } no_pnp: -#endif /* not __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ /* Check all locations on the ISA bus -- evil! */ for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { int irq; -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP /* Make sure this was not already picked up by isapnp */ if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue; if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue; if(ioaddr == corkscrew_isapnp_phys_addr[2]) continue; -#endif +#endif /* CONFIG_ISAPNP */ if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE)) continue; /* Check the resource configuration for a matching ioaddr. */ @@ -1219,7 +1218,7 @@ #ifdef VORTEX_BUS_MASTER if (status & DMADone) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - dev_kfree_skb_irq(lp->tx_skb); /* Release the transfered buffer */ + dev_kfree_skb_irq(lp->tx_skb); /* Release the transferred buffer */ netif_wake_queue(dev); } #endif diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c523.h linux/drivers/net/3c523.h --- v2.4.2/linux/drivers/net/3c523.h Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/3c523.h Sun Mar 4 14:05:04 2001 @@ -60,7 +60,7 @@ unsigned short cbl_offset; /* pointeroffset, command block list */ unsigned short rfa_offset; /* pointeroffset, receive frame area */ unsigned short crc_errs; /* CRC-Error counter */ - unsigned short aln_errs; /* allignmenterror counter */ + unsigned short aln_errs; /* alignmenterror counter */ unsigned short rsc_errs; /* Resourceerror counter */ unsigned short ovrn_errs; /* OVerrunerror counter */ }; diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c527.c linux/drivers/net/3c527.c --- v2.4.2/linux/drivers/net/3c527.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/3c527.c Sun Mar 4 14:05:04 2001 @@ -1,8 +1,9 @@ -/* 3c527.c: 3Com Etherlink/MC32 driver for Linux +/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 * * (c) Copyright 1998 Red Hat Software Inc - * Written by Alan Cox. + * Written by Alan Cox. * Further debugging by Carl Drougge. + * Modified by Richard Procter (rnp@netlink.co.nz) * * Based on skeleton.c written 1993-94 by Donald Becker and ne2.c * (for the MCA stuff) written by Wim Dumon. @@ -16,7 +17,7 @@ */ static const char *version = - "3c527.c:v0.08 2000/02/22 Alan Cox (alan@redhat.com)\n"; + "3c527.c:v0.6 2001/03/03 Richard Proctor (rnp@netlink.co.nz)\n"; /** * DOC: Traps for the unwary @@ -24,6 +25,13 @@ * The diagram (Figure 1-1) and the POS summary disagree with the * "Interrupt Level" section in the manual. * + * The manual contradicts itself when describing the minimum number + * buffers in the 'configure lists' command. + * My card accepts a buffer config of 4/4. + * + * Setting the SAV BP bit does not save bad packets, but + * only enables RX on-card stats collection. + * * The documentation in places seems to miss things. In actual fact * I've always eventually found everything is documented, it just * requires careful study. @@ -35,25 +43,39 @@ * Intel NIC. For performance we want to keep the transmit queue deep * as the card can transmit packets while fetching others from main * memory by bus master DMA. Transmission and reception are driven by - * ring buffers. When updating the ring we are required to do some - * housekeeping work using the mailboxes and the command register. + * circular buffer queues. * - * The mailboxes provide a method for sending control requests to the - * card. The transmit mail box is used to update the transmit ring - * pointers and the receive mail box to update the receive ring - * pointers. The exec mailbox allows a variety of commands to be - * executed. Each command must complete before the next is executed. - * Primarily we use the exec mailbox for controlling the multicast lists. - * We have to do a certain amount of interesting hoop jumping as the - * multicast list changes can occur in interrupt state when the card - * has an exec command pending. We defer such events until the command - * completion interrupt. - * - * The control register is used to pass status information. It tells us - * the transmit and receive status for packets and allows us to control - * the card operation mode. You must stop the card when emptying the - * receive ring, or you will race with the ring buffer and lose packets. - */ + * The mailboxes can be used for controlling how the card traverses + * its buffer rings, but are used only for inital setup in this + * implementation. The exec mailbox allows a variety of commands to + * be executed. Each command must complete before the next is + * executed. Primarily we use the exec mailbox for controlling the + * multicast lists. We have to do a certain amount of interesting + * hoop jumping as the multicast list changes can occur in interrupt + * state when the card has an exec command pending. We defer such + * events until the command completion interrupt. + * + * A copy break scheme (taken from 3c59x.c) is employed whereby + * received frames exceeding a configurable length are passed + * directly to the higher networking layers without incuring a copy, + * in what amounts to a time/space trade-off. + * + * The card also keeps a large amount of statistical information + * on-board. In a perfect world, these could be used safely at no + * cost. However, lacking information to the contrary, processing + * them without races would involve so much extra complexity as to + * make it unworthwhile to do so. In the end, a hybrid SW/HW + * implementation was made necessary --- see mc32_update_stats(). + * + * DOC: Notes + * + * It should be possible to use two or more cards, but at this stage + * only by loading two copies of the same module. + * + * The on-board 82586 NIC has trouble receiving multiple + * back-to-back frames and so is likely to drop packets from fast + * senders. +**/ #include @@ -78,6 +100,7 @@ #include #include #include +#include #include "3c527.h" @@ -91,23 +114,37 @@ #ifndef NET_DEBUG #define NET_DEBUG 2 #endif + +#undef DEBUG_IRQ + static unsigned int mc32_debug = NET_DEBUG; /* The number of low I/O ports used by the ethercard. */ -#define NETCARD_IO_EXTENT 8 +#define MC32_IO_EXTENT 8 + +/* As implemented, values must be a power-of-2 -- 4/8/16/32 */ +#define TX_RING_LEN 32 /* Typically the card supports 37 */ +#define RX_RING_LEN 8 /* " " " */ + +/* Copy break point, see above for details. + * Setting to > 1512 effectively disables this feature. */ +#define RX_COPYBREAK 200 /* Value from 3c59x.c */ + +/* Issue the 82586 workaround command - this is for "busy lans", but + * basically means for all lans now days - has a performance (latency) + * cost, but best set. */ +static const int WORKAROUND_82586=1; +/* Pointers to buffers and their on-card records */ -struct mc32_mailbox +struct mc32_ring_desc { - u16 mbox __attribute((packed)); - u16 data[1] __attribute((packed)); + volatile struct skb_header *p; + struct sk_buff *skb; }; -/* Information that need to be kept for each board. */ - -#define TX_RING_MAX 16 /* Typically the card supports 37 */ -#define RX_RING_MAX 32 /* " " " */ +/* Information that needs to be kept for each board. */ struct mc32_local { struct net_device_stats net_stats; @@ -115,25 +152,28 @@ volatile struct mc32_mailbox *rx_box; volatile struct mc32_mailbox *tx_box; volatile struct mc32_mailbox *exec_box; - volatile u16 *stats; - u16 tx_chain; - u16 rx_chain; - u16 tx_len; - u16 rx_len; + volatile struct mc32_stats *stats; /* Start of on-card statistics */ + u16 tx_chain; /* Transmit list start offset */ + u16 rx_chain; /* Receive list start offset */ + u16 tx_len; /* Transmit list count */ + u16 rx_len; /* Receive list count */ + u32 base; - u16 rx_halted; - u16 tx_halted; - u16 rx_pending; u16 exec_pending; u16 mc_reload_wait; /* a multicast load request is pending */ - atomic_t tx_count; /* buffers left */ + u32 mc_list_valid; /* True when the mclist is set */ + u16 xceiver_state; /* Current transceiver state. bitmapped */ + u16 desired_state; /* The state we want the transceiver to be in */ + atomic_t tx_count; /* buffers left */ wait_queue_head_t event; - struct sk_buff *tx_skb[TX_RING_MAX]; /* Transmit ring */ - u16 tx_skb_top; - u16 tx_skb_end; - struct sk_buff *rx_skb[RX_RING_MAX]; /* Receive ring */ - void *rx_ptr[RX_RING_MAX]; /* Data pointers */ - u32 mc_list_valid; /* True when the mclist is set */ + + struct mc32_ring_desc tx_ring[TX_RING_LEN]; /* Host Transmit ring */ + struct mc32_ring_desc rx_ring[RX_RING_LEN]; /* Host Receive ring */ + + u16 tx_ring_tail; /* index to tx de-queue end */ + u16 tx_ring_head; /* index to tx en-queue end */ + + u16 rx_ring_tail; /* index to rx de-queue end */ }; /* The station (ethernet) address prefix, used for a sanity check. */ @@ -146,18 +186,25 @@ char *name; }; -static struct mca_adapters_t mc32_adapters[] __initdata = { +const struct mca_adapters_t mc32_adapters[] = { { 0x0041, "3COM EtherLink MC/32" }, { 0x8EF5, "IBM High Performance Lan Adapter" }, { 0x0000, NULL } }; -/* Index to functions, as function prototypes. */ +/* Macros for ring index manipulations */ +static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); }; +static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); }; +static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); }; + + +/* Index to functions, as function prototypes. */ extern int mc32_probe(struct net_device *dev); static int mc32_probe1(struct net_device *dev, int ioaddr); +static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len); static int mc32_open(struct net_device *dev); static void mc32_timeout(struct net_device *dev); static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev); @@ -167,9 +214,8 @@ static void mc32_set_multicast_list(struct net_device *dev); static void mc32_reset_multicast_list(struct net_device *dev); - /** - * mc32_probe: + * mc32_probe - Search for supported boards * @dev: device to probe * * Because MCA bus is a real bus and we can scan for cards we could do a @@ -212,7 +258,7 @@ } /** - * mc32_probe1: + * mc32_probe1 - Check a given slot for a board and test the card * @dev: Device structure to fill in * @slot: The MCA bus slot being used by this card * @@ -221,11 +267,11 @@ * in firmware so we have to wait for it to return and post us either a * failure case or some addresses we use to find the board internals. */ - + static int __init mc32_probe1(struct net_device *dev, int slot) { static unsigned version_printed = 0; - int i; + int i, err; u8 POS; u32 base; struct mc32_local *lp; @@ -258,7 +304,7 @@ "82586 initialisation failure", "Adapter list configuration error" }; - + /* Time to play MCA games */ if (mc32_debug && version_printed++ == 0) @@ -301,6 +347,12 @@ dev->irq = ((POS>>2)&3)+9; + if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname)) + { + printk("io 0x%3lX, which is busy.\n", dev->base_addr); + return -EBUSY; + } + printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n", dev->base_addr, dev->irq, dev->mem_start, i/1024); @@ -349,18 +401,20 @@ * Grab the IRQ */ - i = request_irq(dev->irq, &mc32_interrupt, 0, dev->name, dev); + i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev); if (i) { - printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + release_region(dev->base_addr, MC32_IO_EXTENT); + printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); return i; } + /* Initialize the device structure. */ dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL); if (dev->priv == NULL) { - free_irq(dev->irq, dev); - return -ENOMEM; + err = -ENOMEM; + goto err_exit_irq; } memset(dev->priv, 0, sizeof(struct mc32_local)); @@ -371,14 +425,14 @@ base = inb(dev->base_addr); - while(base==0xFF) + while(base == 0xFF) { i++; - if(i==1000) + if(i == 1000) { - printk("%s: failed to boot adapter.\n", dev->name); - free_irq(dev->irq, dev); - return -ENODEV; + printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name); + err = -ENODEV; + goto err_exit_free; } udelay(1000); if(inb(dev->base_addr+2)&(1<<5)) @@ -388,12 +442,12 @@ if(base>0) { if(base < 0x0C) - printk("%s: %s%s.\n", dev->name, failures[base-1], + printk(KERN_ERR "%s: %s%s.\n", dev->name, failures[base-1], base<0x0A?" test failure":""); else - printk("%s: unknown failure %d.\n", dev->name, base); - free_irq(dev->irq, dev); - return -ENODEV; + printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base); + err = -ENODEV; + goto err_exit_free; } base=0; @@ -408,8 +462,8 @@ if(n>100) { printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i); - free_irq(dev->irq, dev); - return -ENODEV; + err = -ENODEV; + goto err_exit_free; } } @@ -418,11 +472,11 @@ lp->exec_box=bus_to_virt(dev->mem_start+base); - base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; + base=lp->exec_box->data[1]<<16|lp->exec_box->data[0]; lp->base = dev->mem_start+base; - lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); + lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); lp->tx_box=bus_to_virt(lp->base + lp->exec_box->data[3]); lp->stats = bus_to_virt(lp->base + lp->exec_box->data[5]); @@ -431,18 +485,16 @@ * Descriptor chains (card relative) */ - lp->tx_chain = lp->exec_box->data[8]; - lp->rx_chain = lp->exec_box->data[10]; - lp->tx_len = lp->exec_box->data[9]; - lp->rx_len = lp->exec_box->data[11]; + lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ + lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ + lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ + lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ + init_waitqueue_head(&lp->event); - printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n", - dev->name, lp->rx_len, lp->tx_len, lp->base); - - if(lp->tx_len > TX_RING_MAX) - lp->tx_len = TX_RING_MAX; - + printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n", + dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base); + dev->open = mc32_open; dev->stop = mc32_close; dev->hard_start_xmit = mc32_send_packet; @@ -450,57 +502,65 @@ dev->set_multicast_list = mc32_set_multicast_list; dev->tx_timeout = mc32_timeout; dev->watchdog_timeo = HZ*5; /* Board does all the work */ + - lp->rx_halted = 1; - lp->tx_halted = 1; - lp->rx_pending = 0; + lp->xceiver_state = HALTED; + + lp->tx_ring_tail=lp->tx_ring_head=0; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); + return 0; + +err_exit_free: + kfree(dev->priv); +err_exit_irq: + free_irq(dev->irq, dev); + release_region(dev->base_addr, MC32_IO_EXTENT); + return err; } /** - * mc32_ring_poll: + * mc32_ready_poll - wait until we can feed it a command * @dev: The device to wait for * - * Wait until a command we issues to the control register is completed. - * This actually takes very little time at all, which is fortunate as - * we often have to busy wait it. + * Wait until the card becomes ready to accept a command via the + * command register. This tells us nothing about the completion + * status of any pending commands and takes very little time at all. */ -static void mc32_ring_poll(struct net_device *dev) +static void mc32_ready_poll(struct net_device *dev) { int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); } - /** - * mc32_command_nowait: + * mc32_command_nowait - send a command non blocking * @dev: The 3c527 to issue the command to * @cmd: The command word to write to the mailbox * @data: A data block if the command expects one * @len: Length of the data block * - * Send a command from interrupt state. If there is a command currently - * being executed then we return an error of -1. It simply isnt viable - * to wait around as commands may be slow. Providing we get in then - * we send the command and busy wait for the board to acknowledge that - * a command request is pending. We do not wait for the command to - * complete, just for the card to admit to noticing it. + * Send a command from interrupt state. If there is a command + * currently being executed then we return an error of -1. It simply + * isn't viable to wait around as commands may be slow. Providing we + * get in, we busy wait for the board to become ready to accept the + * command and issue it. We do not wait for the command to complete + * --- the card will interrupt us when it's done. */ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - + if(lp->exec_pending) return -1; - + lp->exec_pending=3; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; @@ -515,7 +575,7 @@ /** - * mc32_command: + * mc32_command - send a command and sleep until completion * @dev: The 3c527 card to issue the command to * @cmd: The command word to write to the mailbox * @data: A data block if the command expects one @@ -543,8 +603,6 @@ * 3 - command issued, trash reply. In which case the irq * takes it back to state 0 * - * Send command and block for results. On completion spot and reissue - * multicasts */ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) @@ -580,251 +638,287 @@ /* Send the command */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); outb(1<<6, ioaddr+HOST_CMD); - + save_flags(flags); cli(); + while(lp->exec_pending!=2) sleep_on(&lp->event); lp->exec_pending=0; restore_flags(flags); - - if(lp->exec_box->data[0]&(1<<13)) + if(lp->exec_box->mbox&(1<<13)) ret = -1; + /* * A multicast set got blocked - do it now */ if(lp->mc_reload_wait) + { mc32_reset_multicast_list(dev); + } return ret; } /** - * mc32_rx_abort: - * @dev: 3c527 to abort + * mc32_start_transceiver - tell board to restart tx/rx + * @dev: The 3c527 card to issue the command to * - * Peforms a receive abort sequence on the card. In fact after some - * experimenting we now simply tell the card to suspend reception. When - * issuing aborts occasionally odd things happened. - */ - -static void mc32_rx_abort(struct net_device *dev) -{ - struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; + * This may be called from the interrupt state, where it is used + * to restart the rx ring if the card runs out of rx buffers. + * + * First, we check if it's ok to start the transceiver. We then show + * the card where to start in the rx ring and issue the + * commands to start reception and transmission. We don't wait + * around for these to complete. + */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - - lp->rx_box->mbox=0; - outb(3<<3, ioaddr+HOST_CMD); /* Suspend reception */ -} +static void mc32_start_transceiver(struct net_device *dev) { - -/** - * mc32_rx_begin: - * @dev: 3c527 to enable - * - * We wait for any pending command to complete and then issue - * a start reception command to the board itself. At this point - * receive handling continues as it was before. - */ - -static void mc32_rx_begin(struct net_device *dev) -{ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - - lp->rx_box->mbox=0; - outb(1<<3, ioaddr+HOST_CMD); /* GO */ - mc32_ring_poll(dev); - - lp->rx_halted=0; - lp->rx_pending=0; -} -/** - * mc32_tx_abort: - * @dev: 3c527 to abort - * - * Peforms a receive abort sequence on the card. In fact after some - * experimenting we now simply tell the card to suspend transmits . When - * issuing aborts occasionally odd things happened. In theory we want - * an abort to be sure we can recycle our buffers. As it happens we - * just have to be careful to shut the card down on close, and - * boot it carefully from scratch on setup. - */ - -static void mc32_tx_abort(struct net_device *dev) -{ - struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - + /* Ignore RX overflow on device closure */ + if (lp->desired_state==HALTED) + return; + + mc32_ready_poll(dev); + lp->tx_box->mbox=0; - outb(3, ioaddr+HOST_CMD); /* Suspend */ - - /* Ring empty */ - - atomic_set(&lp->tx_count, lp->tx_len); + lp->rx_box->mbox=0; + + /* Give the card the offset to the post-EOL-bit RX descriptor */ + lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; + + outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); + + mc32_ready_poll(dev); + outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */ - /* Flush */ - if(lp->tx_skb_top!=lp->tx_skb_end) - { - int i; - if(lp->tx_skb_top<=lp->tx_skb_end) - { - for(i=lp->tx_skb_top;itx_skb_end;i++) - { - dev_kfree_skb(lp->tx_skb[i]); - lp->tx_skb[i]=NULL; - } - } - else - { - for(i=lp->tx_skb_end;itx_skb[i]); - lp->tx_skb[i]=NULL; - } - for(i=0;itx_skb_top;i++) - { - dev_kfree_skb(lp->tx_skb[i]); - lp->tx_skb[i]=NULL; - } - } - } - lp->tx_skb_top=lp->tx_skb_end=0; + /* We are not interrupted on start completion */ + lp->xceiver_state=RUNNING; } + /** - * mc32_tx_begin: - * @dev: 3c527 to enable + * mc32_halt_transceiver - tell board to stop tx/rx + * @dev: The 3c527 card to issue the command to * - * We wait for any pending command to complete and then issue - * a start transmit command to the board itself. At this point - * transmit handling continues as it was before. The ring must - * be setup before you do this and must have an end marker in it. - * It turns out we can avoid issuing this specific command when - * doing our setup so we avoid it. - */ - -static void mc32_tx_begin(struct net_device *dev) + * We issue the commands to halt the card's transceiver. In fact, + * after some experimenting we now simply tell the card to + * suspend. When issuing aborts occasionally odd things happened. + * + * We then sleep until the card has notified us that both rx and + * tx have been suspended. + */ + +static void mc32_halt_transceiver(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - + unsigned long flags; + + mc32_ready_poll(dev); + lp->tx_box->mbox=0; -#if 0 - outb(5, ioaddr+HOST_CMD); /* GO */ - printk("TX=>5\n"); - mc32_ring_poll(dev); - if(lp->tx_box->mbox&(1<<13)) - printk("TX begin error!\n"); -#endif - lp->tx_halted=0; -} + lp->rx_box->mbox=0; + + outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD); + mc32_ready_poll(dev); + outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD); + + save_flags(flags); + cli(); + + while(lp->xceiver_state!=HALTED) + sleep_on(&lp->event); + + restore_flags(flags); +} + - /** - * mc32_load_rx_ring: + * mc32_load_rx_ring - load the ring of receive buffers * @dev: 3c527 to build the ring for * - * The card setups up the receive ring for us. We are required to - * use the ring it provides although we can change the size of the - * ring. - * - * We allocate an sk_buff for each ring entry in turn and set the entry - * up for a single non s/g buffer. The first buffer we mark with the - * end marker bits. Finally we clear the rx mailbox. + * This initalises the on-card and driver datastructures to + * the point where mc32_start_transceiver() can be called. + * + * The card sets up the receive ring for us. We are required to use the + * ring it provides although we can change the size of the ring. + * + * We allocate an sk_buff for each ring entry in turn and + * initalise its house-keeping info. At the same time, we read + * each 'next' pointer in our rx_ring array. This reduces slow + * shared-memory reads and makes it easy to access predecessor + * descriptors. + * + * We then set the end-of-list bit for the last entry so that the + * card will know when it has run out of buffers. */ - + static int mc32_load_rx_ring(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; int i; - u16 base; + u16 rx_base; volatile struct skb_header *p; - base = lp->rx_box->data[0]; - - /* Fix me - should use card size - also fix flush ! */ + rx_base=lp->rx_chain; - for(i=0;irx_skb[i]=alloc_skb(1532, GFP_KERNEL); - if(lp->rx_skb[i]==NULL) + lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL); + skb_reserve(lp->rx_ring[i].skb, 18); + + if(lp->rx_ring[i].skb==NULL) { for(;i>=0;i--) - kfree_skb(lp->rx_skb[i]); + kfree_skb(lp->rx_ring[i].skb); return -ENOBUFS; } - lp->rx_ptr[i]=lp->rx_skb[i]->data+18; - p=bus_to_virt(lp->base+base); + p=bus_to_virt(lp->base+rx_base); + p->control=0; - p->data = virt_to_bus(lp->rx_ptr[i]); + p->data=virt_to_bus(lp->rx_ring[i].skb->data); p->status=0; - p->length = 1532; - base = p->next; + p->length=1532; + + lp->rx_ring[i].p=p; + rx_base=p->next; } - p->control = (1<<6); - lp->rx_box->mbox = 0; + + lp->rx_ring[i-1].p->control |= CONTROL_EOL; + + lp->rx_ring_tail=0; + return 0; } + /** - * mc32_flush_rx_ring: + * mc32_flush_rx_ring - free the ring of receive buffers * @lp: Local data of 3c527 to flush the rx ring of * - * Free the buffer for each ring slot. Because of the receive - * algorithm we use the ring will always be loaded will a full set - * of buffers. + * Free the buffer for each ring slot. This may be called + * before mc32_load_rx_ring(), eg. on error in mc32_open(). */ -static void mc32_flush_rx_ring(struct mc32_local *lp) +static void mc32_flush_rx_ring(struct net_device *dev) { - int i; - for(i=0;irx_skb[i]); + struct mc32_local *lp = (struct mc32_local *)dev->priv; + + struct sk_buff *skb; + int i; + + for(i=0; i < RX_RING_LEN; i++) + { + skb = lp->rx_ring[i].skb; + if (skb!=NULL) { + kfree_skb(skb); + skb=NULL; + } + lp->rx_ring[i].p=NULL; + } } + /** - * mc32_flush_tx_ring: + * mc32_load_tx_ring - load transmit ring + * @dev: The 3c527 card to issue the command to + * + * This sets up the host transmit data-structures. + * + * First, we obtain from the card it's current postion in the tx + * ring, so that we will know where to begin transmitting + * packets. + * + * Then, we read the 'next' pointers from the on-card tx ring into + * our tx_ring array to reduce slow shared-mem reads. Finally, we + * intitalise the tx house keeping variables. + * + */ + +static void mc32_load_tx_ring(struct net_device *dev) +{ + struct mc32_local *lp = (struct mc32_local *)dev->priv; + volatile struct skb_header *p; + int i; + u16 tx_base; + + tx_base=lp->tx_box->data[0]; + + for(i=0;itx_len;i++) + { + p=bus_to_virt(lp->base+tx_base); + lp->tx_ring[i].p=p; + lp->tx_ring[i].skb=NULL; + + tx_base=p->next; + } + + /* -1 so that tx_ring_head cannot "lap" tx_ring_tail, */ + /* which would be bad news for mc32_tx_ring as cur. implemented */ + + atomic_set(&lp->tx_count, TX_RING_LEN-1); + lp->tx_ring_head=lp->tx_ring_tail=0; +} + + +/** + * mc32_flush_tx_ring - free transmit ring * @lp: Local data of 3c527 to flush the tx ring of * * We have to consider two cases here. We want to free the pending * buffers only. If the ring buffer head is past the start then the - * ring segment we wish to free wraps through zero. + * ring segment we wish to free wraps through zero. The tx ring + * house-keeping variables are then reset. */ -static void mc32_flush_tx_ring(struct mc32_local *lp) +static void mc32_flush_tx_ring(struct net_device *dev) { - int i; + struct mc32_local *lp = (struct mc32_local *)dev->priv; - if(lp->tx_skb_top <= lp->tx_skb_end) - { - for(i=lp->tx_skb_top;itx_skb_end;i++) - dev_kfree_skb(lp->tx_skb[i]); - } - else + if(lp->tx_ring_tail!=lp->tx_ring_head) { - for(i=0;itx_skb_end;i++) - dev_kfree_skb(lp->tx_skb[i]); - for(i=lp->tx_skb_top;itx_skb[i]); + int i; + if(lp->tx_ring_tail < lp->tx_ring_head) + { + for(i=lp->tx_ring_tail;itx_ring_head;i++) + { + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + } + else + { + for(i=lp->tx_ring_tail; itx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + for(i=0; itx_ring_head; i++) + { + dev_kfree_skb(lp->tx_ring[i].skb); + lp->tx_ring[i].skb=NULL; + lp->tx_ring[i].p=NULL; + } + } } + + atomic_set(&lp->tx_count, 0); + lp->tx_ring_tail=lp->tx_ring_head=0; } + /** - * mc32_open + * mc32_open - handle 'up' of card * @dev: device to open * * The user is trying to bring the card into ready state. This requires @@ -832,9 +926,10 @@ * 'indications'. Without these enabled the card doesn't bother telling * us what it has done. This had me puzzled for a week. * - * We then load the network address and multicast filters. Turn on the - * workaround mode. This works around a bug in the 82586 - it asks the - * firmware to do so. It has a performance hit but is needed on busy + * We configure the number of card descriptors, then load the network + * address and multicast filters. Turn on the workaround mode. This + * works around a bug in the 82586 - it asks the firmware to do + * so. It has a performance (latency) hit but is needed on busy * [read most] lans. We load the ring with buffers then we kick it * all off. */ @@ -842,10 +937,11 @@ static int mc32_open(struct net_device *dev) { int ioaddr = dev->base_addr; - u16 zero_word=0; + struct mc32_local *lp = (struct mc32_local *)dev->priv; u8 one=1; u8 regs; - + u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN}; + /* * Interrupts enabled */ @@ -861,46 +957,64 @@ mc32_command(dev, 4, &one, 2); - /* - * Send the command sequence "abort, resume" for RX and TX. - * The abort cleans up the buffer chains if needed. + * Poke it to make sure it's really dead. */ - mc32_rx_abort(dev); - mc32_tx_abort(dev); - + mc32_halt_transceiver(dev); + mc32_flush_tx_ring(dev); + + /* + * Ask card to set up on-card descriptors to our spec + */ + + if(mc32_command(dev, 8, descnumbuffs, 4)) { + printk("%s: %s rejected our buffer configuration!\n", + dev->name, cardname); + mc32_close(dev); + return -ENOBUFS; + } + + /* Report new configuration */ + mc32_command(dev, 6, NULL, 0); + + lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */ + lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */ + lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */ + lp->rx_len = lp->exec_box->data[11]; /* Receive list count */ + /* Set Network Address */ mc32_command(dev, 1, dev->dev_addr, 6); /* Set the filters */ mc32_set_multicast_list(dev); + + if (WORKAROUND_82586) { + u16 zero_word=0; + mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ + } + + mc32_load_tx_ring(dev); - /* Issue the 82586 workaround command - this is for "busy lans", - but basically means for all lans now days - has a performance - cost but best set */ - - mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ - - /* Load the ring we just initialised */ - - if(mc32_load_rx_ring(dev)) + if(mc32_load_rx_ring(dev)) { mc32_close(dev); return -ENOBUFS; } + + lp->desired_state = RUNNING; - /* And the resume command goes last */ - - mc32_rx_begin(dev); - mc32_tx_begin(dev); + /* And finally, set the ball rolling... */ + mc32_start_transceiver(dev); + + netif_start_queue(dev); - netif_start_queue(dev); return 0; } + /** - * mc32_timeout: + * mc32_timeout - handle a timeout from the network layer * @dev: 3c527 that timed out * * Handle a timeout on transmit from the 3c527. This normally means @@ -915,9 +1029,10 @@ /* Try to restart the adaptor. */ netif_wake_queue(dev); } - + + /** - * mc32_send_packet: + * mc32_send_packet - queue a frame for transmit * @skb: buffer to transmit * @dev: 3c527 to send it out of * @@ -931,18 +1046,16 @@ * MCA machine I don't plan to change it. It is probably the top * performance hit for this driver on SMP however. */ - + static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - int ioaddr = dev->base_addr; unsigned long flags; - - u16 tx_head; + volatile struct skb_header *p, *np; netif_stop_queue(dev); - + save_flags(flags); cli(); @@ -952,204 +1065,303 @@ return 1; } - tx_head = lp->tx_box->data[0]; - atomic_dec(&lp->tx_count); - /* We will need this to flush the buffer out */ - - lp->tx_skb[lp->tx_skb_end] = skb; - lp->tx_skb_end++; - lp->tx_skb_end&=(TX_RING_MAX-1); - - /* TX suspend - shouldnt be needed but apparently is. - This is a research item ... */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->tx_box->mbox=0; - outb(3, ioaddr+HOST_CMD); - - /* Transmit now stopped */ + atomic_dec(&lp->tx_count); /* P is the last sending/sent buffer as a pointer */ - p=(struct skb_header *)bus_to_virt(lp->base+tx_head); - - /* NP is the buffer we will be loading */ - np=(struct skb_header *)bus_to_virt(lp->base+p->next); - - np->control |= (1<<6); /* EOL */ - wmb(); + p=lp->tx_ring[lp->tx_ring_head].p; - np->length = skb->len; - - if(np->length < 60) - np->length = 60; + lp->tx_ring_head=next_tx(lp->tx_ring_head); + + /* NP is the buffer we will be loading */ + np=lp->tx_ring[lp->tx_ring_head].p; + + /* We will need this to flush the buffer out */ + lp->tx_ring[lp->tx_ring_head].skb=skb; + + np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; np->data = virt_to_bus(skb->data); np->status = 0; - np->control = (1<<7)|(1<<6); /* EOP EOL */ + np->control = CONTROL_EOP | CONTROL_EOL; wmb(); - p->status = 0; - p->control &= ~(1<<6); + p->control &= ~CONTROL_EOL; /* Clear EOL on p */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->tx_box->mbox=0; - outb(5, ioaddr+HOST_CMD); /* Restart TX */ restore_flags(flags); - + netif_wake_queue(dev); return 0; } + /** - * mc32_update_stats: + * mc32_update_stats - pull off the on board statistics * @dev: 3c527 to service * - * When the board signals us that its statistics need attention we - * should query the table and clear it. In actual fact we currently - * track all our statistics in software and I haven't implemented it yet. + * + * Query and reset the on-card stats. There's the small possibility + * of a race here, which would result in an underestimation of + * actual errors. As such, we'd prefer to keep all our stats + * collection in software. As a rule, we do. However it can't be + * used for rx errors and collisions as, by default, the card discards + * bad rx packets. + * + * Setting the SAV BP in the rx filter command supposedly + * stops this behaviour. However, testing shows that it only seems to + * enable the collation of on-card rx statistics --- the driver + * never sees an RX descriptor with an error status set. + * */ - + static void mc32_update_stats(struct net_device *dev) { -} + struct mc32_local *lp = (struct mc32_local *)dev->priv; + volatile struct mc32_stats *st = lp->stats; + + u32 rx_errors=0; + + rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors; + st->rx_crc_errors=0; + rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors; + st->rx_overrun_errors=0; + rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; + st->rx_alignment_errors=0; + rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; + st->rx_tooshort_errors=0; + rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors; + st->rx_outofresource_errors=0; + lp->net_stats.rx_errors=rx_errors; + + /* Number of packets which saw one collision */ + lp->net_stats.collisions+=st->dataC[10]; + st->dataC[10]=0; + + /* Number of packets which saw 2--15 collisions */ + lp->net_stats.collisions+=st->dataC[11]; + st->dataC[11]=0; +} + /** - * mc32_rx_ring: + * mc32_rx_ring - process the receive ring * @dev: 3c527 that needs its receive ring processing * - * We have received one or more indications from the card that - * a receive has completed. The ring buffer thus contains dirty - * entries. Firstly we tell the card to stop receiving, then We walk - * the ring from the first filled entry, which is pointed to by the - * card rx mailbox and for each completed packet we will either copy - * it and pass it up the stack or if the packet is near MTU sized we - * allocate another buffer and flip the old one up the stack. * + * We have received one or more indications from the card that a + * receive has completed. The buffer ring thus contains dirty + * entries. We walk the ring by iterating over the circular rx_ring + * array, starting at the next dirty buffer (which happens to be the + * one we finished up at last time around). + * + * For each completed packet, we will either copy it and pass it up + * the stack or, if the packet is near MTU sized, we allocate + * another buffer and flip the old one up the stack. + * * We must succeed in keeping a buffer on the ring. If neccessary we - * will toss a received packet rather than lose a ring entry. Once the - * first packet that is unused is found we reload the mailbox with the - * buffer so that the card knows it can use the buffers again. Finally - * we set it receiving again. - * - * We must stop reception during the ring walk. I thought it would be - * neat to avoid it by clever tricks, but it turns out the event order - * on the card means you have to play by the manual. + * will toss a received packet rather than lose a ring entry. Once + * the first uncompleted descriptor is found, we move the + * End-Of-List bit to include the buffers just processed. + * */ - + static void mc32_rx_ring(struct net_device *dev) { - struct mc32_local *lp=dev->priv; - int ioaddr = dev->base_addr; - int x=0; + struct mc32_local *lp=dev->priv; volatile struct skb_header *p; - u16 base; - u16 top; + u16 rx_ring_tail = lp->rx_ring_tail; + u16 rx_old_tail = rx_ring_tail; - /* Halt RX before walking the ring */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(3<<3, ioaddr+HOST_CMD); - while(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR); + int x=0; - top = base = lp->rx_box->data[0]; do - { - p=(struct skb_header *)bus_to_virt(base+lp->base); - if(!(p->status & (1<<7))) + { + p=lp->rx_ring[rx_ring_tail].p; + + if(!(p->status & (1<<7))) { /* Not COMPLETED */ break; - if(p->status & (1<<6)) - { - u16 length = p->length; - struct sk_buff *skb=dev_alloc_skb(length+2); - if(skb!=NULL) + } + if(p->status & (1<<6)) /* COMPLETED_OK */ + { + + u16 length=p->length; + struct sk_buff *skb; + struct sk_buff *newskb; + + /* Try to save time by avoiding a copy on big frames */ + + if ((length > RX_COPYBREAK) + && ((newskb=dev_alloc_skb(1532)) != NULL)) + { + skb=lp->rx_ring[rx_ring_tail].skb; + skb_put(skb, length); + + skb_reserve(newskb,18); + lp->rx_ring[rx_ring_tail].skb=newskb; + p->data=virt_to_bus(newskb->data); + } + else { + skb=dev_alloc_skb(length+2); + + if(skb==NULL) { + lp->net_stats.rx_dropped++; + goto dropped; + } + skb_reserve(skb,2); - /*printk("Frame at %p\n", bus_to_virt(p->data)); */ memcpy(skb_put(skb, length), - bus_to_virt(p->data), length); - skb->protocol=eth_type_trans(skb,dev); - skb->dev=dev; - netif_rx(skb); - dev->last_rx = jiffies; - lp->net_stats.rx_packets++; - lp->net_stats.rx_bytes += length; + lp->rx_ring[rx_ring_tail].skb->data, length); } - else - lp->net_stats.rx_dropped++; + + skb->protocol=eth_type_trans(skb,dev); + skb->dev=dev; + dev->last_rx = jiffies; + lp->net_stats.rx_packets++; + lp->net_stats.rx_bytes += length; + netif_rx(skb); } - else + + dropped: + p->length = 1532; + p->status = 0; + + rx_ring_tail=next_rx(rx_ring_tail); + } + while(x++<48); + + /* If there was actually a frame to be processed, place the EOL bit */ + /* at the descriptor prior to the one to be filled next */ + + if (rx_ring_tail != rx_old_tail) + { + lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL; + lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL; + + lp->rx_ring_tail=rx_ring_tail; + } +} + + +/** + * mc32_tx_ring - process completed transmits + * @dev: 3c527 that needs its transmit ring processing + * + * + * This operates in a similar fashion to mc32_rx_ring. We iterate + * over the transmit ring. For each descriptor which has been + * processed by the card, we free its associated buffer and note + * any errors. This continues until the transmit ring is emptied + * or we reach a descriptor that hasn't yet been processed by the + * card. + * + */ + +static void mc32_tx_ring(struct net_device *dev) +{ + struct mc32_local *lp=(struct mc32_local *)dev->priv; + volatile struct skb_header *np; + + /* NB: lp->tx_count=TX_RING_LEN-1 so that tx_ring_head cannot "lap" tail here */ + + while (lp->tx_ring_tail != lp->tx_ring_head) + { + u16 t; + + t=next_tx(lp->tx_ring_tail); + np=lp->tx_ring[t].p; + + if(!(np->status & (1<<7))) + { + /* Not COMPLETED */ + break; + } + lp->net_stats.tx_packets++; + if(!(np->status & (1<<6))) /* Not COMPLETED_OK */ { - lp->net_stats.rx_errors++; - switch(p->status&0x0F) + lp->net_stats.tx_errors++; + + switch(np->status&0x0F) { case 1: - lp->net_stats.rx_crc_errors++;break; + lp->net_stats.tx_aborted_errors++; + break; /* Max collisions */ case 2: - lp->net_stats.rx_fifo_errors++;break; + lp->net_stats.tx_fifo_errors++; + break; case 3: - lp->net_stats.rx_frame_errors++;break; + lp->net_stats.tx_carrier_errors++; + break; case 4: - lp->net_stats.rx_missed_errors++;break; + lp->net_stats.tx_window_errors++; + break; /* CTS Lost */ case 5: - lp->net_stats.rx_length_errors++;break; + lp->net_stats.tx_aborted_errors++; + break; /* Transmit timeout */ } } - p->length = 1532; - p->control &= ~(1<<6); - p->status = 0; - base = p->next; + /* Packets are sent in order - this is + basically a FIFO queue of buffers matching + the card ring */ + lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len; + dev_kfree_skb_irq(lp->tx_ring[t].skb); + lp->tx_ring[t].skb=NULL; + atomic_inc(&lp->tx_count); + netif_wake_queue(dev); + + lp->tx_ring_tail=t; } - while(x++<48); - /* - * Restart ring processing - */ - - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - lp->rx_box->mbox=0; - lp->rx_box->data[0] = top; - outb(1<<3, ioaddr+HOST_CMD); - lp->rx_halted=0; -} +} /** - * mc32_interrupt: + * mc32_interrupt - handle an interrupt from a 3c527 * @irq: Interrupt number * @dev_id: 3c527 that requires servicing * @regs: Registers (unused) * - * The 3c527 interrupts us for four reasons. The command register - * contains the message it wishes to send us packed into a single - * byte field. We keep reading status entries until we have processed - * all the transmit and control items, but simply count receive - * reports. When the receive reports are in we can call the mc32_rx_ring - * and empty the ring. This saves the overhead of multiple command requests + * + * An interrupt is raised whenever the 3c527 writes to the command + * register. This register contains the message it wishes to send us + * packed into a single byte field. We keep reading status entries + * until we have processed all the control items, but simply count + * transmit and receive reports. When all reports are in we empty the + * transceiver rings as appropriate. This saves the overhead of + * multiple command requests. + * + * Because MCA is level-triggered, we shouldn't miss indications. + * Therefore, we needn't ask the card to suspend interrupts within + * this handler. The card receives an implicit acknowledgment of the + * current interrupt when we read the command register. + * */ - + static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; struct mc32_local *lp; int ioaddr, status, boguscount = 0; + int rx_event = 0; + int tx_event = 0; if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); return; } + ioaddr = dev->base_addr; lp = (struct mc32_local *)dev->priv; /* See whats cooking */ - - while((inb(ioaddr+2)&(1<<5)) && boguscount++<2000) + + while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000) { status=inb(ioaddr+HOST_CMD); #ifdef DEBUG_IRQ - printk("Status TX%d RX%d EX%d OV%d\n", + printk("Status TX%d RX%d EX%d OV%d BC%d\n", (status&7), (status>>3)&7, (status>>6)&1, - (status>>7)&1); + (status>>7)&1, boguscount); #endif switch(status&7) @@ -1157,32 +1369,16 @@ case 0: break; case 6: /* TX fail */ - lp->net_stats.tx_errors++; case 2: /* TX ok */ - lp->net_stats.tx_packets++; - /* Packets are sent in order - this is - basically a FIFO queue of buffers matching - the card ring */ - lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len; - dev_kfree_skb_irq(lp->tx_skb[lp->tx_skb_top]); - lp->tx_skb[lp->tx_skb_top]=NULL; - lp->tx_skb_top++; - lp->tx_skb_top&=(TX_RING_MAX-1); - atomic_inc(&lp->tx_count); - netif_wake_queue(dev); + tx_event = 1; break; case 3: /* Halt */ case 4: /* Abort */ - lp->tx_halted=1; - wake_up(&lp->event); - break; - case 5: - lp->tx_halted=0; + lp->xceiver_state |= TX_HALTED; wake_up(&lp->event); break; default: - printk("%s: strange tx ack %d\n", - dev->name, status&7); + printk("%s: strange tx ack %d\n", dev->name, status&7); } status>>=3; switch(status&7) @@ -1190,87 +1386,87 @@ case 0: break; case 2: /* RX */ - lp->rx_pending=1; - if(!lp->rx_halted) - { - /* - * Halt ring receive - */ - while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); - outb(3<<3, ioaddr+HOST_CMD); - } + rx_event=1; break; - case 3: - case 4: - lp->rx_halted=1; - wake_up(&lp->event); - break; - case 5: - lp->rx_halted=0; + case 3: /* Halt */ + case 4: /* Abort */ + lp->xceiver_state |= RX_HALTED; wake_up(&lp->event); break; case 6: /* Out of RX buffers stat */ + /* Must restart rx */ lp->net_stats.rx_dropped++; - lp->rx_pending=1; - /* Must restart */ - lp->rx_halted=1; + mc32_rx_ring(dev); + mc32_start_transceiver(dev); break; default: printk("%s: strange rx ack %d\n", - dev->name, status&7); - + dev->name, status&7); } status>>=3; if(status&1) { + /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */ - if(lp->exec_pending!=3) + + if(lp->exec_pending!=3) { lp->exec_pending=2; - else - lp->exec_pending=0; - wake_up(&lp->event); + wake_up(&lp->event); + } + else + { + lp->exec_pending=0; + + /* A new multicast set may have been + blocked while the old one was + running. If so, do it now. */ + + if (lp->mc_reload_wait) + mc32_reset_multicast_list(dev); + else + wake_up(&lp->event); + } } if(status&2) { /* - * Update the stats as soon as - * we have it flagged and can - * send an immediate reply (CRR set) + * We get interrupted once per + * counter that is about to overflow. */ - - if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR) - { - mc32_update_stats(dev); - outb(0, ioaddr+HOST_CMD); - } + + mc32_update_stats(dev); } } - + + /* - * Process and restart the receive ring. This has some state - * as we must halt the ring to process it and halting the ring - * might not occur in the same IRQ handling loop as we issue - * the halt. - */ + * Process the transmit and receive rings + */ + + if(tx_event) + mc32_tx_ring(dev); - if(lp->rx_pending && lp->rx_halted) - { + if(rx_event) mc32_rx_ring(dev); - lp->rx_pending = 0; - } + return; } /** - * mc32_close: + * mc32_close - user configuring the 3c527 down * @dev: 3c527 card to shut down * * The 3c527 is a bus mastering device. We must be careful how we * shut it down. It may also be running shared interrupt so we have * to be sure to silence it properly * + * We indicate that the card is closing to the rest of the + * driver. Otherwise, it is possible that the card may run out + * of receive buffers and restart the transceiver while we're + * trying to close it. + * * We abort any receive and transmits going on and then wait until * any pending exec commands have completed in other code threads. * In theory we can't get here while that is true, in practice I am @@ -1279,93 +1475,104 @@ * We turn off the interrupt enable for the board to be sure it can't * intefere with other devices. */ - + static int mc32_close(struct net_device *dev) { struct mc32_local *lp = (struct mc32_local *)dev->priv; + int ioaddr = dev->base_addr; u8 regs; u16 one=1; - - netif_stop_queue(dev); + lp->desired_state = HALTED; + netif_stop_queue(dev); + /* * Send the indications on command (handy debug check) */ mc32_command(dev, 4, &one, 2); - /* Abort RX and Abort TX */ - - mc32_rx_abort(dev); - mc32_tx_abort(dev); + /* Shut down the transceiver */ + + mc32_halt_transceiver(dev); /* Catch any waiting commands */ while(lp->exec_pending==1) sleep_on(&lp->event); - + /* Ok the card is now stopping */ regs=inb(ioaddr+HOST_CTRL); regs&=~HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); - mc32_flush_rx_ring(lp); - mc32_flush_tx_ring(lp); - - /* Update the statistics here. */ + mc32_flush_rx_ring(dev); + mc32_flush_tx_ring(dev); + + mc32_update_stats(dev); return 0; - } + /** - * mc32_get_stats: + * mc32_get_stats - hand back stats to network layer * @dev: The 3c527 card to handle * - * As we currently handle our statistics in software this one is - * easy to handle. With hardware statistics it will get messy - * as the get_stats call will need to send exec mailbox messages and - * need to lock out the multicast reloads. + * We've collected all the stats we can in software already. Now + * it's time to update those kept on-card and return the lot. + * */ static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp; + + mc32_update_stats(dev); + + lp = (struct mc32_local *)dev->priv; + return &lp->net_stats; } + /** - * do_mc32_set_multicast_list: + * do_mc32_set_multicast_list - attempt to update multicasts * @dev: 3c527 device to load the list on * @retry: indicates this is not the first call. * - * Actually set or clear the multicast filter for this adaptor. The locking - * issues are handled by this routine. We have to track state as it may take - * multiple calls to get the command sequence completed. We just keep trying - * to schedule the loads until we manage to process them all. * - * num_addrs == -1 Promiscuous mode, receive all packets + * Actually set or clear the multicast filter for this adaptor. The + * locking issues are handled by this routine. We have to track + * state as it may take multiple calls to get the command sequence + * completed. We just keep trying to schedule the loads until we + * manage to process them all. + * + * num_addrs == -1 Promiscuous mode, receive all packets + * + * num_addrs == 0 Normal mode, clear multicast list + * + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. * - * num_addrs == 0 Normal mode, clear multicast list + * See mc32_update_stats() regards setting the SAV BP bit. * - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * and do best-effort filtering. */ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) { struct mc32_local *lp = (struct mc32_local *)dev->priv; - u16 filt; + u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ if (dev->flags&IFF_PROMISC) /* Enable promiscuous mode */ - filt = 1; + filt |= 1; else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10) { dev->flags|=IFF_PROMISC; - filt = 1; + filt |= 1; } else if(dev->mc_count) { @@ -1374,9 +1581,7 @@ struct dev_mc_list *dmc=dev->mc_list; int i; - - filt = 0; - + if(retry==0) lp->mc_list_valid = 0; if(!lp->mc_list_valid) @@ -1399,39 +1604,40 @@ lp->mc_list_valid=1; } } - else - { - filt = 0; - } - if(mc32_command_nowait(dev, 0, &filt, 2)==-1) + + if(mc32_command_nowait(dev, 0, &filt, 2)==-1) { lp->mc_reload_wait = 1; + } + else { + lp->mc_reload_wait = 0; } } + /** - * mc32_set_multicast_list: + * mc32_set_multicast_list - queue multicast list update * @dev: The 3c527 to use * * Commence loading the multicast list. This is called when the kernel * changes the lists. It will override any pending list we are trying to * load. */ - + static void mc32_set_multicast_list(struct net_device *dev) { do_mc32_set_multicast_list(dev,0); } + /** - * mc32_reset_multicast_list: + * mc32_reset_multicast_list - reset multicast list * @dev: The 3c527 to use * * Attempt the next step in loading the multicast lists. If this attempt * fails to complete then it will be scheduled and this function called * again later from elsewhere. */ - static void mc32_reset_multicast_list(struct net_device *dev) { @@ -1442,19 +1648,18 @@ static struct net_device this_device; - /** - * init_module: + * init_module - entry point * * Probe and locate a 3c527 card. This really should probe and locate * all the 3c527 cards in the machine not just one of them. Yes you can - * insmod multiple modules for now but its a hack. + * insmod multiple modules for now but it's a hack. */ - + int init_module(void) { int result; - + this_device.init = mc32_probe; if ((result = register_netdev(&this_device)) != 0) return result; @@ -1463,7 +1668,7 @@ } /** - * cleanup_module: + * cleanup_module - free resources for an unload * * Unloading time. We release the MCA bus resources and the interrupt * at which point everything is ready to unload. The card must be stopped @@ -1472,7 +1677,7 @@ * initialized it must be rebooted or the rings reloaded before any * transmit operations are allowed to start scribbling into memory. */ - + void cleanup_module(void) { int slot; @@ -1493,6 +1698,7 @@ kfree(this_device.priv); } free_irq(this_device.irq, &this_device); + release_region(this_device.base_addr, MC32_IO_EXTENT); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c527.h linux/drivers/net/3c527.h --- v2.4.2/linux/drivers/net/3c527.h Sun Mar 21 07:11:36 1999 +++ linux/drivers/net/3c527.h Sun Mar 4 14:05:04 2001 @@ -7,11 +7,19 @@ */ #define HOST_CMD 0 +#define HOST_CMD_START_RX (1<<3) +#define HOST_CMD_SUSPND_RX (3<<3) +#define HOST_CMD_RESTRT_RX (5<<3) + +#define HOST_CMD_SUSPND_TX 3 +#define HOST_CMD_RESTRT_TX 5 + #define HOST_STATUS 2 #define HOST_STATUS_CRR (1<<6) #define HOST_STATUS_CWR (1<<5) + #define HOST_CTRL 6 #define HOST_CTRL_ATTN (1<<7) #define HOST_CTRL_RESET (1<<6) @@ -19,6 +27,17 @@ #define HOST_RAMPAGE 8 +#define RX_HALTED (1<<0) +#define TX_HALTED (1<<1) +#define HALTED (RX_HALTED | TX_HALTED) +#define RUNNING 0 + +struct mc32_mailbox +{ + u16 mbox __attribute((packed)); + u16 data[1] __attribute((packed)); +}; + struct skb_header { u8 status __attribute((packed)); @@ -28,13 +47,37 @@ u32 data __attribute((packed)); }; -#define STATUS_MASK 0x0F -#define COMPLETED 0x80 -#define COMPLETED_OK 0x40 -#define BUFFER_BUSY 0x20 +struct mc32_stats +{ + /* RX Errors */ + u32 rx_crc_errors __attribute((packed)); + u32 rx_alignment_errors __attribute((packed)); + u32 rx_overrun_errors __attribute((packed)); + u32 rx_tooshort_errors __attribute((packed)); + u32 rx_toolong_errors __attribute((packed)); + u32 rx_outofresource_errors __attribute((packed)); + + u32 rx_discarded __attribute((packed)); /* via card pattern match filter */ + + /* TX Errors */ + u32 tx_max_collisions __attribute((packed)); + u32 tx_carrier_errors __attribute((packed)); + u32 tx_underrun_errors __attribute((packed)); + u32 tx_cts_errors __attribute((packed)); + u32 tx_timeout_errors __attribute((packed)) ; + + /* various cruft */ + u32 dataA[6] __attribute((packed)); + u16 dataB[5] __attribute((packed)); + u32 dataC[14] __attribute((packed)); +}; -#define CONTROL_EOP 0x80 /* End Of Packet */ -#define CONTROL_EL 0x40 /* End of List */ +#define STATUS_MASK 0x0F +#define COMPLETED (1<<7) +#define COMPLETED_OK (1<<6) +#define BUFFER_BUSY (1<<5) +#define CONTROL_EOP (1<<7) /* End Of Packet */ +#define CONTROL_EOL (1<<6) /* End of List */ -#define MCA_MC32_ID 0x0041 /* Our MCA ident */ \ No newline at end of file +#define MCA_MC32_ID 0x0041 /* Our MCA ident */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.4.2/linux/drivers/net/3c59x.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/3c59x.c Tue Mar 6 19:28:33 2001 @@ -118,7 +118,7 @@ LK1.1.11 13 Nov 2000 andrewm - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER - LK1.1.12 1 Jan 2001 andrewm + LK1.1.12 1 Jan 2001 andrewm (2.4.0-pre1) - Call pci_enable_device before we request our IRQ (Tobias Ringstrom) - Add 3c590 PCI latency timer hack to vortex_probe1 (from 0.99Ra) - Added extended wait_for_completion for the 3c905CX. @@ -126,12 +126,28 @@ - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger) - Don't free skbs we don't own on oom path in vortex_open(). + LK1.1.13 27 Jan 2001 + - Added explicit `medialock' flag so we can truly + lock the media type down with `options'. + - "check ioremap return and some tidbits" (Arnaldo Carvalho de Melo ) + - Added and used EEPROM_NORESET for 3c556B PM resumes. + - Fixed leakage of vp->rx_ring. + - Break out separate HAS_HWCKSM device capability flag. + - Kill vp->tx_full (ANK) + - Merge zerocopy fragment handling (ANK?) + + LK1.1.14 15 Feb 2001 + - Enable WOL. Can be turned on with `enable_wol' module option. + - EISA and PCI initialisation fixes (jgarzik, Manfred Spraul) + - If a device's internalconfig register reports it has NWAY, + use it, even if autoselect is enabled. + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. - Also see Documentation/networking/vortex.txt */ /* - * FIXME: This driver _could_ support MTU changing, but doesn't. See Don's hamaci.c implementation + * FIXME: This driver _could_ support MTU changing, but doesn't. See Don's hamachi.c implementation * as well as other drivers * * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k @@ -154,15 +170,11 @@ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 32; /* Tx timeout interval (millisecs) */ -static int watchdog = 400; +static int watchdog = 5000; /* Allow aggregation of Tx interrupts. Saves CPU load at the cost * of possible Tx stalls if the system is blocking interrupts * somewhere else. Undefine this to disable. - * AKPM 26 April 2000: enabling this still gets vestigial Tx timeouts - * in a heavily loaded (collision-prone) 10BaseT LAN. Should be OK with - * switched Ethernet. - * AKPM 24May00: vestigial timeouts have been removed by later fixes. */ #define tx_interrupt_mitigation 1 @@ -174,10 +186,6 @@ static int vortex_debug = 1; #endif -/* Some values here only for performance evaluation and path-coverage - debugging. */ -static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits; - #ifndef __OPTIMIZE__ #error You must compile this file with the correct options! #error See the last lines of the source file. @@ -211,14 +219,16 @@ #include static char version[] __devinitdata = -"3c59x.c:LK1.1.12 06 Jan 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.46 $\n"; +"3c59x.c:LK1.1.13 27 Jan 2001 Donald Becker and others. http://www.scyld.com/network/vortex.html\n"; MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); MODULE_PARM(debug, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(hw_checksums, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_copybreak, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(compaq_ioaddr, "i"); @@ -332,7 +342,7 @@ EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800, - EEPROM_OFFSET=0x1000 }; + EEPROM_OFFSET=0x1000, EEPROM_NORESET=0x2000, HAS_HWCKSM=0x4000 }; enum vortex_chips { CH_3C590 = 0, @@ -405,58 +415,65 @@ {"3c900 Boomerang 10Mbps Combo", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c900 Cyclone 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c900B-FL Cyclone 10base-FL", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c905 Boomerang 100baseTx", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, {"3c905 Boomerang 100baseT4", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, {"3c905B Cyclone 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c905B Cyclone 10/100/BNC", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c905B-FX Cyclone 100baseFx", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c905C Tornado", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c980 Cyclone", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c980 10/100 Base-TX NIC(Python-T)", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3cSOHO100-TX Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, }, {"3c555 Laptop Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, }, {"3c556 Laptop Tornado", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR| + HAS_HWCKSM, 128, }, {"3c556B Laptop Hurricane", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR| + EEPROM_NORESET|HAS_HWCKSM, 128, }, {"3c575 [Megahertz] 10/100 LAN CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, {"3c575 Boomerang CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, }, {"3CCFE575BT Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT| + INVERT_LED_PWR|HAS_HWCKSM, 128, }, {"3CCFE575CT Tornado CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| + MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, {"3CCFE656 Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| + INVERT_LED_PWR|HAS_HWCKSM, 128, }, {"3CCFEM656B Cyclone+Winmodem CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| + INVERT_LED_PWR|HAS_HWCKSM, 128, }, {"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR| + MAX_COLLISION_RESET|HAS_HWCKSM, 128, }, {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ - PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, }, {0,}, /* 0 terminated list. */ }; @@ -631,11 +648,24 @@ IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31, }; +#ifdef MAX_SKB_FRAGS +#define DO_ZEROCOPY 1 +#else +#define DO_ZEROCOPY 0 +#endif + struct boom_tx_desc { u32 next; /* Last entry points to 0. */ s32 status; /* bits 0:12 length, others see below. */ - u32 addr; - s32 length; +#if DO_ZEROCOPY + struct { + u32 addr; + s32 length; + } frag[1+MAX_SKB_FRAGS]; +#else + u32 addr; + s32 length; +#endif }; /* Values for the Tx status entry. */ @@ -668,6 +698,10 @@ struct pci_dev *pdev; char *cb_fn_base; /* CardBus function status addr space. */ + /* Some values here only for performance evaluation and path-coverage */ + int rx_nocopy, rx_copy, queued_packet, rx_csumhits; + int card_idx; + /* The remainder are related to chip state, mostly media selection. */ struct timer_list timer; /* Media selection timer. */ struct timer_list rx_oom_timer; /* Rx skb allocation retry timer */ @@ -679,9 +713,10 @@ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ partner_flow_ctrl:1, /* Partner supports flow control */ - tx_full:1, has_nway:1, + enable_wol:1, /* Wake-on-LAN is enabled */ open:1, + medialock:1, must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ int drv_flags; u16 status_enable; @@ -755,7 +790,9 @@ #define MAX_UNITS 8 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int hw_checksums[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* #define dev_alloc_skb dev_alloc_skb_debug */ @@ -828,8 +865,7 @@ } rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12, - EISA_TBL_OFFSET, - vortex_cards_found); + EISA_TBL_OFFSET, vortex_cards_found); if (rc == 0) vortex_cards_found++; else @@ -889,9 +925,9 @@ } dev = init_etherdev(NULL, sizeof(*vp)); + retval = -ENOMEM; if (!dev) { printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n"); - retval = -ENOMEM; goto out; } SET_MODULE_OWNER(dev); @@ -909,6 +945,7 @@ vp->drv_flags = vci->drv_flags; vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; vp->io_size = vci->io_size; + vp->card_idx = card_idx; /* module list only for EISA devices */ if (pdev == NULL) { @@ -953,10 +990,9 @@ vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE + sizeof(struct boom_tx_desc) * TX_RING_SIZE, &vp->rx_ring_dma); - if (vp->rx_ring == 0) { - retval = -ENOMEM; + retval = -ENOMEM; + if (vp->rx_ring == 0) goto free_region; - } vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE); vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE; @@ -964,7 +1000,7 @@ /* if we are a PCI driver, we store info in pdev->driver_data * instead of a module list */ if (pdev) - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); /* The lower four bits are the media type. */ if (dev->mem_start) { @@ -982,6 +1018,8 @@ vp->media_override = 7; if (option >= 0) { vp->media_override = ((option & 7) == 2) ? 0 : option & 15; + if (vp->media_override != 7) + vp->medialock = 1; vp->full_duplex = (option & 0x200) ? 1 : 0; vp->bus_master = (option & 16) ? 1 : 0; } @@ -991,6 +1029,8 @@ vp->full_duplex = 1; if (flow_ctrl[card_idx] > 0) vp->flow_ctrl = 1; + if (enable_wol[card_idx] > 0) + vp->enable_wol = 1; } vp->force_fd = vp->full_duplex; @@ -1049,7 +1089,7 @@ EL3WINDOW(4); step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; - printk(KERN_INFO " product code '%c%c' rev %02x.%d date %02d-" + printk(KERN_INFO " product code %02x%02x rev %02x.%d date %02d-" "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9); @@ -1059,8 +1099,12 @@ unsigned short n; fn_st_addr = pci_resource_start (pdev, 2); - if (fn_st_addr) + if (fn_st_addr) { vp->cb_fn_base = ioremap(fn_st_addr, 128); + retval = -ENOMEM; + if (!vp->cb_fn_base) + goto free_ring; + } printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n", dev->name, fn_st_addr, vp->cb_fn_base); EL3WINDOW(2); @@ -1102,6 +1146,8 @@ XCVR(config) > XCVR_ExtMII ? "" : media_tbl[XCVR(config)].name); vp->default_media = XCVR(config); + if (vp->default_media == XCVR_NWAY) + vp->has_nway = 1; vp->autoselect = AUTOSELECT(config); } @@ -1154,7 +1200,7 @@ } } - if (vp->capabilities & CapPwrMgmt) + if (pdev && vp->enable_wol && (vp->capabilities & CapPwrMgmt)) acpi_set_WOL(dev); if (vp->capabilities & CapBusMaster) { @@ -1167,21 +1213,44 @@ /* The 3c59x-specific entries in the device structure. */ dev->open = vortex_open; - dev->hard_start_xmit = vp->full_bus_master_tx ? - boomerang_start_xmit : vortex_start_xmit; + if (vp->full_bus_master_tx) { + dev->hard_start_xmit = boomerang_start_xmit; +#ifndef CONFIG_HIGHMEM + /* Actually, it still should work with iommu. */ + dev->features |= NETIF_F_SG; +#endif + if (((hw_checksums[card_idx] == -1) && (vp->drv_flags & HAS_HWCKSM)) || + (hw_checksums[card_idx] == 1)) { + dev->features |= NETIF_F_IP_CSUM; + } + } else { + dev->hard_start_xmit = vortex_start_xmit; + } + + if (vortex_debug > 0) { + printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n", + dev->name, + (dev->features & NETIF_F_SG) ? "en":"dis", + (dev->features & NETIF_F_IP_CSUM) ? "en":"dis"); + } + dev->stop = vortex_close; dev->get_stats = vortex_get_stats; dev->do_ioctl = vortex_ioctl; dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; -// publish_netdev(dev); return 0; +free_ring: + pci_free_consistent(pdev, + sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE, + vp->rx_ring, + vp->rx_ring_dma); free_region: if (vp->must_free_region) release_region(ioaddr, vci->io_size); -// withdraw_netdev(dev); unregister_netdev(dev); kfree (dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); @@ -1189,7 +1258,8 @@ return retval; } -static void wait_for_completion(struct net_device *dev, int cmd) +static void +wait_for_completion(struct net_device *dev, int cmd) { int i; @@ -1202,7 +1272,8 @@ /* OK, that didn't work. Do it the slow way. One second */ for (i = 0; i < 100000; i++) { if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) { - printk(KERN_INFO "%s: command 0x%04x took %d usecs! Please tell andrewm@uow.edu.au\n", + if (vortex_debug > 1) + printk(KERN_INFO "%s: command 0x%04x took %d usecs\n", dev->name, cmd, i * 10); return; } @@ -1218,26 +1289,23 @@ long ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned int config; - int i, device_id; + int i; + + if (vp->pdev && vp->enable_wol) /* AKPM: test not needed? */ + pci_set_power_state(vp->pdev, 0); /* Go active */ - if (vp->pdev) - device_id = vp->pdev->device; - else - device_id = 0x5900; /* EISA */ - /* Before initializing select the active media port. */ EL3WINDOW(3); config = inl(ioaddr + Wn3_Config); if (vp->media_override != 7) { - if (vortex_debug > 1) - printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, - media_tbl[vp->media_override].name); + printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", + dev->name, vp->media_override, + media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { if (vp->has_nway) { - printk(KERN_INFO "%s: using NWAY autonegotiation\n", dev->name); + printk(KERN_INFO "%s: using NWAY device table, not %d\n", dev->name, dev->if_port); dev->if_port = XCVR_NWAY; } else { /* Find first available media type, starting with 100baseTx. */ @@ -1245,8 +1313,7 @@ while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; printk(KERN_INFO "%s: first available media type: %s\n", - dev->name, - media_tbl[dev->if_port].name); + dev->name, media_tbl[dev->if_port].name); } } else { dev->if_port = vp->default_media; @@ -1270,13 +1337,9 @@ vp->full_duplex = vp->force_fd; config = BFINS(config, dev->if_port, 20, 4); -//AKPM if (!vp->has_nway) - { - if (vortex_debug > 6) - printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", - config); - outl(config, ioaddr + Wn3_Config); - } + if (vortex_debug > 6) + printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); + outl(config, ioaddr + Wn3_Config); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int mii_reg1, mii_reg5; @@ -1292,8 +1355,10 @@ vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); if (vortex_debug > 1) printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," - " setting %s-duplex.\n", dev->name, vp->phys[0], - mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half"); + " info1 %04x, setting %s-duplex.\n", + dev->name, vp->phys[0], + mii_reg1, mii_reg5, + vp->info1, ((vp->info1 & 0x8000) || vp->full_duplex) ? "full" : "half"); EL3WINDOW(3); } @@ -1411,6 +1476,9 @@ int i; int retval; + if (vp->pdev && vp->enable_wol) /* AKPM: test not needed? */ + pci_set_power_state(vp->pdev, 0); /* Go active */ + /* Use the now-standard shared IRQ implementation. */ if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) { @@ -1452,7 +1520,6 @@ vortex_up(dev); vp->open = 1; - vp->tx_full = 0; return 0; out_free_irq: @@ -1463,7 +1530,8 @@ return retval; } -static void vortex_timer(unsigned long data) +static void +vortex_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct vortex_private *vp = (struct vortex_private *)dev->priv; @@ -1478,6 +1546,8 @@ printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); } + if (vp->medialock) + goto leave_media_alone; disable_irq(dev->irq); old_window = inw(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); @@ -1512,7 +1582,7 @@ dev->name, vp->full_duplex ? "full" : "half", vp->phys[0], mii_reg5); /* Set the full-duplex bit. */ - EL3WINDOW(3); /* AKPM: this was missing from 2.3.99 3c59x.c! */ + EL3WINDOW(3); outw( (vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), @@ -1567,6 +1637,7 @@ EL3WINDOW(old_window); enable_irq(dev->irq); +leave_media_alone: if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); @@ -1599,8 +1670,7 @@ /* Bad idea here.. but we might as well handle a few events. */ { /* - * AKPM: block interrupts because vortex_interrupt - * does a bare spin_lock() + * Block interrupts because vortex_interrupt does a bare spin_lock() */ unsigned long flags; local_irq_save(flags); @@ -1619,18 +1689,12 @@ vp->stats.tx_errors++; if (vp->full_bus_master_tx) { - if (vortex_debug > 0) - printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", - dev->name); + printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name); if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0) outl(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); - if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) { - vp->tx_full = 0; + if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE) netif_wake_queue (dev); - } - if (vp->tx_full) - netif_stop_queue (dev); if (vp->drv_flags & IS_BOOMERANG) outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); outw(DownUnstall, ioaddr + EL3_CMD); @@ -1820,17 +1884,53 @@ dev->name, vp->cur_tx); } - if (vp->tx_full) { + if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { if (vortex_debug > 0) - printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n", + printk(KERN_WARNING "%s: BUG! Tx Ring full, refusing to send buffer.\n", dev->name); + netif_stop_queue(dev); return 1; } + vp->tx_skbuff[entry] = skb; + vp->tx_ring[entry].next = 0; +#if DO_ZEROCOPY + if (skb->ip_summed != CHECKSUM_HW) + vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); + else + vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum); + + if (!skb_shinfo(skb)->nr_frags) { + vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE)); + vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len | LAST_FRAG); + } else { + int i; + + vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, + skb->len-skb->data_len, PCI_DMA_TODEVICE)); + vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len-skb->data_len); + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + vp->tx_ring[entry].frag[i+1].addr = + cpu_to_le32(pci_map_single(vp->pdev, + (void*)page_address(frag->page) + frag->page_offset, + frag->size, PCI_DMA_TODEVICE)); + + if (i == skb_shinfo(skb)->nr_frags-1) + vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size|LAST_FRAG); + else + vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size); + } + } +#else vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); +#endif spin_lock_irqsave(&vp->lock, flags); /* Wait for the stall to complete. */ @@ -1838,18 +1938,19 @@ prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)); if (inl(ioaddr + DownListPtr) == 0) { outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); - queued_packet++; + vp->queued_packet++; } vp->cur_tx++; if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { - vp->tx_full = 1; netif_stop_queue (dev); } else { /* Clear previous interrupt enable. */ #if defined(tx_interrupt_mitigation) + /* Dubious. If in boomeang_interrupt "faster" cyclone ifdef + * were selected, this would corrupt DN_COMPLETE. No? + */ prev_entry->status &= cpu_to_le32(~TxIntrUploaded); #endif - /* netif_start_queue (dev); */ /* AKPM: redundant? */ } outw(DownUnstall, ioaddr + EL3_CMD); spin_unlock_irqrestore(&vp->lock, flags); @@ -1889,7 +1990,7 @@ vp->deferred = 0; } - if (status == 0xffff) /* AKPM: h/w no longer present (hotplug)? */ + if (status == 0xffff) /* h/w no longer present (hotplug)? */ goto handler_exit; if (vortex_debug > 4) @@ -1925,7 +2026,7 @@ netif_wake_queue(dev); } else { /* Interrupt when FIFO has room for max-sized packet. */ outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); - netif_stop_queue(dev); /* AKPM: This is new */ + netif_stop_queue(dev); } } } @@ -1990,7 +2091,7 @@ if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs can cause this */ - if (status == 0xffff) { /* AKPM: h/w no longer present (hotplug)? */ + if (status == 0xffff) { /* h/w no longer present (hotplug)? */ if (vortex_debug > 1) printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n"); goto handler_exit; @@ -2032,9 +2133,17 @@ if (vp->tx_skbuff[entry]) { struct sk_buff *skb = vp->tx_skbuff[entry]; - +#if DO_ZEROCOPY + int i; + for (i=0; i<=skb_shinfo(skb)->nr_frags; i++) + pci_unmap_single(vp->pdev, + le32_to_cpu(vp->tx_ring[entry].frag[i].addr), + le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF, + PCI_DMA_TODEVICE); +#else pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); +#endif dev_kfree_skb_irq(skb); vp->tx_skbuff[entry] = 0; } else { @@ -2044,10 +2153,9 @@ dirty_tx++; } vp->dirty_tx = dirty_tx; - if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) { + if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) { if (vortex_debug > 6) - printk(KERN_DEBUG "boomerang_interrupt: clearing tx_full\n"); - vp->tx_full = 0; + printk(KERN_DEBUG "boomerang_interrupt: wake queue\n"); netif_wake_queue (dev); } } @@ -2199,14 +2307,14 @@ memcpy(skb_put(skb, pkt_len), vp->rx_skbuff[entry]->tail, pkt_len); - rx_copy++; + vp->rx_copy++; } else { /* Pass up the skbuff already on the Rx ring. */ skb = vp->rx_skbuff[entry]; vp->rx_skbuff[entry] = NULL; skb_put(skb, pkt_len); pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - rx_nocopy++; + vp->rx_nocopy++; } skb->protocol = eth_type_trans(skb, dev); { /* Use hardware checksum info. */ @@ -2215,7 +2323,7 @@ (csum_bits == (IPChksumValid | TCPChksumValid) || csum_bits == (IPChksumValid | UDPChksumValid))) { skb->ip_summed = CHECKSUM_UNNECESSARY; - rx_csumhits++; + vp->rx_csumhits++; } } netif_rx(skb); @@ -2301,7 +2409,7 @@ if (vp->full_bus_master_tx) outl(0, ioaddr + DownListPtr); - if (vp->capabilities & CapPwrMgmt) + if (vp->pdev && vp->enable_wol && (vp->capabilities & CapPwrMgmt)) acpi_set_WOL(dev); } @@ -2320,9 +2428,18 @@ dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" " tx_queued %d Rx pre-checksummed %d.\n", - dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits); + dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits); } +#if DO_ZEROCOPY + if ( vp->rx_csumhits && + ((vp->drv_flags & HAS_HWCKSM) == 0) && + (hw_checksums[vp->card_idx] == -1)) { + printk(KERN_WARNING "%s supports hardware checksums, and we're not using them!\n", dev->name); + printk(KERN_WARNING "Please see http://www.uow.edu.au/~andrewm/zerocopy.html\n"); + } +#endif + free_irq(dev->irq, dev); if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ @@ -2335,14 +2452,24 @@ } } if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ - for (i = 0; i < TX_RING_SIZE; i++) + for (i = 0; i < TX_RING_SIZE; i++) { if (vp->tx_skbuff[i]) { struct sk_buff *skb = vp->tx_skbuff[i]; +#if DO_ZEROCOPY + int k; + for (k=0; k<=skb_shinfo(skb)->nr_frags; k++) + pci_unmap_single(vp->pdev, + le32_to_cpu(vp->tx_ring[i].frag[k].addr), + le32_to_cpu(vp->tx_ring[i].frag[k].length)&0xFFF, + PCI_DMA_TODEVICE); +#else pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE); +#endif dev_kfree_skb(skb); vp->tx_skbuff[i] = 0; } + } } vp->open = 0; @@ -2360,19 +2487,22 @@ int i; int stalled = inl(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */ - wait_for_completion(dev, DownStall); - printk(KERN_ERR " Flags; bus-master %d, full %d; dirty %d(%d) " - "current %d(%d).\n", - vp->full_bus_master_tx, vp->tx_full, + printk(KERN_ERR " Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", + vp->full_bus_master_tx, vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, vp->cur_tx, vp->cur_tx % TX_RING_SIZE); printk(KERN_ERR " Transmit list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr), &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); + wait_for_completion(dev, DownStall); for (i = 0; i < TX_RING_SIZE; i++) { printk(KERN_ERR " %d: @%p length %8.8x status %8.8x\n", i, &vp->tx_ring[i], +#if DO_ZEROCOPY + le32_to_cpu(vp->tx_ring[i].frag[0].length), +#else le32_to_cpu(vp->tx_ring[i].length), +#endif le32_to_cpu(vp->tx_ring[i].status)); } if (!stalled) @@ -2436,8 +2566,6 @@ vp->stats.tx_bytes += (up & 0xf0) << 12; } - /* We change back to window 7 (not 1) with the Vortex. */ - /* AKPM: the previous comment is obsolete - we switch back to the old window */ EL3WINDOW(old_window >> 13); return; } @@ -2600,12 +2728,6 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - /* AKPM: This kills the 905 */ - if (vortex_debug > 1) { - printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n"); - } - return; - /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ EL3WINDOW(7); outw(2, ioaddr + 0x0c); @@ -2613,13 +2735,13 @@ outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); outw(RxEnable, ioaddr + EL3_CMD); /* Change the power state to D3; RxEnable doesn't take effect. */ - pci_write_config_word(vp->pdev, 0xe0, 0x8103); + pci_set_power_state(vp->pdev, 0x8103); } static void __devexit vortex_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct vortex_private *vp; if (!dev) { @@ -2627,14 +2749,20 @@ BUG(); } - vp = (void *)(dev->priv); + vp = dev->priv; /* AKPM: FIXME: we should have * if (vp->cb_fn_base) iounmap(vp->cb_fn_base); * here */ unregister_netdev(dev); - outw(TotalReset, dev->base_addr + EL3_CMD); + /* Should really use wait_for_completion() here */ + outw((vp->drv_flags & EEPROM_NORESET) ? (TotalReset|0x10) : TotalReset, dev->base_addr + EL3_CMD); + pci_free_consistent(pdev, + sizeof(struct boom_rx_desc) * RX_RING_SIZE + + sizeof(struct boom_tx_desc) * TX_RING_SIZE, + vp->rx_ring, + vp->rx_ring_dma); if (vp->must_free_region) release_region(dev->base_addr, vp->io_size); kfree(dev); @@ -2642,7 +2770,7 @@ static struct pci_driver vortex_driver = { - name: "3c575_cb", + name: "3c59x", probe: vortex_init_one, remove: vortex_remove_one, suspend: vortex_suspend, @@ -2657,18 +2785,17 @@ static int __init vortex_init (void) { - int rc; - - rc = pci_module_init(&vortex_driver); - if (rc < 0) { - rc = vortex_eisa_init(); - if (rc > 0) - vortex_have_eisa = 1; - } else { + int pci_rc, eisa_rc; + + pci_rc = pci_module_init(&vortex_driver); + eisa_rc = vortex_eisa_init(); + + if (pci_rc == 0) vortex_have_pci = 1; - } + if (eisa_rc > 0) + vortex_have_eisa = 1; - return rc; + return (vortex_have_pci + vortex_have_eisa) ? 0 : -ENODEV; } @@ -2707,7 +2834,6 @@ module_init(vortex_init); module_exit(vortex_cleanup); - /* diff -u --recursive --new-file v2.4.2/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.4.2/linux/drivers/net/8139too.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/8139too.c Tue Mar 6 19:28:33 2001 @@ -3,14 +3,15 @@ 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux. Maintained by Jeff Garzik + Copyright 2000,2001 Jeff Garzik Much code comes from Donald Becker's rtl8139.c driver, - versions 1.11 and older. This driver was originally based - on rtl8139.c version 1.07. Header of rtl8139.c version 1.11: + versions 1.13 and older. This driver was originally based + on rtl8139.c version 1.07. Header of rtl8139.c version 1.13: ---------- - Written 1997-2000 by Donald Becker. + Written 1997-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Drivers based on or derived from this @@ -74,7 +75,7 @@ Tobias Ringström - Rx interrupt status checking suggestion - Andrew Morton - (v0.9.13): clear blocked signals, avoid + Andrew Morton - Clear blocked signals, avoid buffer overrun setting current->comm. Submitting bug reports: @@ -150,7 +151,7 @@ #include -#define RTL8139_VERSION "0.9.13" +#define RTL8139_VERSION "0.9.15" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -188,7 +189,9 @@ /* A few user-configurable values. */ /* media options */ -static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#define MAX_UNITS 8 +static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; @@ -230,6 +233,7 @@ enum { + HAS_MII_XCVR = 0x010000, HAS_CHIP_XCVR = 0x020000, HAS_LNK_CHNG = 0x040000, }; @@ -237,6 +241,7 @@ #define RTL_MIN_IO_SIZE 0x80 #define RTL8139B_IO_SIZE 256 +#define RTL8129_CAPS HAS_MII_XCVR #define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG typedef enum { @@ -246,19 +251,24 @@ /*MPX5030,*/ DELTA8139, ADDTRON8139, + DFE538TX, + RTL8129, } board_t; /* indexed by board_t, above */ static struct { const char *name; + u32 hw_flags; } board_info[] __devinitdata = { - { "RealTek RTL8139 Fast Ethernet" }, - { "RealTek RTL8139B PCI/CardBus" }, - { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" }, -/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)" },*/ - { "Delta Electronics 8139 10/100BaseTX" }, - { "Addtron Technolgy 8139 10/100BaseTX" }, + { "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS }, + { "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS }, + { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS }, +/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/ + { "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS }, + { "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS }, + { "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS }, + { "RealTek RTL8129", RTL8129_CAPS }, }; @@ -269,6 +279,15 @@ /* {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/ {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 }, {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 }, + {0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX }, + {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 }, + + /* some crazy cards report invalid vendor ids like + * 0x0001 here. The other ids are valid and constant, + * so we simply don't match on the main vendor id. + */ + {PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 }, + {0,} }; MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl); @@ -504,7 +523,6 @@ struct rtl8139_private { - board_t board; void *mmio_addr; int drv_flags; struct pci_dev *pci_dev; @@ -512,15 +530,16 @@ unsigned char *rx_ring; unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ unsigned int tx_flag; - unsigned int cur_tx; - unsigned int dirty_tx; + unsigned long cur_tx; + unsigned long dirty_tx; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct ring_info tx_info[NUM_TX_DESC]; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ dma_addr_t rx_ring_dma; dma_addr_t tx_bufs_dma; - char phys[4]; /* MII device addresses. */ + signed char phys[4]; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ char twistie, twist_row, twist_col; /* Twister tune state. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int duplex_lock:1; @@ -539,7 +558,8 @@ MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver"); MODULE_PARM (multicast_filter_limit, "i"); MODULE_PARM (max_interrupt_work, "i"); -MODULE_PARM (media, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); static int read_eeprom (void *ioaddr, int location, int addr_len); static int rtl8139_open (struct net_device *dev); @@ -658,6 +678,11 @@ SET_MODULE_OWNER(dev); tp = dev->priv; + /* enable device (incl. PCI PM wakeup and hotplug setup) */ + rc = pci_enable_device (pdev); + if (rc) + goto err_out; + pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); pio_flags = pci_resource_flags (pdev, 0); @@ -697,25 +722,11 @@ goto err_out; } - /* make sure our PIO region in PCI space is available */ - if (!request_region (pio_start, pio_len, dev->name)) { - printk (KERN_ERR PFX "no I/O resource available, aborting\n"); - rc = -EBUSY; - goto err_out; - } - - /* make sure our MMIO region in PCI space is available */ - if (!request_mem_region (mmio_start, mmio_len, dev->name)) { - printk (KERN_ERR PFX "no mem resource available, aborting\n"); - rc = -EBUSY; - goto err_out_free_pio; - } - - /* enable device (incl. PCI PM wakeup), and bus-mastering */ - rc = pci_enable_device (pdev); + rc = pci_request_regions (pdev, dev->name); if (rc) - goto err_out_free_mmio; + goto err_out; + /* enable PCI bus-mastering */ pci_set_master (pdev); #ifdef USE_IO_OPS @@ -726,7 +737,7 @@ if (ioaddr == NULL) { printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; - goto err_out_free_mmio; + goto err_out_free_res; } #endif /* USE_IO_OPS */ @@ -792,11 +803,9 @@ assert (ioaddr > 0); #ifndef USE_IO_OPS iounmap (ioaddr); +err_out_free_res: #endif /* !USE_IO_OPS */ -err_out_free_mmio: - release_mem_region (mmio_start, mmio_len); -err_out_free_pio: - release_region (pio_start, pio_len); + pci_release_regions (pdev); err_out: unregister_netdev (dev); kfree (dev); @@ -813,7 +822,7 @@ int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; - static int printed_version = 0; + static int printed_version; u8 tmp; DPRINTK ("ENTER\n"); @@ -862,18 +871,14 @@ tp = dev->priv; /* note: tp->chipset set in rtl8139_init_board */ - tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | RTL8139_CAPS; + tp->drv_flags = board_info[ent->driver_data].hw_flags; tp->pci_dev = pdev; - tp->board = ent->driver_data; tp->mmio_addr = ioaddr; spin_lock_init (&tp->lock); init_waitqueue_head (&tp->thr_wait); init_MUTEX_LOCKED (&tp->thr_exited); - pdev->driver_data = dev; - - tp->phys[0] = 32; + pci_set_drvdata(pdev, dev); printk (KERN_INFO "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " @@ -889,6 +894,30 @@ printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", dev->name, rtl_chip_info[tp->chipset].name); + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ + if (tp->drv_flags & HAS_MII_XCVR) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + tp->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x " + "advertising %4.4x.\n", + dev->name, phy, mii_status, tp->advertising); + } + } + if (phy_idx == 0) { + printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " + "transceiver.\n", + dev->name); + tp->phys[0] = 32; + } + } else + tp->phys[0] = 32; + /* Put the chip into low-power mode. */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -899,21 +928,29 @@ RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ /* The lower four bits are the media type. */ - option = (board_idx >= ARRAY_SIZE(media)) ? 0 : media[board_idx]; + option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; if (option > 0) { - tp->full_duplex = (option & 0x200) ? 1 : 0; - tp->default_port = option & 15; + tp->full_duplex = (option & 0x210) ? 1 : 0; + tp->default_port = option & 0xFF; if (tp->default_port) tp->medialock = 1; } - + if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) + tp->full_duplex = full_duplex[board_idx]; if (tp->full_duplex) { - printk (KERN_INFO - "%s: Media type forced to Full Duplex.\n", - dev->name); - mdio_write (dev, tp->phys[0], 4, 0x141); + printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); + /* Changing the MII-advertised media because might prevent + re-connection. */ tp->duplex_lock = 1; } + if (tp->default_port) { + printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", + (option & 0x20 ? 100 : 10), + (option & 0x10 ? "full" : "half")); + mdio_write(dev, tp->phys[0], 0, + ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ + ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + } DPRINTK ("EXIT - returning 0\n"); return 0; @@ -922,7 +959,7 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct rtl8139_private *np; DPRINTK ("ENTER\n"); @@ -938,10 +975,7 @@ iounmap (np->mmio_addr); #endif /* !USE_IO_OPS */ - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + pci_release_regions (pdev); #ifndef RTL8139_NDEBUG /* poison memory before freeing */ @@ -952,7 +986,7 @@ kfree (dev); - pdev->driver_data = NULL; + pci_set_drvdata (pdev, NULL); DPRINTK ("EXIT\n"); } @@ -1035,7 +1069,7 @@ #define MDIO_WRITE0 (MDIO_DIR) #define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) -#define mdio_delay() readb(mdio_addr) +#define mdio_delay(mdio_addr) readb(mdio_addr) static char mii_2_8139_map[8] = { @@ -1059,9 +1093,9 @@ for (i = 32; i >= 0; i--) { writeb (MDIO_WRITE1, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } DPRINTK ("EXIT\n"); @@ -1089,20 +1123,18 @@ int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; writeb (MDIO_DIR | dataval, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { writeb (0, mdio_addr); - mdio_delay (); - retval = - (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 - : 0); + mdio_delay (mdio_addr); + retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0); writeb (MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); @@ -1115,19 +1147,19 @@ { struct rtl8139_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; - int mii_cmd = - (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; int i; DPRINTK ("ENTER\n"); if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - if (location < 8 && mii_2_8139_map[location]) { - writew (value, - tp->mmio_addr + mii_2_8139_map[location]); - readw (tp->mmio_addr + mii_2_8139_map[location]); - } - DPRINTK ("EXIT after directly using 8139 internal regs\n"); + void *ioaddr = tp->mmio_addr; + if (location == 0) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W16_F (BasicModeCtrl, value); + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } else if (location < 8 && mii_2_8139_map[location]) + RTL_W16_F (mii_2_8139_map[location], value); return; } mdio_sync (mdio_addr); @@ -1137,20 +1169,18 @@ int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; writeb (dataval, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (dataval | MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } - /* Clear out extra bits. */ for (i = 2; i > 0; i--) { writeb (0, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); writeb (MDIO_CLK, mdio_addr); - mdio_delay (); + mdio_delay (mdio_addr); } - - DPRINTK ("EXIT\n"); + return; } @@ -1231,6 +1261,8 @@ if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; + /* unlock Config[01234] and BMCR register writes */ + RTL_W8_F (Cfg9346, Cfg9346_Unlock); /* Restore our idea of the MAC address. */ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); @@ -1246,12 +1278,23 @@ /* Check this value: the documentation for IFG contradicts ifself. */ RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); - /* unlock Config[01234] and BMCR register writes */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - udelay (10); - tp->cur_rx = 0; + /* This is check_duplex() */ + if (tp->phys[0] >= 0 || (tp->drv_flags & HAS_MII_XCVR)) { + u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); + if (mii_reg5 == 0xffff) + ; /* Not there */ + else if ((mii_reg5 & 0x0100) == 0x0100 + || (mii_reg5 & 0x00C0) == 0x0040) + tp->full_duplex = 1; + printk(KERN_INFO"%s: Setting %s%s-duplex based on" + " auto-negotiated partner ability %4.4x.\n", dev->name, + mii_reg5 == 0 ? "" : + (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", + tp->full_duplex ? "full" : "half", mii_reg5); + } + if (tp->chipset >= CH_8139A) { tmp = RTL_R8 (Config1) & Config1Clear; tmp |= Cfg1_Driver_Load; @@ -1544,7 +1587,7 @@ RTL_W16 (IntrMask, 0x0000); /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n", + printk (KERN_DEBUG "%s: Tx queue start entry %ld dirty entry %ld.\n", dev->name, tp->cur_tx, tp->dirty_tx); for (i = 0; i < NUM_TX_DESC; i++) printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8lx.%s\n", @@ -1559,6 +1602,8 @@ /* ...and finally, reset everything */ rtl8139_hw_start (dev); + + netif_wake_queue (dev); } @@ -1593,11 +1638,15 @@ tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; + + spin_lock_irq (&tp->lock); + tp->cur_tx++; - mb(); if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) netif_stop_queue (dev); + spin_unlock_irq (&tp->lock); + DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); @@ -1609,7 +1658,7 @@ struct rtl8139_private *tp, void *ioaddr) { - unsigned int dirty_tx, tx_left; + unsigned long dirty_tx, tx_left; assert (dev != NULL); assert (tp != NULL); @@ -1673,9 +1722,8 @@ #ifndef RTL8139_NDEBUG if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk (KERN_ERR - "%s: Out-of-sync dirty pointer, %d vs. %d.\n", - dev->name, dirty_tx, tp->cur_tx); + printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n", + dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } #endif /* RTL8139_NDEBUG */ @@ -1683,7 +1731,6 @@ /* only wake the queue if we did work, and the queue is stopped */ if (tp->dirty_tx != dirty_tx) { tp->dirty_tx = dirty_tx; - mb(); if (netif_queue_stopped (dev)) netif_wake_queue (dev); } @@ -1856,8 +1903,8 @@ void *ioaddr, int status, int link_changed) { - printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n", - dev->name, status); + DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", + dev->name, status); assert (dev != NULL); assert (tp != NULL); @@ -1917,8 +1964,6 @@ void *ioaddr = tp->mmio_addr; int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ - spin_lock (&tp->lock); - do { status = RTL_R16 (IntrStatus); @@ -1949,7 +1994,7 @@ RxFIFOOver error (I got the feeling this depends on the CPU speed, lower CPU speed --> more errors). After clearing the RxOverflow bit the transfer of the - packet was repeated and all data are error free transfered */ + packet was repeated and all data are error free transferred */ RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", @@ -1970,8 +2015,11 @@ if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ rtl8139_rx_interrupt (dev, tp, ioaddr); - if (status & (TxOK | TxErr)) + if (status & (TxOK | TxErr)) { + spin_lock (&tp->lock); rtl8139_tx_interrupt (dev, tp, ioaddr); + spin_unlock (&tp->lock); + } boguscnt--; } while (boguscnt > 0); @@ -1986,8 +2034,6 @@ RTL_W16 (IntrStatus, 0xffff); } - spin_unlock (&tp->lock); - DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); } @@ -2074,7 +2120,19 @@ break; } - mdio_write (dev, data[0], data[1] & 0x1f, data[2]); + if (data[0] == tp->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + tp->medialock = (value & 0x9000) ? 0 : 1; + if (tp->medialock) + tp->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: tp->advertising = value; break; + } + } + mdio_write(dev, data[0], data[1] & 0x1f, data[2]); break; default: @@ -2095,8 +2153,10 @@ DPRINTK ("ENTER\n"); if (netif_running(dev)) { + spin_lock_irq (&tp->lock); tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + spin_unlock_irq (&tp->lock); } DPRINTK ("EXIT\n"); @@ -2117,12 +2177,11 @@ unsigned char current_octet = *data++; int bit; for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? + crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); } - DPRINTK ("EXIT\n"); + DPRINTK ("EXIT, returning %u\n", crc); return crc; } @@ -2131,6 +2190,7 @@ { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; + unsigned long flags; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; u32 tmp; @@ -2164,9 +2224,7 @@ mc_filter); } - /* if called from irq handler, lock already acquired */ - if (!in_irq ()) - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); /* We can safely update without stopping the chip. */ tmp = rtl8139_rx_config | rx_mode | @@ -2175,8 +2233,7 @@ RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); - if (!in_irq ()) - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("EXIT\n"); } @@ -2184,7 +2241,7 @@ static void rtl8139_suspend (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; @@ -2207,7 +2264,7 @@ static void rtl8139_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); netif_device_attach (dev); rtl8139_hw_start (dev); diff -u --recursive --new-file v2.4.2/linux/drivers/net/82596.c linux/drivers/net/82596.c --- v2.4.2/linux/drivers/net/82596.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/82596.c Tue Mar 6 19:28:33 2001 @@ -40,8 +40,6 @@ */ -static const char *version = "82596.c $Revision: 1.4 $\n"; - #include #include @@ -65,6 +63,9 @@ #include #include +static char version[] __initdata = + "82596.c $Revision: 1.4 $\n"; + /* DEBUG flags */ @@ -333,7 +334,7 @@ spinlock_t lock; }; -char init_setup[] = +static char init_setup[] = { 0x8E, /* length, prefetch on */ 0xC8, /* fifo to 8, monitor off */ @@ -1132,9 +1133,9 @@ /* this is easy the ethernet interface can only be at 0x300 */ /* first check nothing is already registered here */ - if (check_region(ioaddr, I596_TOTAL_SIZE)) { + if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) { printk("82596: IO address 0x%04x in use\n", ioaddr); - return -ENODEV; + return -EBUSY; } for (i = 0; i < 8; i++) { @@ -1144,19 +1145,15 @@ /* checksum is a multiple of 0x100, got this wrong first time some machines have 0x100, some 0x200. The DOS driver doesn't - even bother with the checksum */ - - if (checksum % 0x100) - return -ENODEV; - - /* Some other boards trip the checksum.. but then appear as - * ether address 0. Trap these - AC */ - - if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0) - return -ENODEV; - - if (!request_region(ioaddr, I596_TOTAL_SIZE, "i596")) + even bother with the checksum. + Some other boards trip the checksum.. but then appear as + ether address 0. Trap these - AC */ + + if ((checksum % 0x100) || + (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) { + release_region(ioaddr, I596_TOTAL_SIZE); return -ENODEV; + } dev->base_addr = ioaddr; dev->irq = 10; diff -u --recursive --new-file v2.4.2/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.4.2/linux/drivers/net/Config.in Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/Config.in Tue Mar 6 19:28:33 2001 @@ -114,9 +114,11 @@ tristate ' ICL EtherTeam 16i/32 support' CONFIG_ETH16I tristate ' NE2000/NE1000 support' CONFIG_NE2000 if [ "$CONFIG_OBSOLETE" = "y" ]; then - tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 + dep_tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 $CONFIG_EXPERIMENTAL + fi + if [ "$CONFIG_OBSOLETE" = "y" ]; then + tristate ' SK_G16 support' CONFIG_SK_G16 fi - tristate ' SK_G16 support' CONFIG_SK_G16 fi if [ "$CONFIG_MCA" = "y" ]; then tristate ' SKnet MCA support' CONFIG_SKMC @@ -142,12 +144,11 @@ dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI dep_mbool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL dep_tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL - dep_tristate ' National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI + dep_tristate ' National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI - dep_tristate ' RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)' CONFIG_RTL8129 $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI dep_tristate ' SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI dep_tristate ' Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI @@ -192,14 +193,16 @@ bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then - dep_tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX $CONFIG_PCI + if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then + tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX + fi tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_INET" = "y" ]; then bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI - if [ "$CONFIG_HIPPI" = "y" ]; then + if [ "$CONFIG_HIPPI" = "y" -a "$CONFIG_PCI" = "y" ]; then tristate ' Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER if [ "$CONFIG_ROADRUNNER" != "n" ]; then bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS @@ -260,7 +263,7 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI + dep_tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI $CONFIG_PCI tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER fi diff -u --recursive --new-file v2.4.2/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.4.2/linux/drivers/net/Makefile Sat Feb 3 19:51:28 2001 +++ linux/drivers/net/Makefile Fri Mar 2 11:02:14 2001 @@ -163,7 +163,6 @@ obj-$(CONFIG_3C515) += 3c515.o obj-$(CONFIG_EEXPRESS) += eexpress.o obj-$(CONFIG_EEXPRESS_PRO) += eepro.o -obj-$(CONFIG_RTL8129) += rtl8129.o obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o diff -u --recursive --new-file v2.4.2/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h --- v2.4.2/linux/drivers/net/acenic_firmware.h Sat Dec 30 11:23:13 2000 +++ linux/drivers/net/acenic_firmware.h Tue Mar 6 19:28:33 2001 @@ -23,7 +23,7 @@ #define tigonFwRodata 0 #else /* Generated by genfw.c */ -u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { +static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000, @@ -4397,7 +4397,7 @@ 0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 }; -u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { +static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, @@ -4571,7 +4571,7 @@ 0x0, 0x14c38, 0x14c38, 0x14b80, 0x14bc4, 0x14c38, 0x14c38, 0x0, 0x0, 0x0 }; -u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { +static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, @@ -4612,7 +4612,7 @@ #define tigon2FwSbssLen 0xcc #define tigon2FwBssAddr 0x00016f50 #define tigon2FwBssLen 0x20c0 -u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { +static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x0, 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, @@ -9154,7 +9154,7 @@ 0x24020001, 0x8f430328, 0x1021, 0x24630001, 0x3e00008, 0xaf430328, 0x3e00008, 0x0, 0x0, 0x0, 0x0, 0x0 }; -u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { +static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, @@ -9425,7 +9425,7 @@ 0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 0x0, 0x0 }; -u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { +static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { 0x1, 0x1, 0x1, 0xc001fc, 0x3ffc, 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, diff -u --recursive --new-file v2.4.2/linux/drivers/net/appletalk/cops.c linux/drivers/net/appletalk/cops.c --- v2.4.2/linux/drivers/net/appletalk/cops.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/appletalk/cops.c Sat Mar 3 10:55:47 2001 @@ -181,7 +181,7 @@ int board; /* Holds what board type is. */ int nodeid; /* Set to 1 once have nodeid. */ unsigned char node_acquire; /* Node ID when acquired. */ - struct at_addr node_addr; /* Full node addres */ + struct at_addr node_addr; /* Full node address */ }; /* Index to functions, as function prototypes. */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/arcnet/Config.in linux/drivers/net/arcnet/Config.in --- v2.4.2/linux/drivers/net/arcnet/Config.in Thu Dec 30 11:51:26 1999 +++ linux/drivers/net/arcnet/Config.in Tue Mar 6 19:28:35 2001 @@ -14,10 +14,8 @@ dep_tristate 'ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET dep_tristate 'ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET dep_tristate 'ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET - if [ "$CONFIG_ARCNET_COM20020" != "n" ]; then - dep_tristate ' Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET - dep_tristate ' Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET - fi + dep_tristate ' Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ISA + dep_tristate ' Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_PCI fi endmenu diff -u --recursive --new-file v2.4.2/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c --- v2.4.2/linux/drivers/net/arcnet/arcnet.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/arcnet/arcnet.c Sat Mar 3 10:55:48 2001 @@ -696,6 +696,9 @@ msg, status, lp->intmask, lp->lasttrans_dest); lp->last_timeout = jiffies; } + + if (lp->cur_tx == -1) + netif_wake_queue(dev); } diff -u --recursive --new-file v2.4.2/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c --- v2.4.2/linux/drivers/net/arcnet/com20020-pci.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/arcnet/com20020-pci.c Tue Mar 6 19:28:35 2001 @@ -78,8 +78,10 @@ if (!dev) return err; lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); - if (!lp) - return -ENOMEM; + if (!lp) { + err = -ENOMEM; + goto out_dev; + } memset(lp, 0, sizeof(struct arcnet_local)); pdev->driver_data = dev; @@ -98,17 +100,30 @@ if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); - return -EBUSY; + err = -EBUSY; + goto out_priv; } if (ASTATUS() == 0xFF) { BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " "but seems empty!\n", ioaddr); - return -EIO; + err = -EIO; + goto out_priv; + } + if (com20020_check(dev)) { + err = -EIO; + goto out_priv; } - if (com20020_check(dev)) - return -EIO; - return com20020_found(dev, SA_SHIRQ); + if ((err = com20020_found(dev, SA_SHIRQ)) != 0) + goto out_priv; + + return 0; + +out_priv: + kfree(dev->priv); +out_dev: + kfree(dev); + return err; } static void __devexit com20020pci_remove(struct pci_dev *pdev) diff -u --recursive --new-file v2.4.2/linux/drivers/net/arlan-proc.c linux/drivers/net/arlan-proc.c --- v2.4.2/linux/drivers/net/arlan-proc.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/arlan-proc.c Tue Mar 6 19:28:33 2001 @@ -185,7 +185,7 @@ return "type A672T"; } } -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING static void arlan_print_diagnostic_info(struct net_device *dev) { int i; @@ -341,7 +341,7 @@ DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char); DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char); - /* issue nop command - no interupt */ + /* issue nop command - no interrupt */ arlan_command(dev, ARLAN_COMMAND_NOOP); if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0) return -1; @@ -818,7 +818,7 @@ #define CTBLN(num,card,nam) \ {num , #nam, &(arlan_conf[card].nam), \ sizeof(int), 0600, NULL, &proc_dointvec} -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING #define ARLAN_PROC_DEBUG_ENTRIES {48, "entry_exit_debug", &arlan_entry_and_exit_debug, \ sizeof(int), 0600, NULL, &proc_dointvec},\ diff -u --recursive --new-file v2.4.2/linux/drivers/net/arlan.c linux/drivers/net/arlan.c --- v2.4.2/linux/drivers/net/arlan.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/arlan.c Tue Mar 6 19:28:33 2001 @@ -32,9 +32,8 @@ static int async = 1; static int tx_queue_len = 1; static int arlan_EEPROM_bad; -static int arlan_entry_and_exit_debug; -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING static int arlan_entry_debug; static int arlan_exit_debug; @@ -71,6 +70,7 @@ MODULE_PARM(arlan_EEPROM_bad, "i"); EXPORT_SYMBOL(arlan_device); +EXPORT_SYMBOL(arlan_conf); EXPORT_SYMBOL(last_arlan); @@ -114,7 +114,7 @@ return ((long long) timev.tv_sec * 1000000 + timev.tv_usec); }; -#ifdef ARLAN_ENTRY_EXIT_DEBUGING +#ifdef ARLAN_ENTRY_EXIT_DEBUGGING #define ARLAN_DEBUG_ENTRY(name) \ {\ struct timeval timev;\ @@ -694,7 +694,7 @@ } -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING static void arlan_print_registers(struct net_device *dev, int line) { @@ -1671,7 +1671,7 @@ } /* we reach here if multicast filtering is on and packet * is multicast and not for receive */ - goto end_of_interupt; + goto end_of_interrupt; } } #endif // ARLAN_MULTICAST @@ -1728,7 +1728,7 @@ break; default: - printk(KERN_ERR "arlan intr: recieved unknown status\n"); + printk(KERN_ERR "arlan intr: received unknown status\n"); priv->stats.rx_crc_errors++; break; } @@ -1896,7 +1896,7 @@ return 0; } -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING static long alignLong(volatile u_char * ptr) { long ret; diff -u --recursive --new-file v2.4.2/linux/drivers/net/arlan.h linux/drivers/net/arlan.h --- v2.4.2/linux/drivers/net/arlan.h Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/arlan.h Tue Mar 6 19:28:33 2001 @@ -29,7 +29,7 @@ #include -//#define ARLAN_DEBUGING 1 +//#define ARLAN_DEBUGGING 1 #define ARLAN_PROC_INTERFACE #define MAX_ARLANS 4 /* not more than 4 ! */ @@ -50,7 +50,6 @@ extern char * siteName; extern int arlan_entry_debug; extern int arlan_exit_debug; -extern int arlan_entry_and_exit_debug; extern int testMemory; extern const char* arlan_version; extern int arlan_command(struct net_device * dev, int command); @@ -76,9 +75,9 @@ #define IFDEBUG( L ) if ( (L) & arlan_debug ) #define ARLAN_FAKE_HDR_LEN 12 -#ifdef ARLAN_DEBUGING +#ifdef ARLAN_DEBUGGING #define DEBUG 1 - #define ARLAN_ENTRY_EXIT_DEBUGING 1 + #define ARLAN_ENTRY_EXIT_DEBUGGING 1 #define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b) #else #define ARLAN_DEBUG(a,b) @@ -321,7 +320,7 @@ int tx_queue_len; }; -struct arlan_conf_stru arlan_conf[MAX_ARLANS]; +extern struct arlan_conf_stru arlan_conf[MAX_ARLANS]; struct TxParam { diff -u --recursive --new-file v2.4.2/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.4.2/linux/drivers/net/atp.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/atp.c Tue Mar 6 19:28:33 2001 @@ -536,7 +536,6 @@ dev->trans_start = jiffies; netif_wake_queue(dev); np->stats.tx_errors++; - return; } static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) diff -u --recursive --new-file v2.4.2/linux/drivers/net/bonding.c linux/drivers/net/bonding.c --- v2.4.2/linux/drivers/net/bonding.c Fri Sep 22 14:21:16 2000 +++ linux/drivers/net/bonding.c Tue Mar 6 22:44:15 2001 @@ -60,12 +60,6 @@ static struct net_device *this_bond; -static int bond_open(struct net_device *dev) -{ - MOD_INC_USE_COUNT; - return 0; -} - static void release_one_slave(struct net_device *master, slave_t *slave) { bonding_t *bond = master->priv; @@ -81,7 +75,6 @@ dev_put(slave->dev); kfree(slave); - MOD_DEC_USE_COUNT; } static int bond_close(struct net_device *master) @@ -92,21 +85,11 @@ while ((slave = bond->next) != (slave_t*)bond) release_one_slave(master, slave); - MOD_DEC_USE_COUNT; return 0; } static void bond_set_multicast_list(struct net_device *master) { - bonding_t *bond = master->priv; - slave_t *slave; - - for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) { - slave->dev->mc_list = master->mc_list; - slave->dev->mc_count = master->mc_count; - slave->dev->flags = master->flags; - slave->dev->set_multicast_list(slave->dev); - } } static int bond_enslave(struct net_device *master, struct net_device *dev) @@ -142,7 +125,6 @@ spin_unlock_bh(&master->xmit_lock); - MOD_INC_USE_COUNT; return 0; } @@ -210,9 +192,7 @@ } static struct notifier_block bond_netdev_notifier={ - bond_event, - NULL, - 0 + notifier_call: bond_event }; static int __init bond_init(struct net_device *dev) @@ -233,7 +213,6 @@ /* Initialize the device structure. */ dev->hard_start_xmit = bond_xmit; dev->get_stats = bond_get_stats; - dev->open = bond_open; dev->stop = bond_close; dev->set_multicast_list = bond_set_multicast_list; dev->do_ioctl = bond_ioctl; @@ -289,20 +268,20 @@ return &bond->stats; } -static struct net_device dev_bond = { - "", - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, bond_init }; +static struct net_device dev_bond; static int __init bonding_init(void) { /* Find a name for this unit */ - int err=dev_alloc_name(&dev_bond,"bond%d"); + int err; + + dev_bond.init = bond_init; + err = dev_alloc_name(&dev_bond,"bond%d"); if (err<0) return err; + SET_MODULE_OWNER(&dev_bond); if (register_netdev(&dev_bond) != 0) return -EIO; diff -u --recursive --new-file v2.4.2/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.4.2/linux/drivers/net/cs89x0.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/cs89x0.c Tue Mar 6 19:28:34 2001 @@ -74,13 +74,14 @@ : Use SET_MODULE_OWNER() : Tidied up strange request_irq() abuse in net_open(). -*/ - -static char version[] = -"cs89x0.c: v2.4.0-test11-pre4 Russell Nelson , Andrew Morton \n"; - -/* ======================= end of configuration ======================= */ + Andrew Morton : Kernel 2.4.3-pre1 + : Request correct number of pages for DMA (Hugh Dickens) + : Select PP_ChipID _after_ unregister_netdev in cleanup_module() + : because unregister_netdev() calls get_stats. + : Make `version[]' __initdata + : Uninlined the read/write reg/word functions. +*/ /* Always include 'config.h' first in case the user wants to turn on or override something. */ @@ -121,6 +122,7 @@ #include #include #include +#include #include #include #include @@ -137,6 +139,9 @@ #include "cs89x0.h" +static char version[] __initdata = +"cs89x0.c: v2.4.3-pre1 Russell Nelson , Andrew Morton \n"; + /* First, a few definitions that the brave might change. A zero-terminated list of I/O addresses to be probed. Some special flags.. Addr & 1 = Read back the address port, look for signature and reset @@ -260,7 +265,7 @@ SET_MODULE_OWNER(dev); if (net_debug) - printk("cs89x0:cs89x0_probe()\n"); + printk("cs89x0:cs89x0_probe(0x%x)\n", base_addr); if (base_addr > 0x1ff) /* Check a single specified location. */ return cs89x0_probe1(dev, base_addr); @@ -275,27 +280,27 @@ return -ENODEV; } -extern int inline +static int readreg(struct net_device *dev, int portno) { outw(portno, dev->base_addr + ADD_PORT); return inw(dev->base_addr + DATA_PORT); } -extern void inline +static void writereg(struct net_device *dev, int portno, int value) { outw(portno, dev->base_addr + ADD_PORT); outw(value, dev->base_addr + DATA_PORT); } -extern int inline +static int readword(struct net_device *dev, int portno) { return inw(dev->base_addr + portno); } -extern void inline +static void writeword(struct net_device *dev, int portno, int value) { outw(value, dev->base_addr + portno); @@ -383,7 +388,9 @@ lp = (struct net_local *)dev->priv; /* Grab the region so we can find another board if autoIRQ fails. */ - if (!request_region(ioaddr, NETCARD_IO_EXTENT, dev->name)) { + if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, dev->name)) { + printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n", + dev->name, ioaddr, NETCARD_IO_EXTENT); retval = -EBUSY; goto out1; } @@ -393,16 +400,23 @@ expect to find the EISA signature word. An IO with a base of 0x3 will skip the test for the ADD_PORT. */ if (ioaddr & 1) { + if (net_debug > 1) + printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr); if ((ioaddr & 2) != 2) if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) { + printk(KERN_ERR "%s: bad signature 0x%x\n", + dev->name, inw((ioaddr & ~3)+ ADD_PORT)); retval = -ENODEV; goto out2; } ioaddr &= ~3; outw(PP_ChipID, ioaddr + ADD_PORT); } +printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) { + printk(KERN_ERR "%s: incorrect signature 0x%x\n", + dev->name, inw(ioaddr + DATA_PORT)); retval = -ENODEV; goto out2; } @@ -480,6 +494,10 @@ lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T | A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO; + if (net_debug > 1) + printk(KERN_INFO "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n", + dev->name, i, lp->adapter_cnf); + /* IRQ. Other chips already probe, see below. */ if (lp->chip_type == CS8900) lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK; @@ -519,6 +537,9 @@ dev->dev_addr[i*2] = eeprom_buff[i]; dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8; } + if (net_debug > 1) + printk(KERN_DEBUG "%s: new adapter_cnf: 0%x\n", + dev->name, lp->adapter_cnf); } /* allow them to force multiple transceivers. If they force multiple, autosense */ @@ -533,6 +554,10 @@ else if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_MEDIA_10B_2; } } + if (net_debug > 1) + printk(KERN_DEBUG "%s: after force 0x%x, adapter_cnf=0x%x\n", + dev->name, lp->force, lp->adapter_cnf); + /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */ /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */ @@ -615,7 +640,7 @@ printk("cs89x0_probe1() successful\n"); return 0; out2: - release_region(ioaddr, NETCARD_IO_EXTENT); + release_region(ioaddr & ~3, NETCARD_IO_EXTENT); out1: kfree(dev->priv); dev->priv = 0; @@ -1075,7 +1100,7 @@ if (lp->isa_config & ANY_ISA_DMA) { unsigned long flags; lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL, - (lp->dmasize * 1024) / PAGE_SIZE); + get_order(lp->dmasize * 1024)); if (!lp->dma_buff) { printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize); @@ -1456,7 +1481,7 @@ static void release_dma_buff(struct net_local *lp) { if (lp->dma_buff) { - free_pages((unsigned long)(lp->dma_buff), (lp->dmasize * 1024) / PAGE_SIZE); + free_pages((unsigned long)(lp->dma_buff), get_order(lp->dmasize * 1024)); lp->dma_buff = 0; } } @@ -1690,10 +1715,10 @@ void cleanup_module(void) { - outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); if (dev_cs89x0.priv != NULL) { /* Free up the private structure, or leak memory :-) */ unregister_netdev(&dev_cs89x0); + outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); kfree(dev_cs89x0.priv); dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ /* If we don't do this, we can't re-insmod it later. */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c --- v2.4.2/linux/drivers/net/daynaport.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/daynaport.c Sat Mar 3 10:55:47 2001 @@ -275,6 +275,9 @@ return -ENODEV; dev = init_etherdev(dev, 0); + if (!dev) + return -ENOMEM; + SET_MODULE_OWNER(dev); if (!version_printed) { printk(KERN_INFO "%s", version); @@ -445,7 +448,7 @@ } /* We should hopefully not get here */ - printk(KERN_ERR "Probe unsucessful.\n"); + printk(KERN_ERR "Probe unsuccessful.\n"); return -ENODEV; membad: @@ -630,7 +633,8 @@ static int ns8390_open(struct net_device *dev) { - MOD_INC_USE_COUNT; + int ret; + ei_open(dev); /* At least on my card (a Focus Enhancements PDS card) I start */ @@ -639,11 +643,10 @@ /* - funaho@jurai.org (1999-05-17) */ /* Non-slow interrupt, works around issues with the SONIC driver */ - if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) - { + ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); + if (ret) { printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; - return -EAGAIN; + return ret; } return 0; } @@ -654,7 +657,6 @@ printk("Need to reset the NS8390 t=%lu...", jiffies); ei_status.txing = 0; if (ei_debug > 1) printk("reset not supported\n"); - return; } static int ns8390_close_card(struct net_device *dev) @@ -663,7 +665,6 @@ printk("%s: Shutting down ethercard.\n", dev->name); free_irq(dev->irq, dev); ei_close(dev); - MOD_DEC_USE_COUNT; return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.4.2/linux/drivers/net/de4x5.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/de4x5.c Tue Mar 6 19:28:35 2001 @@ -929,8 +929,6 @@ static int autoconf_media(struct net_device *dev); static void create_packet(struct net_device *dev, char *frame, int len); -static void de4x5_us_delay(u32 usec); -static void de4x5_ms_delay(u32 msec); static void load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb); static int dc21040_autoconf(struct net_device *dev); static int dc21041_autoconf(struct net_device *dev); @@ -1096,13 +1094,13 @@ #define RESET_DE4X5 {\ int i;\ i=inl(DE4X5_BMR);\ - de4x5_ms_delay(1);\ + mdelay(1);\ outl(i | BMR_SWR, DE4X5_BMR);\ - de4x5_ms_delay(1);\ + mdelay(1);\ outl(i, DE4X5_BMR);\ - de4x5_ms_delay(1);\ - for (i=0;i<5;i++) {inl(DE4X5_BMR); de4x5_ms_delay(1);}\ - de4x5_ms_delay(1);\ + mdelay(1);\ + for (i=0;i<5;i++) {inl(DE4X5_BMR); mdelay(1);}\ + mdelay(1);\ } #define PHY_HARD_RESET {\ @@ -1146,7 +1144,7 @@ pcibios_write_config_byte(lp->bus_num, lp->device << 3, PCI_CFDA_PSM, WAKEUP); } - de4x5_ms_delay(10); + mdelay(10); RESET_DE4X5; @@ -1731,13 +1729,13 @@ /* Push up the protocol stack */ skb->protocol=eth_type_trans(skb,dev); + de4x5_local_stats(dev, skb->data, pkt_len); netif_rx(skb); /* Update stats */ dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; - de4x5_local_stats(dev, skb->data, pkt_len); } } @@ -2303,6 +2301,9 @@ for (walk = walk->next; walk != &dev->bus_list; walk = walk->next) { struct pci_dev *this_dev = pci_dev_b(walk); + /* Skip the pci_bus list entry */ + if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue; + pb = this_dev->bus->number; vendor = this_dev->vendor; device = this_dev->device << 8; @@ -3921,7 +3922,7 @@ outl(csr14, DE4X5_STRR); outl(csr13, DE4X5_SICR); - de4x5_ms_delay(10); + mdelay(10); return; } @@ -3949,33 +3950,6 @@ } /* -** Known delay in microseconds -*/ -static void -de4x5_us_delay(u32 usec) -{ - udelay(usec); - - return; -} - -/* -** Known delay in milliseconds, in millisecond steps. -*/ -static void -de4x5_ms_delay(u32 msec) -{ - u_int i; - - for (i=0; i> 3) & 0x01; @@ -4401,7 +4375,7 @@ sendto_srom((command & 0x0000ff00) | DT_CS, addr); while (!((getfrom_srom(addr) >> 3) & 0x01)) { - de4x5_ms_delay(1); + mdelay(1); } sendto_srom(command & 0x0000ff00, addr); @@ -5332,7 +5306,7 @@ switch(state) { case WAKEUP: outb(WAKEUP, PCI_CFPM); - de4x5_ms_delay(10); + mdelay(10); break; case SNOOZE: @@ -5349,7 +5323,7 @@ case WAKEUP: pcibios_write_config_byte(lp->bus_num, lp->device << 3, PCI_CFDA_PSM, WAKEUP); - de4x5_ms_delay(10); + mdelay(10); break; case SNOOZE: diff -u --recursive --new-file v2.4.2/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h --- v2.4.2/linux/drivers/net/de4x5.h Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/de4x5.h Tue Mar 6 19:28:34 2001 @@ -287,7 +287,7 @@ #define STS_LNF 0x00001000 /* Link Fail */ #define STS_FD 0x00000800 /* Full-Duplex Short Frame Received */ #define STS_TM 0x00000800 /* Timer Expired (DC21041) */ -#define STS_ETI 0x00000400 /* Early Transmit Interupt */ +#define STS_ETI 0x00000400 /* Early Transmit Interrupt */ #define STS_AT 0x00000400 /* AUI/TP Pin */ #define STS_RWT 0x00000200 /* Receive Watchdog Time-Out */ #define STS_RPS 0x00000100 /* Receive Process Stopped */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.4.2/linux/drivers/net/de600.c Thu Nov 16 12:51:28 2000 +++ linux/drivers/net/de600.c Sat Mar 3 10:55:47 2001 @@ -616,11 +616,15 @@ for (i = size; i > 0; --i, ++buffer) *buffer = de600_read_byte(READ_DATA, dev); - ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */ - skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); + + /* update stats */ + dev->last_rx = jiffies; + ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */ + ((struct net_device_stats *)(dev->priv))->rx_bytes += size; /* count all received bytes */ + /* * If any worth-while packets have been received, netif_rx() * has done a mark_bh(INET_BH) for us and will work on them diff -u --recursive --new-file v2.4.2/linux/drivers/net/de620.c linux/drivers/net/de620.c --- v2.4.2/linux/drivers/net/de620.c Thu Nov 16 12:51:28 2000 +++ linux/drivers/net/de620.c Tue Mar 6 19:28:34 2001 @@ -563,7 +563,6 @@ printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name); restore_flags(flags); return 1; - break; } de620_write_block(dev, buffer, len); @@ -699,8 +698,10 @@ PRINTK(("Read %d bytes\n", size)); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* deliver it "upstairs" */ + dev->last_rx = jiffies; /* count all receives */ ((struct net_device_stats *)(dev->priv))->rx_packets++; + ((struct net_device_stats *)(dev->priv))->rx_bytes += size; } } diff -u --recursive --new-file v2.4.2/linux/drivers/net/declance.c linux/drivers/net/declance.c --- v2.4.2/linux/drivers/net/declance.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/declance.c Sat Mar 3 10:55:47 2001 @@ -999,7 +999,7 @@ lance_set_multicast(dev); } -static int __init dec_lance_init(struct net_device *dev, const int type) +static int __init dec_lance_init(const int type) { static unsigned version_printed; struct net_device *dev; @@ -1008,6 +1008,7 @@ int i, ret; unsigned long esar_base; unsigned char *esar; + struct net_device *dev; #ifndef CONFIG_TC system_base = KN01_LANCE_BASE; @@ -1018,12 +1019,12 @@ if (dec_lance_debug && version_printed++ == 0) printk(version); - dev = init_etherdev(0, sizeof(struct lance_private)); + dev = init_etherdev(NULL, sizeof(struct lance_private)); if (!dev) return -ENOMEM; /* init_etherdev ensures the data structures used by the LANCE are aligned. */ - lp = (struct lance_private *) dev->priv; + lp = dev->priv; spin_lock_init(&lp->lock); switch (type) { @@ -1206,7 +1207,6 @@ /* Find all the lance cards on the system and initialize them */ static int __init dec_lance_probe(void) { - struct net_device *dev = NULL; static int called = 0; #ifdef MODULE @@ -1244,7 +1244,7 @@ } #endif - return dec_lance_init(dev, type); + return dec_lance_init(type); } static void __exit dec_lance_cleanup(void) diff -u --recursive --new-file v2.4.2/linux/drivers/net/defxx.c linux/drivers/net/defxx.c --- v2.4.2/linux/drivers/net/defxx.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/defxx.c Tue Mar 6 19:28:34 2001 @@ -195,6 +195,8 @@ * Jun 2000 jgarzik PCI and resource alloc cleanups * Jul 2000 tjeerd Much cleanup and some bug fixes * Sep 2000 tjeerd Fix leak on unload, cosmetic code cleanup + * Feb 2001 Skb allocation fixes + * Feb 2001 davej PCI enable cleanups. */ /* Include files */ @@ -225,7 +227,7 @@ /* Version information string - should be updated prior to each new release!!! */ static char version[] __devinitdata = - "defxx.c:v1.05d 2000/09/05 Lawrence V. Stefani and others\n"; + "defxx.c:v1.05e 2001/02/03 Lawrence V. Stefani and others\n"; #define DYNAMIC_BUFFERS 1 @@ -242,7 +244,7 @@ static void dfx_bus_config_check(DFX_board_t *bp); static int dfx_driver_init(struct net_device *dev); -static int dfx_adap_init(DFX_board_t *bp); +static int dfx_adap_init(DFX_board_t *bp, int get_buffers); static int dfx_open(struct net_device *dev); static int dfx_close(struct net_device *dev); @@ -264,8 +266,9 @@ static int dfx_hw_adap_state_rd(DFX_board_t *bp); static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type); -static void dfx_rcv_init(DFX_board_t *bp); +static int dfx_rcv_init(DFX_board_t *bp, int get_buffers); static void dfx_rcv_queue_process(DFX_board_t *bp); +static void dfx_rcv_flush(DFX_board_t *bp); static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev); static int dfx_xmt_done(DFX_board_t *bp); @@ -339,7 +342,6 @@ u16 port = bp->base_addr + offset; outb(data, port); - return; } static inline void dfx_port_read_byte( @@ -352,7 +354,6 @@ u16 port = bp->base_addr + offset; *data = inb(port); - return; } static inline void dfx_port_write_long( @@ -365,7 +366,6 @@ u16 port = bp->base_addr + offset; outl(data, port); - return; } static inline void dfx_port_read_long( @@ -378,7 +378,6 @@ u16 port = bp->base_addr + offset; *data = inl(port); - return; } @@ -395,6 +394,7 @@ * * Arguments: * pdev - pointer to pci device information (NULL for EISA) + * ioaddr - pointer to port (NULL for PCI) * * Functional Description: * @@ -415,6 +415,7 @@ struct net_device *dev; DFX_board_t *bp; /* board pointer */ static int version_disp; + int err; if (!version_disp) /* display version info if adapter is found */ { @@ -426,18 +427,27 @@ * init_fddidev() allocates a device structure with private data, clears the device structure and private data, * and calls fddi_setup() and register_netdev(). Not much left to do for us here. */ - dev = init_fddidev( NULL, sizeof(*bp)); - + dev = init_fddidev(NULL, sizeof(*bp)); if (!dev) { printk (KERN_ERR "defxx: unable to allocate fddidev, aborting\n"); return -ENOMEM; } - bp = (DFX_board_t*)dev->priv; + /* Enable PCI device. */ + if (pdev != NULL) { + err = pci_enable_device (pdev); + if (err) goto err_out; + ioaddr = pci_resource_start (pdev, 1); + } + + SET_MODULE_OWNER(dev); + + bp = dev->priv; if (!request_region (ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, dev->name)) { printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n", dev->name, PFI_K_CSR_IO_LEN, ioaddr); + err = -EBUSY; goto err_out; } @@ -461,14 +471,14 @@ /* PCI board */ bp->bus_type = DFX_BUS_TYPE_PCI; bp->pci_dev = pdev; - pdev->driver_data = dev; - if (pci_enable_device (pdev)) - goto err_out_region; + pci_set_drvdata (pdev, dev); pci_set_master (pdev); } - if (dfx_driver_init(dev) != DFX_K_SUCCESS) + if (dfx_driver_init(dev) != DFX_K_SUCCESS) { + err = -ENODEV; goto err_out_region; + } return 0; @@ -477,12 +487,12 @@ err_out: unregister_netdev(dev); kfree(dev); - return -ENODEV; + return err; } static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - return dfx_init_one_pci_or_eisa(pdev, pci_resource_start (pdev, 1)); + return dfx_init_one_pci_or_eisa(pdev, 0); } static int __init dfx_eisa_init(void) @@ -642,7 +652,6 @@ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB)); } - return; } @@ -737,7 +746,6 @@ } } } - return; } @@ -977,6 +985,7 @@ * * Arguments: * bp - pointer to board information + * get_buffers - non-zero if buffers to be allocated * * Functional Description: * Issues the low-level firmware/hardware calls necessary to bring @@ -996,7 +1005,7 @@ * upon a successful return of this routine. */ -static int dfx_adap_init(DFX_board_t *bp) +static int dfx_adap_init(DFX_board_t *bp, int get_buffers) { DBG_printk("In dfx_adap_init...\n"); @@ -1131,9 +1140,23 @@ return(DFX_K_FAILURE); } + /* + * Remove any existing dynamic buffers (i.e. if the adapter is being + * reinitialized) + */ + + if (get_buffers) + dfx_rcv_flush(bp); + /* Initialize receive descriptor block and produce buffers */ - dfx_rcv_init(bp); + if (dfx_rcv_init(bp, get_buffers)) + { + printk("%s: Receive buffer allocation failed\n", bp->dev->name); + if (get_buffers) + dfx_rcv_flush(bp); + return(DFX_K_FAILURE); + } /* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */ @@ -1141,6 +1164,8 @@ if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS) { printk("%s: Start command failed\n", bp->dev->name); + if (get_buffers) + dfx_rcv_flush(bp); return(DFX_K_FAILURE); } @@ -1183,19 +1208,17 @@ static int dfx_open(struct net_device *dev) { + int ret; DFX_board_t *bp = (DFX_board_t *)dev->priv; DBG_printk("In dfx_open...\n"); - MOD_INC_USE_COUNT; - /* Register IRQ - support shared interrupts by passing device ptr */ - if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev)) - { + ret = request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev); + if (ret) { printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - MOD_DEC_USE_COUNT; - return -EAGAIN; + return ret; } /* @@ -1228,11 +1251,10 @@ /* Reset and initialize adapter */ bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST; /* skip self-test */ - if (dfx_adap_init(bp) != DFX_K_SUCCESS) + if (dfx_adap_init(bp, 1) != DFX_K_SUCCESS) { printk(KERN_ERR "%s: Adapter open failed!\n", dev->name); free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return -EAGAIN; } @@ -1318,6 +1340,10 @@ memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK)); + /* Release all dynamically allocate skb in the receive ring. */ + + dfx_rcv_flush(bp); + /* Clear device structure flags */ netif_stop_queue(dev); @@ -1326,7 +1352,6 @@ free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; return(0); } @@ -1412,7 +1437,6 @@ printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id); break; } - return; } @@ -1504,7 +1528,7 @@ bp->link_available = PI_K_FALSE; /* link is no longer available */ bp->reset_type = 0; /* rerun on-board diagnostics */ printk("%s: Resetting adapter...\n", bp->dev->name); - if (dfx_adap_init(bp) != DFX_K_SUCCESS) + if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) { printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); @@ -1552,7 +1576,7 @@ bp->link_available = PI_K_FALSE; /* link is no longer available */ bp->reset_type = 0; /* rerun on-board diagnostics */ printk("%s: Resetting adapter...\n", bp->dev->name); - if (dfx_adap_init(bp) != DFX_K_SUCCESS) + if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS) { printk("%s: Adapter reset failed! Disabling adapter interrupts.\n", bp->dev->name); dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS); @@ -1565,7 +1589,6 @@ bp->link_available = PI_K_TRUE; /* set link available flag */ } } - return; } @@ -1640,7 +1663,6 @@ if (port_status & PI_PSTATUS_M_TYPE_0_PENDING) dfx_int_type_0_process(bp); /* process Type 0 interrupts */ - return; } @@ -1732,7 +1754,6 @@ } spin_unlock(&bp->lock); - return; } @@ -2039,7 +2060,6 @@ { DBG_printk("%s: Adapter filters updated!\n", dev->name); } - return; } @@ -2540,7 +2560,6 @@ /* Deassert reset */ dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); - return; } @@ -2631,7 +2650,28 @@ return(DFX_K_HW_TIMEOUT); return(DFX_K_SUCCESS); } + +/* + * ================= + * = dfx_alloc_skb = + * ================= + * + * Overview: + * Allocate an skbuff for sending. + * + * Functional Description: + * Same as dev_alloc_skb(), but it may sleep. + */ +static inline struct sk_buff *dfx_alloc_skb(unsigned int length) +{ + struct sk_buff *skb; + + skb = alloc_skb(length + 16, GFP_BUFFER); + if (skb) + skb_reserve(skb, 16); + return skb; +} /* * Align an sk_buff to a boundary power of 2 @@ -2662,6 +2702,7 @@ * * Arguments: * bp - pointer to board information + * get_buffers - non-zero if buffers to be allocated * * Functional Description: * This routine can be called during dfx_adap_init() or during an adapter @@ -2669,7 +2710,10 @@ * LLC Host queue receive buffers. * * Return Codes: - * None + * Return 0 on success or -ENOMEM if buffer allocation failed (when using + * dynamic buffer allocation). If the buffer allocation failed, the + * already allocated buffers will not be released and the caller should do + * this. * * Assumptions: * The PDQ has been reset and the adapter and driver maintained Type 2 @@ -2680,7 +2724,7 @@ * is notified. */ -static void dfx_rcv_init(DFX_board_t *bp) +static int dfx_rcv_init(DFX_board_t *bp, int get_buffers) { int i, j; /* used in for loop */ @@ -2702,14 +2746,16 @@ * driver initialization when we allocated memory for the receive buffers. */ + if (get_buffers) { #ifdef DYNAMIC_BUFFERS for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) { - struct sk_buff *newskb; + struct sk_buff *newskb = dfx_alloc_skb(NEW_SKB_SIZE); + if (!newskb) + return -ENOMEM; bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP | ((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN)); - newskb = dev_alloc_skb(NEW_SKB_SIZE); /* * align to 128 bytes for compatibility with * the old EISA boards. @@ -2733,12 +2779,13 @@ bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX)); } #endif + } /* Update receive producer and Type 2 register */ bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post; dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword); - return; + return 0; } @@ -2833,7 +2880,7 @@ bp->p_rcv_buff_va[entry] = (char *)newskb; bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data); } else - skb = 0; + skb = NULL; } else #endif skb = dev_alloc_skb(pkt_len+3); /* alloc new buffer to pass up, add room for PRH */ @@ -2858,6 +2905,7 @@ skb->dev = bp->dev; /* pass up device pointer */ skb->protocol = fddi_type_trans(skb, bp->dev); + bp->rcv_total_bytes += skb->len; netif_rx(skb); /* Update the rcv counters */ @@ -2865,8 +2913,6 @@ bp->rcv_total_frames++; if (*(p_buff + RCV_BUFF_K_DA) & 0x01) bp->rcv_multicast_frames++; - - bp->rcv_total_bytes += skb->len; } } } @@ -2882,7 +2928,6 @@ bp->rcv_xmt_reg.index.rcv_prod += 1; bp->rcv_xmt_reg.index.rcv_comp += 1; } - return; } @@ -3183,6 +3228,54 @@ /* * ================= + * = dfx_rcv_flush = + * ================= + * + * Overview: + * Remove all skb's in the receive ring. + * + * Returns: + * None + * + * Arguments: + * bp - pointer to board information + * + * Functional Description: + * Free's all the dynamically allocated skb's that are + * currently attached to the device receive ring. This + * function is typically only used when the device is + * initialized or reinitialized. + * + * Return Codes: + * None + * + * Side Effects: + * None + */ +#ifdef DYNAMIC_BUFFERS +static void dfx_rcv_flush( DFX_board_t *bp ) + { + int i, j; + + for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++) + for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post) + { + struct sk_buff *skb; + skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j]; + if (skb) + dev_kfree_skb(skb); + bp->p_rcv_buff_va[i+j] = NULL; + } + + } +#else +static inline void dfx_rcv_flush( DFX_board_t *bp ) +{ +} +#endif /* DYNAMIC_BUFFERS */ + +/* + * ================= * = dfx_xmt_flush = * ================= * @@ -3257,7 +3350,6 @@ prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX); prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX); bp->cons_block_virt->xmt_rcv_data = prod_cons; - return; } static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev) @@ -3272,9 +3364,10 @@ static void __devexit dfx_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); dfx_remove_one_pci_or_eisa(pdev, dev); + pci_set_drvdata(pdev, NULL); } static struct pci_device_id dfx_pci_tbl[] __devinitdata = { diff -u --recursive --new-file v2.4.2/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v2.4.2/linux/drivers/net/depca.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/depca.c Tue Mar 6 19:28:35 2001 @@ -226,12 +226,12 @@ 0.52 16-Oct-00 Fixes for 2.3 io memory accesses Fix show-stopper (ints left masked) in depca_interrupt by + 0.53 12-Jan-01 Release resources on failure, bss tidbits + by acme@conectiva.com.br ========================================================================= */ -static const char *version = "depca.c:v0.51 1999/6/27 davies@maniac.ultranet.com\n"; - #include #include @@ -265,6 +265,9 @@ #include "depca.h" +static char version[] __initdata = + "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n"; + #ifdef DEPCA_DEBUG static int depca_debug = DEPCA_DEBUG; #else @@ -309,7 +312,7 @@ #define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000} #define DEPCA_IO_PORTS {0x300, 0x200, 0} #define DEPCA_TOTAL_SIZE 0x10 -static short mem_chkd = 0; +static short mem_chkd; /* ** Adapter ID for the MCA EtherWORKS DE210/212 adapter @@ -480,8 +483,9 @@ static int num_depcas, num_eth; static int mem; /* For loadable module assignment use insmod mem=0x????? .... */ -static char *adapter_name = '\0'; /* If no PROM when loadable module +static char *adapter_name; /* = '\0'; If no PROM when loadable module use insmod adapter_name=DE??? ... + bss initializes this to zero */ /* ** Miscellaneous defines... @@ -496,6 +500,8 @@ int tmp = num_depcas, status = -ENODEV; u_long iobase = dev->base_addr; + SET_MODULE_OWNER(dev); + if ((iobase == 0) && loading_module){ printk("Autoprobing is not supported when loading a module based driver.\n"); status = -EIO; @@ -566,15 +572,14 @@ printk(", h/w address "); status = get_hw_addr(dev); - for (i=0; idev_addr[i]); - } - printk("%2.2x", dev->dev_addr[i]); - if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); return -ENXIO; } + for (i=0; idev_addr[i]); + } + printk("%2.2x", dev->dev_addr[i]); /* Set up the maximum amount of network RAM(kB) */ netRAM = ((adapter != DEPCA) ? 64 : 48); @@ -616,17 +621,19 @@ lp->mca_slot = mca_slot; lp->lock = SPIN_LOCK_UNLOCKED; sprintf(lp->adapter_name,"%s (%s)", name, dev->name); + status = -EBUSY; if (!request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name)) { printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n", DEPCA_TOTAL_SIZE, ioaddr); - return -EBUSY; + goto out_priv; } /* Initialisation Block */ lp->sh_mem = ioremap(mem_start, mem_len); + status = -EIO; if (lp->sh_mem == NULL) { printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n"); - return -EIO; + goto out_region; } lp->device_ram_start = mem_start & LA_MASK; @@ -700,20 +707,21 @@ outw(INEA | INIT, DEPCA_DATA); irqnum = autoirq_report(1); + status = -ENXIO; if (!irqnum) { printk(" and failed to detect IRQ line.\n"); - status = -ENXIO; + goto out_region; } else { - for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) { + for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) if (irqnum == depca_irq[i]) { dev->irq = irqnum; printk(" and uses IRQ%d.\n", dev->irq); } - } + status = -ENXIO; if (!dev->irq) { printk(" but incorrect IRQ line detected.\n"); - status = -ENXIO; + goto out_region; } } #endif /* MODULE */ @@ -721,33 +729,30 @@ printk(" and assigned IRQ%d.\n", dev->irq); } - if (!status) { - if (depca_debug > 1) { - printk(version); - } - - /* The DEPCA-specific entries in the device structure. */ - dev->open = &depca_open; - dev->hard_start_xmit = &depca_start_xmit; - dev->stop = &depca_close; - dev->get_stats = &depca_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->do_ioctl = &depca_ioctl; - dev->tx_timeout = depca_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - dev->mem_start = 0; - - /* Fill in the generic field of the device structure. */ - ether_setup(dev); - } else { /* Incorrectly initialised hardware */ - release_region(ioaddr, DEPCA_TOTAL_SIZE); - if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } + if (depca_debug > 1) { + printk(version); } + /* The DEPCA-specific entries in the device structure. */ + dev->open = &depca_open; + dev->hard_start_xmit = &depca_start_xmit; + dev->stop = &depca_close; + dev->get_stats = &depca_get_stats; + dev->set_multicast_list = &set_multicast_list; + dev->do_ioctl = &depca_ioctl; + dev->tx_timeout = depca_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + dev->mem_start = 0; + + /* Fill in the generic field of the device structure. */ + ether_setup(dev); + return 0; +out_region: + release_region(ioaddr, DEPCA_TOTAL_SIZE); +out_priv: + kfree(dev->priv); + dev->priv = NULL; return status; } @@ -794,9 +799,6 @@ printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR)); } } - - MOD_INC_USE_COUNT; - return status; } @@ -1120,9 +1122,6 @@ ** Free the associated irq */ free_irq(dev->irq, dev); - - MOD_DEC_USE_COUNT; - return 0; } @@ -1927,14 +1926,14 @@ tmp.addr[i] = dev->dev_addr[i]; } ioc->len = ETH_ALEN; - if (verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + return -EFAULT; break; case DEPCA_SET_HWADDR: /* Set the hardware address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN)) return -EFAULT; - copy_from_user(tmp.addr,ioc->data,ETH_ALEN); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) + return -EFAULT; for (i=0; idev_addr[i] = tmp.addr[i]; } @@ -1982,14 +1981,14 @@ case DEPCA_GET_MCA: /* Get the multicast address table */ ioc->len = (HASH_TABLE_LEN >> 3); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len); + if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len)) + return -EFAULT; break; case DEPCA_SET_MCA: /* Set a multicast address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len)) return -EFAULT; - copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); + if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) + return -EFAULT; set_multicast_list(dev); break; @@ -2006,11 +2005,8 @@ case DEPCA_GET_STATS: /* Get the driver statistics */ cli(); ioc->len = sizeof(lp->pktStats); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) { - status = -EFAULT; - } else { - copy_to_user(ioc->data, &lp->pktStats, ioc->len); - } + if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) + status = -EFAULT; sti(); break; @@ -2028,8 +2024,8 @@ tmp.sval[i++] = inw(DEPCA_DATA); memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init)); ioc->len = i+sizeof(struct depca_init); - if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; - copy_to_user(ioc->data, tmp.addr, ioc->len); + if (copy_to_user(ioc->data, tmp.addr, ioc->len)) + return -EFAULT; break; default: @@ -2040,13 +2036,7 @@ } #ifdef MODULE -static struct net_device thisDepca = { - "", /* device name is inserted by /linux/drivers/net/net_init.c */ - 0, 0, 0, 0, - 0x200, 7, /* I/O address, IRQ */ - 0, 0, 0, NULL, depca_probe -}; - +static struct net_device thisDepca; static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */ static int io=0x200; /* Or use the irq= io= options to insmod */ MODULE_PARM(irq, "i"); @@ -2058,6 +2048,7 @@ { thisDepca.irq=irq; thisDepca.base_addr=io; + thisDepca.init = depca_probe; if (register_netdev(&thisDepca) != 0) return -EIO; diff -u --recursive --new-file v2.4.2/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v2.4.2/linux/drivers/net/dgrs.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/dgrs.c Tue Mar 6 19:28:35 2001 @@ -71,49 +71,40 @@ * into the kernel. * - Better handling of multicast addresses. * + * Fixes: + * Arnaldo Carvalho de Melo - 11/01/2001 + * - fix dgrs_found_device wrt checking kmalloc return and + * rollbacking the partial steps of the whole process when + * one of the devices can't be allocated. Fix SET_MODULE_OWNER + * on the loop to use devN instead of repeated calls to dev. + * + * davej - 9/2/2001 + * - Enable PCI device before reading ioaddr/irq + * */ -static char *version = "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $"; - -#include #include - #include #include #include #include #include #include -#include +#include #include #include #include -#include -#include -#include - #include #include #include -#include +#include +#include +#include +#include -/* - * API changed at linux version 2.1.0 - */ -#if LINUX_VERSION_CODE >= 0x20100 - #include - #define IOREMAP(ADDR, LEN) ioremap(ADDR, LEN) - #define IOUNMAP(ADDR) iounmap(ADDR) - #define COPY_FROM_USER(DST,SRC,LEN) copy_from_user(DST,SRC,LEN) - #define COPY_TO_USER(DST,SRC,LEN) copy_to_user(DST,SRC,LEN) -#else - #include - #define IOREMAP(ADDR, LEN) vremap(ADDR, LEN) - #define IOUNMAP(ADDR) vfree(ADDR) - #define COPY_FROM_USER(DST,SRC,LEN) memcpy_fromfs(DST,SRC,LEN) - #define COPY_TO_USER(DST,SRC,LEN) memcpy_tofs(DST,SRC,LEN) -#endif +static char version[] __initdata = + "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $"; /* * DGRS include files @@ -130,13 +121,11 @@ #include "dgrs_asstruct.h" #include "dgrs_bcomm.h" -#if LINUX_VERSION_CODE >= 0x20400 static struct pci_device_id dgrs_pci_tbl[] __initdata = { { SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl); -#endif /* LINUX_VERSION_CODE >= 0x20400 */ /* * Firmware. Compiled separately for local compilation, @@ -178,19 +167,19 @@ * "Space.c" variables, now settable from module interface * Use the name below, minus the "dgrs_" prefix. See init_module(). */ -int dgrs_debug = 1; -int dgrs_dma = 1; -int dgrs_spantree = -1; -int dgrs_hashexpire = -1; -uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff}; -uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff}; -__u32 dgrs_ipxnet = -1; -int dgrs_nicmode = 0; +static int dgrs_debug = 1; +static int dgrs_dma = 1; +static int dgrs_spantree = -1; +static int dgrs_hashexpire = -1; +static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff}; +static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff}; +static __u32 dgrs_ipxnet = -1; +static int dgrs_nicmode = 0; /* * Chain of device structures */ -static struct net_device *dgrs_root_dev = NULL; +static struct net_device *dgrs_root_dev; /* * Private per-board data structure (dev->priv) @@ -316,7 +305,7 @@ /* * Now map the DMA registers into our virtual space */ - priv0->vplxdma = (ulong *) IOREMAP (priv0->plxdma, 256); + priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256); if (!priv0->vplxdma) { printk("%s: can't *remap() the DMA regs\n", dev0->name); @@ -843,7 +832,7 @@ if (cmd != DGRSIOCTL) return -EINVAL; - if(COPY_FROM_USER(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL))) + if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL))) return -EFAULT; switch (ioc.cmd) @@ -851,7 +840,7 @@ case DGRS_GETMEM: if (ioc.len != sizeof(ulong)) return -EINVAL; - if(COPY_TO_USER(ioc.data, &devN->mem_start, ioc.len)) + if(copy_to_user(ioc.data, &devN->mem_start, ioc.len)) return -EFAULT; return (0); case DGRS_SETFILTER: @@ -880,7 +869,7 @@ if (ioc.len) { - if(COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area), + if(copy_from_user(S2HN(privN->bcomm->bc_filter_area), ioc.data, ioc.len)) return -EFAULT; privN->bcomm->bc_filter_cmd = BC_FILTER_SET; @@ -1003,7 +992,7 @@ /* * Map in the dual port memory */ - priv0->vmem = IOREMAP(dev0->mem_start, 2048*1024); + priv0->vmem = ioremap(dev0->mem_start, 2048*1024); if (!priv0->vmem) { printk("%s: cannot map in board memory\n", dev0->name); @@ -1050,7 +1039,7 @@ memcpy(priv0->vmem, dgrs_code, dgrs_ncode); /* Load code */ if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode)) { - IOUNMAP(priv0->vmem); + iounmap(priv0->vmem); priv0->vmem = NULL; printk("%s: download compare failed\n", dev0->name); return -ENXIO; @@ -1249,13 +1238,17 @@ ) { DGRS_PRIV *priv; - struct net_device *dev; + struct net_device *dev, *aux; /* Allocate and fill new device structure. */ int dev_size = sizeof(struct net_device) + sizeof(DGRS_PRIV); - int i; + int i, ret; dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); + + if (!dev) + return -ENOMEM; + memset(dev, 0, dev_size); dev->priv = ((void *)dev) + sizeof(struct net_device); priv = (DGRS_PRIV *)dev->priv; @@ -1274,11 +1267,12 @@ dev->init = dgrs_probe1; SET_MODULE_OWNER(dev); ether_setup(dev); - priv->next_dev = dgrs_root_dev; - dgrs_root_dev = dev; if (register_netdev(dev) != 0) return -EIO; + priv->next_dev = dgrs_root_dev; + dgrs_root_dev = dev; + if ( !dgrs_nicmode ) return (0); /* Switch mode, we are done */ @@ -1295,6 +1289,9 @@ /* Allocate new dev and priv structures */ devN = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); /* Make it an exact copy of dev[0]... */ + ret = -ENOMEM; + if (!devN) + goto fail; memcpy(devN, dev, dev_size); devN->priv = ((void *)devN) + sizeof(struct net_device); privN = (DGRS_PRIV *)devN->priv; @@ -1305,17 +1302,29 @@ devN->irq = 0; /* ... and base MAC address off address of 1st port */ devN->dev_addr[5] += i; - privN->chan = i+1; - priv->devtbl[i] = devN; devN->init = dgrs_initclone; - SET_MODULE_OWNER(dev); + SET_MODULE_OWNER(devN); ether_setup(devN); + ret = -EIO; + if (register_netdev(devN)) { + kfree(devN); + goto fail; + } + privN->chan = i+1; + priv->devtbl[i] = devN; privN->next_dev = dgrs_root_dev; dgrs_root_dev = devN; - if (register_netdev(devN) != 0) - return -EIO; } - return (0); + return 0; +fail: aux = priv->next_dev; + while (dgrs_root_dev != aux) { + struct net_device *d = dgrs_root_dev; + + dgrs_root_dev = ((DGRS_PRIV *)d->priv)->next_dev; + unregister_netdev(d); + kfree(d); + } + return ret; } /* @@ -1341,6 +1350,17 @@ while ((pdev = pci_find_device(SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, pdev)) != NULL) { + /* + * Get and check the bus-master and latency values. + * Some PCI BIOSes fail to set the master-enable bit, + * and the latency timer must be set to the maximum + * value to avoid data corruption that occurs when the + * timer expires during a transfer. Yes, it's a bug. + */ + if (pci_enable_device(pdev)) + continue; + pci_set_master(pdev); + plxreg = pci_resource_start (pdev, 0); io = pci_resource_start (pdev, 1); mem = pci_resource_start (pdev, 2); @@ -1365,17 +1385,6 @@ pci_read_config_dword(pdev, 0x30, &plxdma); plxdma &= ~15; - /* - * Get and check the bus-master and latency values. - * Some PCI BIOSes fail to set the master-enable bit, - * and the latency timer must be set to the maximum - * value to avoid data corruption that occurs when the - * timer expires during a transfer. Yes, it's a bug. - */ - if (pci_enable_device(pdev)) - continue; - pci_set_master(pdev); - dgrs_found_device(io, mem, irq, plxreg, plxdma); cards_found++; @@ -1470,8 +1479,8 @@ if (dgrs_debug) { - printk("dgrs: SW=%s FW=Build %d %s\n", - version, dgrs_firmnum, dgrs_firmdate); + printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n", + version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver); } /* @@ -1497,9 +1506,9 @@ proc_reset(priv->devtbl[0], 1); if (priv->vmem) - IOUNMAP(priv->vmem); + iounmap(priv->vmem); if (priv->vplxdma) - IOUNMAP((uchar *) priv->vplxdma); + iounmap((uchar *) priv->vplxdma); release_region(dgrs_root_dev->base_addr, 256); diff -u --recursive --new-file v2.4.2/linux/drivers/net/dgrs_firmware.c linux/drivers/net/dgrs_firmware.c --- v2.4.2/linux/drivers/net/dgrs_firmware.c Tue Feb 10 12:56:44 1998 +++ linux/drivers/net/dgrs_firmware.c Tue Mar 6 19:28:34 2001 @@ -1,7 +1,7 @@ -int dgrs_firmnum = 550; -char dgrs_firmver[] = "$Version$"; -char dgrs_firmdate[] = "11/16/96 03:45:15"; -unsigned char dgrs_code[] __initdata = { +static int dgrs_firmnum = 550; +static char dgrs_firmver[] = "$Version$"; +static char dgrs_firmdate[] = "11/16/96 03:45:15"; +static unsigned char dgrs_code[] __initdata = { 213,5,192,8,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,64,40,35,41, @@ -9963,4 +9963,4 @@ 109,46,99,0,114,99,0,0,48,120,0,0, 0,0,0,0,0,0,0,0,0,0,0,0 } ; -int dgrs_ncode = 119520 ; +static int dgrs_ncode = 119520 ; diff -u --recursive --new-file v2.4.2/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c --- v2.4.2/linux/drivers/net/dmfe.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/dmfe.c Tue Mar 6 19:28:34 2001 @@ -127,16 +127,17 @@ #define DMFE_100MFD 5 #define DMFE_AUTO 8 -#define DMFE_TIMER_WUT jiffies+(HZ*2)/2 /* timer wakeup time : 1 second */ +#define DMFE_TIMER_WUT (HZ) /* timer wakeup time : 1 second */ #define DMFE_TX_TIMEOUT ((HZ*3)/2) /* tx packet time-out time 1.5 s" */ -#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk("DBUG: %s %x\n", msg, vaule) - -#define DELAY_5US udelay(5) /* udelay scale 1 usec */ - -#define DELAY_1US udelay(1) /* udelay scale 1 usec */ - -#define SHOW_MEDIA_TYPE(mode) printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); +#define DMFE_DBUG(dbug_now, msg, vaule) \ + if (dmfe_debug || dbug_now) \ + printk("DBUG: %s %x\n", msg, vaule) + +#define SHOW_MEDIA_TYPE(mode) \ + printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n", \ + mode & 1 ? "100" : "10", \ + mode & 4 ? "full":"half"); /* CR9 definition: SROM/MII */ @@ -150,9 +151,17 @@ #define PHY_DATA_0 0x00000 #define MDCLKH 0x10000 -#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US; - -#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE +#define SROM_CLK_WRITE(data, ioaddr) \ + outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr); \ + udelay(5); \ + outl(data | CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, ioaddr); \ + udelay(5); \ + outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr); \ + udelay(5); + +#define __CHK_IO_SIZE(pci_id, dev_rev) \ + ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? \ + DM9102A_IO_SIZE : DM9102_IO_SIZE #define CHK_IO_SIZE(pci_dev, dev_rev) \ __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev) @@ -353,9 +362,19 @@ int i; struct net_device *dev; u32 dev_rev; + u16 pci_command; DMFE_DBUG(0, "dmfe_probe()", 0); + /* Enable Master/IO access, Disable memory access */ + i = pci_enable_device(pdev); + if (i) return i; + + pci_set_master(pdev); + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + pci_command &= ~PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + pci_iobase = pci_resource_start(pdev, 0); pci_irqline = pdev->irq; @@ -372,11 +391,6 @@ goto err_out; } - /* Enable Master/IO access, Disable memory access */ - if (pci_enable_device(pdev)) - goto err_out; - pci_set_master(pdev); - #if 0 /* pci_{enable_device,set_master} sets minimum latency for us now */ /* Set Latency Timer 80h */ @@ -403,7 +417,7 @@ } db = dev->priv; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); db->chip_id = ent->driver_data; db->ioaddr = pci_iobase; @@ -440,7 +454,7 @@ static void __exit dmfe_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct dmfe_board_info *db; DMFE_DBUG(0, "dmfe_remove_one()", 0); @@ -451,6 +465,8 @@ release_region(dev->base_addr, CHK_IO_SIZE(pdev, db->chip_revision)); kfree(dev); /* free board information */ + pci_set_drvdata(pdev, NULL); + DMFE_DBUG(0, "dmfe_remove_one() exit", 0); } @@ -511,12 +527,12 @@ db->dm910x_chk_mode = 1; /* Enter the check mode */ } - /* Initilize DM910X board */ + /* Initialize DM910X board */ dmfe_init_dm910x(dev); /* set and active a timer process */ init_timer(&db->timer); - db->timer.expires = DMFE_TIMER_WUT; + db->timer.expires = jiffies + DMFE_TIMER_WUT; db->timer.data = (unsigned long) dev; db->timer.function = &dmfe_timer; add_timer(&db->timer); @@ -526,9 +542,9 @@ return 0; } -/* Initilize DM910X board +/* Initialize DM910X board Reset DM910X board - Initilize TX/Rx descriptor chain structure + Initialize TX/Rx descriptor chain structure Send the set-up frame Enable Tx/Rx machine */ @@ -541,7 +557,7 @@ /* Reset DM910x board : need 32 PCI clock to complete */ outl(DM910X_RESET, ioaddr + DCR0); /* RESET MAC */ - DELAY_5US; + udelay(5); outl(db->cr0_data, ioaddr + DCR0); outl(0x180, ioaddr + DCR12); /* Let bit 7 output port */ @@ -559,7 +575,7 @@ db->op_mode = db->media_mode; dmfe_process_mode(db); - /* Initiliaze Transmit/Receive decriptor and CR3/4 */ + /* Initialize Transmit/Receive decriptor and CR3/4 */ dmfe_descriptor_init(db, ioaddr); /* Init CR6 to program DM910x operation */ @@ -623,10 +639,10 @@ if (db->tx_packet_cnt < TX_MAX_SEND_CNT) { txptr->tdes0 = 0x80000000; /* set owner bit to DM910X */ db->tx_packet_cnt++; /* Ready to send count */ - outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling comand */ + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling command */ } else { db->tx_queue_cnt++; /* queue the tx packet */ - outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling comand */ + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling command */ } /* Tx resource check */ @@ -654,7 +670,7 @@ /* Reset & stop DM910X board */ outl(DM910X_RESET, ioaddr + DCR0); - DELAY_5US; + udelay(5); /* deleted timer */ del_timer_sync(&db->timer); @@ -673,7 +689,7 @@ } /* - DM9102 insterrupt handler + DM9102 interrupt handler receive the packet to upper layer, free the transmitted packet */ @@ -935,7 +951,7 @@ */ DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt); dmfe_dynamic_reset(dev); - db->timer.expires = DMFE_TIMER_WUT; + db->timer.expires = jiffies + DMFE_TIMER_WUT; add_timer(&db->timer); return; } @@ -990,7 +1006,7 @@ allocated_rx_buffer(db); /* Timer active again */ - db->timer.expires = DMFE_TIMER_WUT; + db->timer.expires = jiffies + DMFE_TIMER_WUT; add_timer(&db->timer); } @@ -999,7 +1015,7 @@ Stop DM910X board Free Tx/Rx allocated memory Reset DM910X board - Re-initilize DM910X board + Re-initialize DM910X board */ static void dmfe_dynamic_reset(struct net_device *dev) { @@ -1027,7 +1043,7 @@ db->wait_reset = 0; db->rx_error_cnt = 0; - /* Re-initilize DM910X board */ + /* Re-initialize DM910X board */ dmfe_init_dm910x(dev); /* Leave dynamic reser route */ @@ -1132,14 +1148,14 @@ cr6_tmp = cr6_data & ~0x2002; /* stop Tx/Rx */ outl(cr6_tmp, ioaddr + DCR6); - DELAY_5US; + udelay(5); outl(cr6_data, ioaddr + DCR6); cr6_tmp = inl(ioaddr + DCR6); /* printk("CR6 update %x ", cr6_tmp); */ } /* Send a setup frame for DM9132 - This setup frame initilize DM910X addres filter mode + This setup frame initialize DM910X address filter mode */ static void dm9132_id_table(struct net_device *dev, int mc_cnt) { @@ -1180,7 +1196,7 @@ } /* Send a setup frame for DM9102/DM9102A - This setup frame initilize DM910X addres filter mode + This setup frame initialize DM910X address filter mode */ static void send_filter_frame(struct net_device *dev, int mc_cnt) { @@ -1288,10 +1304,10 @@ for (i = 16; i > 0; i--) { outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr); - DELAY_5US; + udelay(5); srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0); outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); - DELAY_5US; + udelay(5); } outl(CR9_SROM_READ, cr9_ioaddr); @@ -1305,10 +1321,10 @@ static void dmfe_sense_speed(struct dmfe_board_info *db) { int i; - u16 phy_mode; + u16 phy_mode = 0; for (i = 1000; i; i--) { - DELAY_5US; + udelay(5); phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id); if ((phy_mode & 0x24) == 0x24) break; @@ -1429,11 +1445,11 @@ phy_write_1bit(ioaddr, PHY_DATA_0); phy_write_1bit(ioaddr, PHY_DATA_1); - /* Send Phy addres */ + /* Send Phy address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); - /* Send register addres */ + /* Send register address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); @@ -1476,11 +1492,11 @@ phy_write_1bit(ioaddr, PHY_DATA_1); phy_write_1bit(ioaddr, PHY_DATA_0); - /* Send Phy addres */ + /* Send Phy address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); - /* Send register addres */ + /* Send register address */ for (i = 0x10; i > 0; i = i >> 1) phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); @@ -1503,11 +1519,11 @@ static void phy_write_1bit(u32 ioaddr, u32 phy_data) { outl(phy_data, ioaddr); /* MII Clock Low */ - DELAY_1US; + udelay(1); outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */ - DELAY_1US; + udelay(1); outl(phy_data, ioaddr); /* MII Clock Low */ - DELAY_1US; + udelay(1); } /* @@ -1518,10 +1534,10 @@ u16 phy_data; outl(0x50000, ioaddr); - DELAY_1US; + udelay(1); phy_data = (inl(ioaddr) >> 19) & 0x1; outl(0x40000, ioaddr); - DELAY_1US; + udelay(1); return phy_data; } @@ -1570,7 +1586,7 @@ /* Description: * when user used insmod to add module, system invoked init_module() - * to initilize and register. + * to initialize and register. */ static int __init dmfe_init_module(void) @@ -1599,12 +1615,10 @@ rc = pci_module_init(&dmfe_driver); if (rc < 0) return rc; - if (rc >= 0) { - printk (KERN_INFO "Davicom DM91xx net driver loaded, version " - DMFE_VERSION "\n"); - return 0; - } - return -ENODEV; + + printk (KERN_INFO "Davicom DM91xx net driver loaded, version " + DMFE_VERSION "\n"); + return 0; } /* diff -u --recursive --new-file v2.4.2/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.4.2/linux/drivers/net/eepro.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/eepro.c Tue Mar 6 19:28:35 2001 @@ -23,6 +23,7 @@ This is a compatibility hardware problem. Versions: + 0.12c fixing some problems with old cards (aris, 01/08/2001) 0.12b misc fixes (aris, 06/26/2000) 0.12a port of version 0.12a of 2.2.x kernels to 2.3.x (aris (aris@conectiva.com.br), 05/19/2000) @@ -96,7 +97,7 @@ */ static const char *version = - "eepro.c: v0.12b 04/26/2000 aris@conectiva.com.br\n"; + "eepro.c: v0.12c 01/08/2000 aris@conectiva.com.br\n"; #include @@ -501,8 +502,10 @@ /* set diagnose flag */ #define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr) +#ifdef ANSWER_TX_AND_RX /* experimental way of handling interrupts */ /* ack for rx/tx int */ #define eepro_ack_rxtx(ioaddr) outb (RX_INT | TX_INT, ioaddr + STATUS_REG) +#endif /* ack for rx int */ #define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG) @@ -585,7 +588,7 @@ return -ENODEV; } -void printEEPROMInfo(short ioaddr, struct net_device *dev) +static void printEEPROMInfo(short ioaddr, struct net_device *dev) { unsigned short Word; int i,j; @@ -776,7 +779,8 @@ } if (dev->irq < 2) { printk(" Duh! illegal interrupt vector stored in EEPROM.\n"); - return -ENODEV; + kfree(dev->priv); + return -ENODEV; } else if (dev->irq==2) @@ -950,6 +954,7 @@ || (irq2dev_map[dev->irq] = dev) == 0) && (irq2dev_map[dev->irq]!=dev)) { /* printk("%s: IRQ map wrong\n", dev->name); */ + free_irq(dev->irq, dev); return -EAGAIN; } #endif @@ -1067,6 +1072,8 @@ } eepro_sel_reset(ioaddr); + SLOW_DOWN; + SLOW_DOWN; lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8; lp->tx_last = 0; @@ -1162,9 +1169,11 @@ while (((status = inb(ioaddr + STATUS_REG)) & 0x06) && (boguscount--)) { switch (status & (RX_INT | TX_INT)) { +#ifdef ANSWER_TX_AND_RX case (RX_INT | TX_INT): eepro_ack_rxtx(ioaddr); break; +#endif case RX_INT: eepro_ack_rx(ioaddr); break; @@ -1178,6 +1187,9 @@ /* Get the received packets */ eepro_rx(dev); +#ifndef ANSWER_TX_AND_RX + continue; +#endif } if (status & TX_INT) { if (net_debug > 4) @@ -1367,7 +1379,11 @@ /* Re-enable RX and TX interrupts */ eepro_en_int(ioaddr); } - eepro_complete_selreset(ioaddr); + if (lp->eepro == LAN595FX_10ISA) { + eepro_complete_selreset(ioaddr); + } + else + eepro_en_rx(ioaddr); } /* The horrible routine to read a word from the serial EEPROM. */ @@ -1535,7 +1551,9 @@ printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); return; } - netif_stop_queue(dev); + if (lp->eepro == LAN595FX_10ISA) + netif_stop_queue(dev); + if (net_debug > 5) printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name); } @@ -1591,6 +1609,7 @@ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; } @@ -1654,9 +1673,13 @@ xmt_status = inw(ioaddr+IO_PORT); if ((xmt_status & TX_DONE_BIT) == 0) { - udelay(40); - boguscount--; - continue; + if (lp->eepro == LAN595FX_10ISA) { + udelay(40); + boguscount--; + continue; + } + else + break; } xmt_status = inw(ioaddr+IO_PORT); @@ -1723,10 +1746,12 @@ * interrupt again for tx. in other words: tx timeout what will take * a lot of time to happen, so we'll do a complete selreset. */ - if (!boguscount) + if (!boguscount && lp->eepro == LAN595FX_10ISA) eepro_complete_selreset(ioaddr); } +#ifdef MODULE + #define MAX_EEPRO 8 static struct net_device dev_eepro[MAX_EEPRO]; @@ -1737,7 +1762,7 @@ }; static int autodetect; -static int n_eepro = 0; +static int n_eepro; /* For linux 2.1.xx */ MODULE_AUTHOR("Pascal Dupuis for the 2.1 stuff (locking,...)"); @@ -1746,8 +1771,6 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i"); MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i"); MODULE_PARM(autodetect, "1-" __MODULE_STRING(1) "i"); - -#ifdef MODULE int init_module(void) diff -u --recursive --new-file v2.4.2/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.4.2/linux/drivers/net/epic100.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/epic100.c Tue Mar 6 19:28:35 2001 @@ -1,6 +1,6 @@ /* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */ /* - Written/copyright 1997-2000 by Donald Becker. + Written/copyright 1997-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. @@ -37,15 +37,19 @@ * Fix locking (jgarzik) * Limit 83c175 probe to ethernet-class PCI devices (rgooch) + LK1.1.6: + * Merge becker version 1.11 + * Move pci_enable_device before any PCI BAR len checks + */ /* These identify the driver base version and may not be removed. */ static const char version[] = -"epic100.c:v1.09 5/29/2000 Written by Donald Becker \n"; +"epic100.c:v1.11 1/7/2001 Written by Donald Becker \n"; static const char version2[] = " http://www.scyld.com/network/epic100.html\n"; static const char version3[] = -" (unofficial 2.4.x kernel port, version 1.1.5, September 7, 2000)\n"; +" (unofficial 2.4.x kernel port, version 1.1.6, January 11, 2001)\n"; /* The user-configurable values. These may be modified when a driver module is loaded.*/ @@ -61,7 +65,7 @@ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ -static int rx_copybreak = 0; +static int rx_copybreak; /* Operational parameters that are set at compile time. */ @@ -73,6 +77,8 @@ #define TX_RING_SIZE 16 #define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ #define RX_RING_SIZE 32 +#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct epic_tx_desc) +#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct epic_rx_desc) /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -161,14 +167,13 @@ enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 }; #define EPIC_TOTAL_SIZE 0x100 +#define USE_IO_OPS 1 #ifdef USE_IO_OPS #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0 #else #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1 #endif -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) - typedef enum { SMSC_83C170_0, SMSC_83C170, @@ -185,7 +190,7 @@ /* indexed by chip_t */ -static struct epic_chip_info epic_chip_info[] __devinitdata = { +static struct epic_chip_info pci_id_tbl[] = { { "SMSC EPIC/100 83c170", EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN }, { "SMSC EPIC/100 83c170", @@ -269,16 +274,18 @@ DescOwn=0x8000, }; - +#define PRIV_ALIGN 15 /* Required alignment mask */ struct epic_private { - /* Tx and Rx rings first so that they remain paragraph aligned. */ - struct epic_rx_desc rx_ring[RX_RING_SIZE]; - struct epic_tx_desc tx_ring[TX_RING_SIZE]; + struct epic_rx_desc *rx_ring; + struct epic_tx_desc *tx_ring; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; + /* Ring pointers. */ spinlock_t lock; /* Group with Tx control cache line. */ unsigned int cur_tx, dirty_tx; @@ -290,7 +297,7 @@ long last_rx_time; /* Last Rx, in jiffies. */ struct pci_dev *pci_dev; /* PCI bus location. */ - int chip_flags; + int chip_id, chip_flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ @@ -301,7 +308,7 @@ int mii_phy_cnt; unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Current duplex setting. */ - unsigned int force_fd:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; /* Duplex forced by the user. */ unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ @@ -310,8 +317,8 @@ static int epic_open(struct net_device *dev); static int read_eeprom(long ioaddr, int location); -static int mdio_read(long ioaddr, int phy_id, int location); -static void mdio_write(long ioaddr, int phy_id, int location, int value); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int loc, int val); static void epic_restart(struct net_device *dev); static void epic_timer(unsigned long data); static void epic_tx_timeout(struct net_device *dev); @@ -330,13 +337,15 @@ const struct pci_device_id *ent) { static int card_idx = -1; - static int printed_version = 0; + static int printed_version; + long ioaddr; + int chip_idx = (int) ent->driver_data; + int irq; struct net_device *dev; struct epic_private *ep; int i, option = 0, duplex = 0; - struct epic_chip_info *ci = &epic_chip_info[ent->driver_data]; - long ioaddr; - int chip_idx = (int) ent->driver_data; + void *ring_space; + dma_addr_t ring_dma; card_idx++; @@ -344,16 +353,16 @@ printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", version, version2, version3); - if ((pci_resource_len(pdev, 0) < ci->io_size) || - (pci_resource_len(pdev, 1) < ci->io_size)) { + i = pci_enable_device(pdev); + if (i) + return i; + irq = pdev->irq; + + if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) { printk (KERN_ERR "card %d: no PCI region space\n", card_idx); return -ENODEV; } - i = pci_enable_device(pdev); - if (i) - return i; - pci_set_master(pdev); dev = init_etherdev(NULL, sizeof (*ep)); @@ -361,20 +370,10 @@ printk (KERN_ERR "card %d: no memory for eth device\n", card_idx); return -ENOMEM; } + SET_MODULE_OWNER(dev); - /* request 100% of both regions 0 and 1, just to make - * sure noone else steals our regions while we are talking - * to them */ - if (!request_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0), dev->name)) { - printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); + if (pci_request_regions(pdev, dev->name)) goto err_out_free_netdev; - } - if (!request_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1), dev->name)) { - printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx); - goto err_out_free_pio; - } #ifdef USE_IO_OPS ioaddr = pci_resource_start (pdev, 0); @@ -383,10 +382,25 @@ ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); if (!ioaddr) { printk (KERN_ERR "epic100 %d: ioremap failed\n", card_idx); - goto err_out_free_mmio; + goto err_out_free_res; } #endif + pci_set_drvdata(pdev, dev); + ep = dev->priv; + + ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_iounmap; + ep->tx_ring = (struct epic_tx_desc *)ring_space; + ep->tx_ring_dma = ring_dma; + + ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); + if (!ring_space) + goto err_out_unmap_tx; + ep->rx_ring = (struct epic_rx_desc *)ring_space; + ep->rx_ring_dma = ring_dma; + if (dev->mem_start) { option = dev->mem_start; duplex = (dev->mem_start & 16) ? 1 : 0; @@ -397,18 +411,13 @@ duplex = full_duplex[card_idx]; } - pdev->driver_data = dev; - dev->base_addr = ioaddr; - dev->irq = pdev->irq; + dev->irq = irq; - ep = dev->priv; - ep->pci_dev = pdev; - ep->chip_flags = ci->drv_flags; spin_lock_init (&ep->lock); printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", - dev->name, ci->name, ioaddr, dev->irq); + dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); @@ -421,7 +430,7 @@ outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); outl(0x0200, ioaddr + GENCTL); - /* This could also be read from the EEPROM. */ + /* Note: the '175 does not have a serial EEPROM. */ for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4)); @@ -436,27 +445,31 @@ i % 16 == 15 ? "\n" : ""); } + ep->pci_dev = pdev; + ep->chip_id = chip_idx; + ep->chip_flags = pci_id_tbl[chip_idx].drv_flags; + /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes much time and no cards have external MII. */ { int phy, phy_idx = 0; for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) { - int mii_status = mdio_read(ioaddr, phy, 1); + int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { ep->phys[phy_idx++] = phy; printk(KERN_INFO "%s: MII transceiver #%d control " "%4.4x status %4.4x.\n", - dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status); + dev->name, phy, mdio_read(dev, phy, 0), mii_status); } } ep->mii_phy_cnt = phy_idx; if (phy_idx != 0) { phy = ep->phys[0]; - ep->advertising = mdio_read(ioaddr, phy, 4); - printk( KERN_INFO "%s: Autonegotiation advertising %4.4x link " - "partner %4.4x.\n", - dev->name, ep->advertising, mdio_read(ioaddr, phy, 5)); + ep->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: Autonegotiation advertising %4.4x link " + "partner %4.4x.\n", + dev->name, ep->advertising, mdio_read(dev, phy, 5)); } else if ( ! (ep->chip_flags & NO_MII)) { printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n", dev->name); @@ -471,7 +484,11 @@ outl(0x0008, ioaddr + GENCTL); /* The lower four bits are the media type. */ - ep->force_fd = duplex; + if (duplex) { + ep->duplex_lock = ep->full_duplex = 1; + printk(KERN_INFO "%s: Forced full duplex operation requested.\n", + dev->name); + } dev->if_port = ep->default_port = option; if (ep->default_port) ep->medialock = 1; @@ -488,14 +505,14 @@ return 0; +err_out_unmap_tx: + pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); +err_out_iounmap: #ifndef USE_IO_OPS -err_out_free_mmio: - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + iounmap(ioaddr); +err_out_free_res: #endif -err_out_free_pio: - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); + pci_release_regions(pdev); err_out_free_netdev: unregister_netdev(dev); kfree(dev); @@ -514,7 +531,7 @@ #define EE_ENB (0x0001 | EE_CS) /* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but 66Mhz is untested. + This serves to flush the operation to the PCI bus. */ #define eeprom_delay() inl(ee_addr) @@ -561,24 +578,34 @@ #define MII_READOP 1 #define MII_WRITEOP 2 -static int mdio_read(long ioaddr, int phy_id, int location) +static int mdio_read(struct net_device *dev, int phy_id, int location) { + long ioaddr = dev->base_addr; + int read_cmd = (phy_id << 9) | (location << 4) | MII_READOP; int i; - outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl); - /* Typical operation takes < 50 ticks. */ - for (i = 4000; i > 0; i--) - if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) + outl(read_cmd, ioaddr + MIICtrl); + /* Typical operation takes 25 loops. */ + for (i = 400; i > 0; i--) + if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) { + /* Work around read failure bug. */ + if (phy_id == 1 && location < 6 + && inw(ioaddr + MIIData) == 0xffff) { + outl(read_cmd, ioaddr + MIICtrl); + continue; + } return inw(ioaddr + MIIData); + } return 0xffff; } -static void mdio_write(long ioaddr, int phy_id, int location, int value) +static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) { + long ioaddr = dev->base_addr; int i; outw(value, ioaddr + MIIData); - outl((phy_id << 9) | (location << 4) | MII_WRITEOP, ioaddr + MIICtrl); + outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl); for (i = 10000; i > 0; i--) { if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0) break; @@ -589,27 +616,21 @@ static int epic_open(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; int i; int retval; - ep->full_duplex = ep->force_fd; - /* Soft reset the chip. */ outl(0x4001, ioaddr + GENCTL); - MOD_INC_USE_COUNT; - - if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev))) { - MOD_DEC_USE_COUNT; + if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev))) return retval; - } epic_init_ring(dev); outl(0x4000, ioaddr + GENCTL); - /* This next magic! line by Ken Yamaguchi.. ?? */ + /* This magic is documented in SMSC app note 7.15 */ outl(0x0008, ioaddr + TEST1); /* Pull the chip out of low-power mode, enable interrupts, and set for @@ -639,21 +660,21 @@ if (media2miictl[dev->if_port & 15]) { if (ep->mii_phy_cnt) - mdio_write(ioaddr, ep->phys[0], 0, media2miictl[dev->if_port&15]); + mdio_write(dev, ep->phys[0], 0, media2miictl[dev->if_port&15]); if (dev->if_port == 1) { if (debug > 1) printk(KERN_INFO "%s: Using the 10base2 transceiver, MII " "status %4.4x.\n", - dev->name, mdio_read(ioaddr, ep->phys[0], 1)); + dev->name, mdio_read(dev, ep->phys[0], 1)); outl(0x13, ioaddr + MIICfg); } } else { - int mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5); + int mii_reg5 = mdio_read(dev, ep->phys[0], 5); if (mii_reg5 != 0xffff) { if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040) ep->full_duplex = 1; else if (! (mii_reg5 & 0x4000)) - mdio_write(ioaddr, ep->phys[0], 0, 0x1200); + mdio_write(dev, ep->phys[0], 0, 0x1200); if (debug > 1) printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d" " register read of %4.4x.\n", dev->name, @@ -663,8 +684,8 @@ } outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - outl(virt_to_bus(ep->rx_ring), ioaddr + PRxCDAR); - outl(virt_to_bus(ep->tx_ring), ioaddr + PTxCDAR); + outl(ep->rx_ring_dma, ioaddr + PRxCDAR); + outl(ep->tx_ring_dma, ioaddr + PTxCDAR); /* Start the chip's Rx process. */ set_rx_mode(dev); @@ -700,7 +721,7 @@ static void epic_pause(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; netif_stop_queue (dev); @@ -723,17 +744,19 @@ static void epic_restart(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; int i; - printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n", - dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx); /* Soft reset the chip. */ - outl(0x0001, ioaddr + GENCTL); + outl(0x4001, ioaddr + GENCTL); + printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n", + dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx); udelay(1); - /* Duplicate code from epic_open(). */ - outl(0x0008, ioaddr + TEST1); + + /* This magic is documented in SMSC app note 7.15 */ + for (i = 16; i > 0; i--) + outl(0x0008, ioaddr + TEST1); #if defined(__powerpc__) || defined(__sparc__) /* Big endian */ outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL); @@ -750,9 +773,10 @@ ep->tx_threshold = TX_FIFO_THRESH; outl(ep->tx_threshold, ioaddr + TxThresh); outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - outl(virt_to_bus(&ep->rx_ring[ep->cur_rx%RX_RING_SIZE]), ioaddr + PRxCDAR); - outl(virt_to_bus(&ep->tx_ring[ep->dirty_tx%TX_RING_SIZE]), - ioaddr + PTxCDAR); + outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)* + sizeof(struct epic_rx_desc), ioaddr + PRxCDAR); + outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)* + sizeof(struct epic_tx_desc), ioaddr + PTxCDAR); /* Start the chip's Rx process. */ set_rx_mode(dev); @@ -770,16 +794,34 @@ return; } -static void epic_timer(unsigned long data) +static void check_media(struct net_device *dev) { - struct net_device *dev = (struct net_device *)data; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - int mii_reg5 = ep->mii_phy_cnt ? mdio_read(ioaddr, ep->phys[0], 5) : 0; + int mii_reg5 = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], 5) : 0; int negotiated = mii_reg5 & ep->advertising; int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (ep->duplex_lock) + return; + if (mii_reg5 == 0xffff) /* Bogus read */ + return; + if (ep->full_duplex != duplex) { + ep->full_duplex = duplex; + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" + " partner capability of %4.4x.\n", dev->name, + ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5); + outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); + } +} + +static void epic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct epic_private *ep = dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 5*HZ; + if (debug > 3) { printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n", dev->name, (int)inl(ioaddr + TxSTAT)); @@ -789,15 +831,7 @@ (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT)); } - if (! ep->force_fd) { - if (ep->full_duplex != duplex) { - ep->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" - " partner capability of %4.4x.\n", dev->name, - ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5); - outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); - } - } + check_media(dev); ep->timer.expires = jiffies + next_tick; add_timer(&ep->timer); @@ -805,7 +839,7 @@ static void epic_tx_timeout(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; if (debug > 0) { @@ -827,13 +861,14 @@ dev->trans_start = jiffies; ep->stats.tx_errors++; - return; + if (!ep->tx_full) + netif_wake_queue(dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void epic_init_ring(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; int i; ep->tx_full = 0; @@ -847,11 +882,12 @@ for (i = 0; i < RX_RING_SIZE; i++) { ep->rx_ring[i].rxstatus = 0; ep->rx_ring[i].buflength = cpu_to_le32(ep->rx_buf_sz); - ep->rx_ring[i].next = virt_to_le32desc(&ep->rx_ring[i+1]); + ep->rx_ring[i].next = ep->rx_ring_dma + + (i+1)*sizeof(struct epic_rx_desc); ep->rx_skbuff[i] = 0; } /* Mark the last entry as wrapping the ring. */ - ep->rx_ring[i-1].next = virt_to_le32desc(&ep->rx_ring[0]); + ep->rx_ring[i-1].next = ep->rx_ring_dma; /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { @@ -861,7 +897,8 @@ break; skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ - ep->rx_ring[i].bufaddr = virt_to_le32desc(skb->tail); + ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, + skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn); } ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -871,29 +908,31 @@ for (i = 0; i < TX_RING_SIZE; i++) { ep->tx_skbuff[i] = 0; ep->tx_ring[i].txstatus = 0x0000; - ep->tx_ring[i].next = virt_to_le32desc(&ep->tx_ring[i+1]); + ep->tx_ring[i].next = ep->tx_ring_dma + + (i+1)*sizeof(struct epic_tx_desc); } - ep->tx_ring[i-1].next = virt_to_le32desc(&ep->tx_ring[0]); + ep->tx_ring[i-1].next = ep->tx_ring_dma; return; } static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; int entry, free_count; u32 ctrl_word; + long flags; /* Caution: the write order is important here, set the field with the "ownership" bit last. */ - spin_lock_irq(&ep->lock); /* Calculate the next Tx descriptor entry. */ + spin_lock_irqsave(&ep->lock, flags); free_count = ep->cur_tx - ep->dirty_tx; entry = ep->cur_tx % TX_RING_SIZE; ep->tx_skbuff[entry] = skb; - ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data); - + ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data, + skb->len, PCI_DMA_TODEVICE); if (free_count < TX_QUEUE_LEN/2) {/* Typical path */ ctrl_word = cpu_to_le32(0x100000); /* No interrupt */ } else if (free_count == TX_QUEUE_LEN/2) { @@ -914,8 +953,7 @@ if (ep->tx_full) netif_stop_queue(dev); - spin_unlock_irq(&ep->lock); - + spin_unlock_irqrestore(&ep->lock, flags); /* Trigger an immediate transmit demand. */ outl(TxQueued, dev->base_addr + COMMAND); @@ -934,12 +972,10 @@ static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_instance; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; int status, boguscnt = max_interrupt_work; - spin_lock(&ep->lock); - do { status = inl(ioaddr + INTSTAT); /* Acknowledge all of the current interrupt sources ASAP. */ @@ -962,9 +998,11 @@ /* Note: if this lock becomes a problem we can narrow the locked region at the cost of occasionally grabbing the lock more times. */ + spin_lock(&ep->lock); cur_tx = ep->cur_tx; dirty_tx = ep->dirty_tx; for (; cur_tx - dirty_tx > 0; dirty_tx++) { + struct sk_buff *skb; int entry = dirty_tx % TX_RING_SIZE; int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus); @@ -975,7 +1013,7 @@ /* There was an major error, log it. */ #ifndef final_version if (debug > 1) - printk("%s: Transmit error, Tx status %8.8x.\n", + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, txstatus); #endif ep->stats.tx_errors++; @@ -996,13 +1034,16 @@ } /* Free the original skb. */ - dev_kfree_skb_irq(ep->tx_skbuff[entry]); + skb = ep->tx_skbuff[entry]; + pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); ep->tx_skbuff[entry] = 0; } #ifndef final_version if (cur_tx - dirty_tx > TX_RING_SIZE) { - printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, cur_tx, ep->tx_full); dirty_tx += TX_RING_SIZE; } @@ -1010,10 +1051,12 @@ ep->dirty_tx = dirty_tx; if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) { - /* The ring is no longer full, clear tbusy. */ + /* The ring is no longer full, allow new TX entries. */ ep->tx_full = 0; + spin_unlock(&ep->lock); netif_wake_queue(dev); - } + } else + spin_unlock(&ep->lock); } /* Check uncommon events all at once. */ @@ -1060,12 +1103,12 @@ printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, status); - spin_unlock(&ep->lock); + return; } static int epic_rx(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; int entry = ep->cur_rx % RX_RING_SIZE; int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx; int work_done = 0; @@ -1074,7 +1117,7 @@ printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry, ep->rx_ring[entry].rxstatus); /* If we own the next entry, it's a new packet. Send it up. */ - while (!(le32_to_cpu(ep->rx_ring[entry].rxstatus) & DescOwn)) { + while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) { int status = le32_to_cpu(ep->rx_ring[entry].rxstatus); if (debug > 4) @@ -1098,6 +1141,10 @@ short pkt_len = (status >> 16) - 4; struct sk_buff *skb; + pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, PCI_DMA_FROMDEVICE); + pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, PCI_DMA_FROMDEVICE); if (pkt_len > PKT_BUF_SZ - 4) { printk(KERN_ERR "%s: Oversized Ethernet frame, status %x " "%d bytes.\n", @@ -1141,7 +1188,8 @@ break; skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - ep->rx_ring[entry].bufaddr = virt_to_le32desc(skb->tail); + ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, + skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); work_done++; } ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn); @@ -1152,7 +1200,8 @@ static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; + struct sk_buff *skb; int i; netif_stop_queue(dev); @@ -1167,31 +1216,36 @@ /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = ep->rx_skbuff[i]; + skb = ep->rx_skbuff[i]; ep->rx_skbuff[i] = 0; ep->rx_ring[i].rxstatus = 0; /* Not owned by Epic chip. */ ep->rx_ring[i].buflength = 0; - ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ if (skb) { + pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr, + ep->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); } + ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */ } for (i = 0; i < TX_RING_SIZE; i++) { - if (ep->tx_skbuff[i]) - dev_kfree_skb(ep->tx_skbuff[i]); + skb = ep->tx_skbuff[i]; ep->tx_skbuff[i] = 0; + if (!skb) + continue; + pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); } /* Green! Leave the chip in low-power mode. */ outl(0x0008, ioaddr + GENCTL); - MOD_DEC_USE_COUNT; return 0; } static struct net_device_stats *epic_get_stats(struct net_device *dev) { - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; long ioaddr = dev->base_addr; if (netif_running(dev)) { @@ -1233,7 +1287,7 @@ static void set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = (struct epic_private *)dev->priv; + struct epic_private *ep = dev->priv; unsigned char mc_filter[8]; /* Multicast hash filter */ int i; @@ -1271,25 +1325,26 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct epic_private *ep = (void *)dev->priv; long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f; + data[0] = ep->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ if (! netif_running(dev)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } - data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); +#if 0 /* Just leave on if the ioctl() is ever used. */ if (! netif_running(dev)) { -#ifdef notdef /* Leave on if the ioctl() is used. */ outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); -#endif } +#endif return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) @@ -1298,13 +1353,26 @@ outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } - mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + if (data[0] == ep->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + ep->duplex_lock = (value & 0x9000) ? 0 : 1; + if (ep->duplex_lock) + ep->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: ep->advertising = value; break; + } + /* Perhaps check_duplex(dev), depending on chip semantics. */ + } + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); +#if 0 /* Leave on if the ioctl() is used. */ if (! netif_running(dev)) { -#ifdef notdef /* Leave on if the ioctl() is used. */ outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); -#endif } +#endif return 0; default: return -EOPNOTSUPP; @@ -1314,36 +1382,40 @@ static void __devexit epic_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); + struct epic_private *ep = dev->priv; + pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); + pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); unregister_netdev(dev); #ifndef USE_IO_OPS - iounmap ((void*) dev->base_addr); + iounmap((void*) dev->base_addr); #endif - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); + pci_release_regions(pdev); kfree(dev); + pci_set_drvdata(pdev, NULL); + /* pci_power_off(pdev, -1); */ } static void epic_suspend (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); long ioaddr = dev->base_addr; epic_pause(dev); /* Put the chip into low-power mode. */ outl(0x0008, ioaddr + GENCTL); + /* pci_power_off(pdev, -1); */ } static void epic_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); - epic_restart (dev); + epic_restart(dev); + /* pci_power_on(pdev); */ } diff -u --recursive --new-file v2.4.2/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.4.2/linux/drivers/net/eth16i.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/eth16i.c Sat Mar 3 10:55:48 2001 @@ -1195,10 +1195,6 @@ } skb->protocol=eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; if( eth16i_debug > 5 ) { int i; @@ -1208,6 +1204,10 @@ printk(KERN_DEBUG " %02x", skb->data[i]); printk(KERN_DEBUG ".\n"); } + netif_rx(skb); + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } /* else */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v2.4.2/linux/drivers/net/ewrk3.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/ewrk3.c Sat Mar 3 10:55:48 2001 @@ -997,19 +997,6 @@ isa_memcpy_fromio(p, buf, pkt_len); } - /* - ** Notify the upper protocol layers that there is another - ** packet to handle - */ - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - /* - ** Update stats - */ - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) { if (pkt_len < i * EWRK3_PKT_BIN_SZ) { lp->pktStats.bins[i]++; @@ -1031,6 +1018,19 @@ if (lp->pktStats.bins[0] == 0) { /* Reset counters */ memset(&lp->pktStats, 0, sizeof(lp->pktStats)); } + /* + ** Notify the upper protocol layers that there is another + ** packet to handle + */ + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + /* + ** Update stats + */ + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } else { printk("%s: Insufficient memory; nuking packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c --- v2.4.2/linux/drivers/net/fmv18x.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/fmv18x.c Sat Mar 3 10:55:48 2001 @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -79,6 +80,7 @@ uint rx_started:1; /* Packets are Rxing. */ uchar tx_queue; /* Number of packet on the Tx queue. */ ushort tx_queue_len; /* Current length of the Tx queue. */ + spinlock_t lock; }; @@ -161,6 +163,7 @@ char irqmap[4] = {3, 7, 10, 15}; char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15}; unsigned int i, irq, retval; + struct net_local *lp; /* Resetting the chip doesn't reset the ISA interface, so don't bother. That means we have to be careful with the register values we probe for. @@ -268,6 +271,8 @@ goto out_irq; } memset(dev->priv, 0, sizeof(struct net_local)); + lp = dev->priv; + spin_lock_init(&lp->lock); dev->open = net_open; dev->stop = net_close; @@ -292,7 +297,7 @@ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; int ioaddr = dev->base_addr; /* Set the configuration register 0 to 32K 100ns. byte-wide memory, @@ -326,7 +331,7 @@ static void net_timeout(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; int ioaddr = dev->base_addr; unsigned long flags; @@ -346,8 +351,7 @@ htons(inw(ioaddr+FJ_CONFIG0))); lp->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ - save_flags(flags); - cli(); + spin_lock_irqsave(&lp->lock, flags); /* Initialize LAN Controller and LAN Card */ outb(0xda, ioaddr + CONFIG_0); /* Initialize LAN Controller */ @@ -355,20 +359,21 @@ outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */ outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */ net_open(dev); - restore_flags(flags); + spin_unlock_irqrestore(&lp->lock, flags); + + netif_wake_queue(dev); } static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; int ioaddr = dev->base_addr; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; + unsigned long flags; /* Block a transmit from overlapping. */ - netif_stop_queue(dev); - if (length > ETH_FRAME_LEN) { if (net_debug) printk("%s: Attempting to send a large packet (%d bytes).\n", @@ -383,6 +388,7 @@ codes we possibly catch a Tx interrupt. Thus we flag off tx_queue_ready, so that we prevent the interrupt routine (net_interrupt) to start transmitting. */ + spin_lock_irqsave(&lp->lock, flags); lp->tx_queue_ready = 0; { outw(length, ioaddr + DATAPORT); @@ -391,6 +397,8 @@ lp->tx_queue_len += length + 2; } lp->tx_queue_ready = 1; + spin_unlock_irqrestore(&lp->lock, flags); + if (lp->tx_started == 0) { /* If the Tx is idle, always trigger a transmit. */ outb(0x80 | lp->tx_queue, ioaddr + TX_START); @@ -398,10 +406,10 @@ lp->tx_queue_len = 0; dev->trans_start = jiffies; lp->tx_started = 1; - netif_wake_queue(dev); } else if (lp->tx_queue_len < 4096 - 1502) /* Yes, there is room for one more packet. */ - netif_wake_queue(dev); + else + netif_stop_queue(dev); dev_kfree_skb(skb); return 0; @@ -417,7 +425,7 @@ int ioaddr, status; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = dev->priv; status = inw(ioaddr + TX_STATUS); outw(status, ioaddr + TX_STATUS); @@ -447,6 +455,7 @@ lp->stats.collisions++; } if (status & 0x82) { + spin_lock(&lp->lock); lp->stats.tx_packets++; if (lp->tx_queue && lp->tx_queue_ready) { outb(0x80 | lp->tx_queue, ioaddr + TX_START); @@ -458,6 +467,7 @@ lp->tx_started = 0; netif_wake_queue(dev); /* Inform upper layers. */ } + spin_unlock(&lp->lock); } } return; @@ -466,7 +476,7 @@ /* We have a good packet(s), get it/them out of the buffers. */ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; int ioaddr = dev->base_addr; int boguscount = 5; @@ -581,7 +591,7 @@ closed. */ static struct net_device_stats *net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = dev->priv; return &lp->stats; } diff -u --recursive --new-file v2.4.2/linux/drivers/net/hamachi.c linux/drivers/net/hamachi.c --- v2.4.2/linux/drivers/net/hamachi.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/hamachi.c Sat Mar 3 10:55:48 2001 @@ -477,6 +477,7 @@ }; #define PRIV_ALIGN 15 /* Required alignment mask */ +#define MII_CNT 4 struct hamachi_private { /* Descriptor rings first for alignment. Tx requires a second descriptor for status. */ @@ -503,7 +504,7 @@ /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ + unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ u_int32_t rx_int_var, tx_int_var; /* interrupt control variables */ u_int32_t option; /* Hold on to a copy of the options */ u_int8_t pad[16]; /* Used for 32-byte alignment */ @@ -554,7 +555,7 @@ struct hamachi_private *hmp; int option, i, rx_int_var, tx_int_var, boguscnt; int chip_id = ent->driver_data; - int irq = pdev->irq; + int irq; long ioaddr; static int card_idx = 0; struct net_device *dev; @@ -562,15 +563,17 @@ if (hamachi_debug > 0 && did_version++ == 0) printk(version); + if (pci_enable_device(pdev)) + return -EIO; + ioaddr = pci_resource_start(pdev, 0); #ifdef __alpha__ /* Really "64 bit addrs" */ ioaddr |= (pci_resource_start(pdev, 1) << 32); #endif - if (pci_enable_device(pdev)) - return -EIO; pci_set_master(pdev); + irq = pdev->irq; ioaddr = (long) ioremap(ioaddr, 0x400); if (!ioaddr) return -ENOMEM; @@ -703,7 +706,7 @@ if (chip_tbl[hmp->chip_id].flags & CanHaveMII) { int phy, phy_idx = 0; - for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(ioaddr, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { @@ -1062,7 +1065,6 @@ hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as wrapping the ring. */ hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); - /* Trigger an immediate transmit demand. */ dev->trans_start = jiffies; diff -u --recursive --new-file v2.4.2/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c --- v2.4.2/linux/drivers/net/hamradio/scc.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/hamradio/scc.c Tue Mar 6 19:28:34 2001 @@ -689,7 +689,7 @@ break; } - /* This looks wierd and it is. At least the BayCom USCC doesn't + /* This looks weird and it is. At least the BayCom USCC doesn't * use the Interrupt Daisy Chain, thus we'll have to start * all over again to be sure not to miss an interrupt from * (any of) the other chip(s)... diff -u --recursive --new-file v2.4.2/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v2.4.2/linux/drivers/net/hp100.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/hp100.c Sat Mar 3 10:55:47 2001 @@ -45,6 +45,8 @@ ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ** +** 1.57b -> 1.57c - Arnaldo Carvalho de Melo +** - release resources on failure in init_module ** ** 1.57 -> 1.57b - Jean II ** - fix spinlocks, SMP is now working ! @@ -265,12 +267,14 @@ #define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id)) +#ifdef CONFIG_PCI static struct hp100_pci_id hp100_pci_ids[] = { { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A }, { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B }, { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4 }, { PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG } }; +#endif #define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id)) @@ -1896,7 +1900,7 @@ /* First get indication of received lan packet */ /* RX_PKT_CND indicates the number of packets which have been fully */ - /* received onto the card but have not been fully transfered of the card */ + /* received onto the card but have not been fully transferred of the card */ packets = hp100_inb( RX_PKT_CNT ); #ifdef HP100_DEBUG_RX if ( packets > 1 ) @@ -1967,11 +1971,6 @@ insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 ); skb->protocol = eth_type_trans( skb, dev ); - - netif_rx( skb ); - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; #ifdef HP100_DEBUG_RX printk( "hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", @@ -1979,6 +1978,10 @@ ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ], ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] ); #endif + netif_rx( skb ); + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } /* Indicate the card that we have got the packet */ @@ -3017,16 +3020,34 @@ #ifdef MODULE /* Parameters set by insmod */ -int hp100_port[5] = { 0, -1, -1, -1, -1 }; +static int hp100_port[5] = { 0, -1, -1, -1, -1 }; MODULE_PARM(hp100_port, "1-5i"); /* Allocate 5 string of length IFNAMSIZ, one string for each device */ -char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; +static char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; /* Allow insmod to write those 5 strings individually */ MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ)); /* List of devices */ -static struct net_device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL }; +static struct net_device *hp100_devlist[5]; + +static void release_dev(int i) +{ + struct net_device *d = hp100_devlist[i]; + struct hp100_private *p = (struct hp100_private *)d->priv; + + unregister_netdev(d); + release_region(d->base_addr, HP100_REGION_SIZE); + + if (p->mode == 1) /* busmaster */ + kfree(p->page_vaddr); + if (p->mem_ptr_virt) + iounmap(p->mem_ptr_virt); + kfree(d->priv); + d->priv = NULL; + kfree(d); + hp100_devlist[i] = NULL; +} /* * Note: if you have more than five 100vg cards in your pc, feel free to @@ -3053,6 +3074,8 @@ { /* Create device and set basics args */ hp100_devlist[i] = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!hp100_devlist[i]) + goto fail; memset(hp100_devlist[i], 0x00, sizeof(struct net_device)); #if LINUX_VERSION_CODE >= 0x020362 /* 2.3.99-pre7 */ memcpy(hp100_devlist[i]->name, hp100_name[i], IFNAMSIZ); /* Copy name */ @@ -3075,6 +3098,13 @@ } /* Loop over all devices */ return cards > 0 ? 0 : -ENODEV; + fail: + while (cards && --i) + if (hp100_devlist[i]) { + release_dev(i); + --cards; + } + return -ENOMEM; } void cleanup_module( void ) @@ -3084,18 +3114,7 @@ /* TODO: Check if all skb's are released/freed. */ for(i = 0; i < 5; i++) if(hp100_devlist[i] != (struct net_device *) NULL) - { - unregister_netdev( hp100_devlist[i] ); - release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE ); - if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */ - kfree( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr ); - if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ) - iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ); - kfree( hp100_devlist[i]->priv ); - hp100_devlist[i]->priv = NULL; - kfree(hp100_devlist[i]); - hp100_devlist[i] = (struct net_device *) NULL; - } + release_dev(i); } #endif /* MODULE */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/ibmlana.h linux/drivers/net/ibmlana.h --- v2.4.2/linux/drivers/net/ibmlana.h Tue Jul 11 11:12:23 2000 +++ linux/drivers/net/ibmlana.h Tue Mar 6 19:28:34 2001 @@ -127,12 +127,12 @@ #define TCREG_POWC 0x4000 /* timer start out of window detect */ #define TCREG_CRCI 0x2000 /* inhibit CRC generation */ #define TCREG_EXDIS 0x1000 /* disable excessive deferral timer */ -#define TCREG_EXD 0x0400 /* excessive deferral occured */ -#define TCREG_DEF 0x0200 /* single deferral occured */ +#define TCREG_EXD 0x0400 /* excessive deferral occurred */ +#define TCREG_DEF 0x0200 /* single deferral occurred */ #define TCREG_NCRS 0x0100 /* no carrier detected */ #define TCREG_CRSL 0x0080 /* carrier lost */ -#define TCREG_EXC 0x0040 /* excessive collisions occured */ -#define TCREG_OWC 0x0020 /* out of window collision occured */ +#define TCREG_EXC 0x0040 /* excessive collisions occurred */ +#define TCREG_OWC 0x0020 /* out of window collision occurred */ #define TCREG_PMB 0x0008 /* packet monitored bad */ #define TCREG_FU 0x0004 /* FIFO underrun */ #define TCREG_BCM 0x0002 /* byte count mismatch of fragments */ @@ -141,7 +141,7 @@ /* Interrupt Mask Register */ #define SONIC_IMREG 0x08 -#define IMREG_BREN 0x4000 /* interrupt when bus retry occured */ +#define IMREG_BREN 0x4000 /* interrupt when bus retry occurred */ #define IMREG_HBLEN 0x2000 /* interrupt when heartbeat lost */ #define IMREG_LCDEN 0x1000 /* interrupt when CAM loaded */ #define IMREG_PINTEN 0x0800 /* interrupt when PINT in TDA set */ @@ -160,7 +160,7 @@ /* Interrupt Status Register */ #define SONIC_ISREG 0x0a -#define ISREG_BR 0x4000 /* bus retry occured */ +#define ISREG_BR 0x4000 /* bus retry occurred */ #define ISREG_HBL 0x2000 /* heartbeat lost */ #define ISREG_LCD 0x1000 /* CAM loaded */ #define ISREG_PINT 0x0800 /* PINT in TDA set */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c --- v2.4.2/linux/drivers/net/ioc3-eth.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/ioc3-eth.c Sat Mar 3 10:55:47 2001 @@ -862,9 +862,6 @@ ioc3_init(dev); netif_start_queue(dev); - - MOD_INC_USE_COUNT; - return 0; } @@ -880,9 +877,6 @@ free_irq(dev->irq, dev); ioc3_free_rings(ip); - - MOD_DEC_USE_COUNT; - return 0; } @@ -894,13 +888,14 @@ struct ioc3 *ioc3; unsigned long ioc3_base, ioc3_size; u32 vendor, model, rev; - int phy; + int phy, err; dev = init_etherdev(0, sizeof(struct ioc3_private)); if (!dev) return -ENOMEM; + SET_MODULE_OWNER(dev); ip = dev->priv; memset(ip, 0, sizeof(*ip)); @@ -916,6 +911,11 @@ ioc3_base = pdev->resource[0].start; ioc3_size = pdev->resource[0].end - ioc3_base; ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size); + if (!ioc3) { + printk(KERN_CRIT"%s: Unable to map device I/O.\n", dev->name); + err = -ENOMEM; + goto out_free; + } ip->regs = ioc3; spin_lock_init(&ip->ioc3_lock); @@ -930,11 +930,8 @@ phy = ip->phy; if (phy == -1) { printk(KERN_CRIT"%s: Didn't find a PHY, goodbye.\n", dev->name); - ioc3_stop(dev); - free_irq(dev->irq, dev); - ioc3_free_rings(ip); - - return -ENODEV; + err = -ENODEV; + goto out_stop; } mii0 = mii_read(ioc3, phy, 0); @@ -967,11 +964,19 @@ dev->set_multicast_list = ioc3_set_multicast_list; return 0; + +out_stop: + ioc3_stop(dev); + free_irq(dev->irq, dev); + ioc3_free_rings(ip); +out_free: + kfree(dev); + return err; } static int __init ioc3_probe(void) { - static int called = 0; + static int called; int cards = 0; if (called) @@ -1192,10 +1197,8 @@ } } -#ifdef MODULE MODULE_AUTHOR("Ralf Baechle "); MODULE_DESCRIPTION("SGI IOC3 Ethernet driver"); -#endif /* MODULE */ module_init(ioc3_probe); module_exit(ioc3_cleanup_module); diff -u --recursive --new-file v2.4.2/linux/drivers/net/jazzsonic.c linux/drivers/net/jazzsonic.c --- v2.4.2/linux/drivers/net/jazzsonic.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/jazzsonic.c Sat Mar 3 10:55:47 2001 @@ -62,7 +62,7 @@ #endif /* - * Base address and interupt of the SONIC controller on JAZZ boards + * Base address and interrupt of the SONIC controller on JAZZ boards */ static struct { unsigned int port; diff -u --recursive --new-file v2.4.2/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.4.2/linux/drivers/net/lance.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/lance.c Tue Mar 6 19:28:35 2001 @@ -33,6 +33,9 @@ Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from the 2.1 version of the old driver - Alan Cox + + Get rid of check_region, check kmalloc return in lance_probe1 + Arnaldo Carvalho de Melo - 11/01/2001 */ static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n"; @@ -61,9 +64,9 @@ static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options); #ifdef LANCE_DEBUG -int lance_debug = LANCE_DEBUG; +static int lance_debug = LANCE_DEBUG; #else -int lance_debug = 1; +static int lance_debug = 1; #endif /* @@ -295,6 +298,7 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i"); +MODULE_PARM(lance_debug, "i"); int init_module(void) { @@ -352,17 +356,27 @@ for (port = lance_portlist; *port; port++) { int ioaddr = *port; + struct resource *r = request_region(ioaddr, LANCE_TOTAL_SIZE, + "lance-probe"); - if ( check_region(ioaddr, LANCE_TOTAL_SIZE) == 0) { + if (r) { /* Detect "normal" 0x57 0x57 and the NI6510EB 0x52 0x44 signatures w/ minimal I/O reads */ char offset15, offset14 = inb(ioaddr + 14); if ((offset14 == 0x52 || offset14 == 0x57) && - ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) { + ((offset15 = inb(ioaddr + 15)) == 0x57 || + offset15 == 0x44)) { result = lance_probe1(dev, ioaddr, 0, 0); - if ( !result ) return 0; + if (!result) { + struct lance_private *lp = dev->priv; + int ver = lp->chip_version; + + r->name = chip_table[ver].name; + return 0; + } } + release_resource(r); } } return -ENODEV; @@ -444,12 +458,10 @@ printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); dev->base_addr = ioaddr; - request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name); - /* Make certain the data structures used by the LANCE are aligned and DMAble. */ lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7, - GFP_DMA | GFP_KERNEL)+7) & ~7); + GFP_DMA | GFP_KERNEL)+7) & ~7); if(lp==NULL) return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); @@ -457,11 +469,15 @@ dev->priv = lp; lp->name = chipname; lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE, - GFP_DMA | GFP_KERNEL); - if (lance_need_isa_bounce_buffers) + GFP_DMA | GFP_KERNEL); + if (!lp->rx_buffs) + goto out_lp; + if (lance_need_isa_bounce_buffers) { lp->tx_bounce_buffs = kmalloc(PKT_BUF_SZ*TX_RING_SIZE, - GFP_DMA | GFP_KERNEL); - else + GFP_DMA | GFP_KERNEL); + if (!lp->tx_bounce_buffs) + goto out_rx; + } else lp->tx_bounce_buffs = NULL; lp->chip_version = lance_version; @@ -628,6 +644,9 @@ dev->watchdog_timeo = TX_TIMEOUT; return 0; +out_rx: kfree((void*)lp->rx_buffs); +out_lp: kfree(lp); + return -ENOMEM; } static int diff -u --recursive --new-file v2.4.2/linux/drivers/net/mac89x0.c linux/drivers/net/mac89x0.c --- v2.4.2/linux/drivers/net/mac89x0.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/mac89x0.c Tue Mar 6 19:28:35 2001 @@ -48,6 +48,11 @@ I/O space and NuBus interrupts for these cards, but neglected to provide anything even remotely resembling a NuBus ROM. Therefore we have to probe for them in a brain-damaged ISA-like fashion. + + Arnaldo Carvalho de Melo - 11/01/2001 + check kmalloc and release the allocated memory on failure in + mac89x0_probe and in init_module + use save_flags/restore_flags in net_get_stat, not just cli/sti */ static char *version = @@ -167,9 +172,9 @@ anywhere else until we have a really good reason to do so. */ int __init mac89x0_probe(struct net_device *dev) { - static int once_is_enough = 0; + static int once_is_enough; struct net_local *lp; - static unsigned version_printed = 0; + static unsigned version_printed; int i, slot; unsigned rev_type = 0; unsigned long ioaddr; @@ -213,6 +218,8 @@ /* Initialize the net_device structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (!dev->priv) + return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); } lp = (struct net_local *)dev->priv; @@ -252,6 +259,8 @@ /* Try to read the MAC address */ if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { printk("\nmac89x0: No EEPROM, giving up now.\n"); + kfree(dev->priv); + dev->priv = NULL; return -ENODEV; } else { for (i = 0; i < ETH_ALEN; i += 2) { @@ -558,12 +567,14 @@ net_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + save_flags(flags); cli(); /* Update the statistics from the device registers. */ lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); - sti(); + restore_flags(flags); return &lp->stats; } @@ -621,16 +632,16 @@ int init_module(void) { - struct net_local *lp; - net_debug = debug; dev_cs89x0.init = mac89x0_probe; dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (!dev_cs89x0.priv) + return -ENOMEM; memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); - lp = (struct net_local *)dev_cs89x0.priv; if (register_netdev(&dev_cs89x0) != 0) { printk(KERN_WARNING "mac89x0.c: No card found\n"); + kfree(dev_cs89x0.priv); return -ENXIO; } return 0; diff -u --recursive --new-file v2.4.2/linux/drivers/net/macmace.c linux/drivers/net/macmace.c --- v2.4.2/linux/drivers/net/macmace.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/macmace.c Sat Mar 3 10:55:47 2001 @@ -632,7 +632,7 @@ } /* - * A transmit error has occured. (We kick the transmit side from + * A transmit error has occurred. (We kick the transmit side from * the DMA completion) */ @@ -661,7 +661,7 @@ } /* - * A receive interrupt occured. + * A receive interrupt occurred. */ static void mace68k_recv_interrupt(struct net_device *dev) diff -u --recursive --new-file v2.4.2/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c --- v2.4.2/linux/drivers/net/macsonic.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/macsonic.c Tue Mar 6 19:28:35 2001 @@ -59,8 +59,8 @@ #include "sonic.h" -static int sonic_debug = 0; -static int sonic_version_printed = 0; +static int sonic_debug; +static int sonic_version_printed; extern int macsonic_probe(struct net_device* dev); extern int mac_onboard_sonic_probe(struct net_device* dev); @@ -272,7 +272,7 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) { /* Bwahahaha */ - static int once_is_more_than_enough = 0; + static int once_is_more_than_enough; struct sonic_local* lp; int i; @@ -438,7 +438,7 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) { - static int slots = 0; + static int slots; struct nubus_dev* ndev = NULL; struct sonic_local* lp; unsigned long base_addr, prom_addr; @@ -567,11 +567,7 @@ #ifdef MODULE static char namespace[16] = ""; -static struct net_device dev_macsonic = { - NULL, - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, NULL }; +static struct net_device dev_macsonic; MODULE_PARM(sonic_debug, "i"); diff -u --recursive --new-file v2.4.2/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v2.4.2/linux/drivers/net/ne.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/ne.c Tue Mar 6 19:28:34 2001 @@ -76,13 +76,18 @@ }; #endif -static struct { unsigned short vendor, function; char *name; } -isapnp_clone_list[] __initdata = { - {ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), "NN NE2000" }, - {ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6), "Generic PNP" }, - {0,} +static struct isapnp_device_id isapnp_clone_list[] __initdata = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), + (long) "NN NE2000" }, + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6), + (long) "Generic PNP" }, + { } /* terminate list */ }; +MODULE_DEVICE_TABLE(isapnp, isapnp_clone_list); + #ifdef SUPPORT_NE_BAD_CLONES /* A list of bad clones that we none-the-less recognize. */ static struct { const char *name8, *name16; unsigned char SAprefix[4];} @@ -206,7 +211,7 @@ dev->base_addr = idev->resource[0].start; dev->irq = idev->irq_resource[0].start; printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", - isapnp_clone_list[i].name, + (char *) isapnp_clone_list[i].driver_data, dev->base_addr, dev->irq); if (ne_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.4.2/linux/drivers/net/net_init.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/net_init.c Fri Mar 2 11:02:15 2001 @@ -390,23 +390,6 @@ #endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */ -int ether_config(struct net_device *dev, struct ifmap *map) -{ - if (map->mem_start != (u_long)(-1)) - dev->mem_start = map->mem_start; - if (map->mem_end != (u_long)(-1)) - dev->mem_end = map->mem_end; - if (map->base_addr != (u_short)(-1)) - dev->base_addr = map->base_addr; - if (map->irq != (u_char)(-1)) - dev->irq = map->irq; - if (map->dma != (u_char)(-1)) - dev->dma = map->dma; - if (map->port != (u_char)(-1)) - dev->if_port = map->port; - return 0; -} - int register_netdev(struct net_device *dev) { int err; diff -u --recursive --new-file v2.4.2/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c --- v2.4.2/linux/drivers/net/ni5010.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/ni5010.c Tue Mar 6 19:28:34 2001 @@ -469,7 +469,7 @@ } if ((status & IS_DMA_INT) == 0) { - PRINTK((KERN_DEBUG "%s: DMA complete (???)\n", dev->name)); + PRINTK((KERN_DEBUG "%s: DMA complete (?)\n", dev->name)); outb(0, IE_DMA_RST); /* Reset DMA int */ } diff -u --recursive --new-file v2.4.2/linux/drivers/net/ni52.h linux/drivers/net/ni52.h --- v2.4.2/linux/drivers/net/ni52.h Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/ni52.h Tue Mar 6 19:28:34 2001 @@ -68,7 +68,7 @@ unsigned short cbl_offset; /* pointeroffset, command block list */ unsigned short rfa_offset; /* pointeroffset, receive frame area */ unsigned short crc_errs; /* CRC-Error counter */ - unsigned short aln_errs; /* allignmenterror counter */ + unsigned short aln_errs; /* alignmenterror counter */ unsigned short rsc_errs; /* Resourceerror counter */ unsigned short ovrn_errs; /* OVerrunerror counter */ }; diff -u --recursive --new-file v2.4.2/linux/drivers/net/oaknet.c linux/drivers/net/oaknet.c --- v2.4.2/linux/drivers/net/oaknet.c Sat Dec 30 11:23:14 2000 +++ linux/drivers/net/oaknet.c Sat Mar 3 10:55:47 2001 @@ -53,7 +53,7 @@ static const char *name = "National DP83902AV"; -static struct net_device *oaknet_devs = NULL; +static struct net_device *oaknet_devs; /* Function Prototypes */ @@ -94,6 +94,7 @@ { register int i; int reg0, regd; + int ret; struct net_device tmp, *dev = NULL; #if 0 unsigned long ioaddr = OAKNET_IO_BASE; @@ -102,6 +103,8 @@ #endif bd_t *bip = (bd_t *)__res; + if (!ioaddr) + return -ENOMEM; /* * This MUST happen here because of the nic_* macros * which have an implicit dependency on dev->base_addr. @@ -110,15 +113,15 @@ tmp.base_addr = ioaddr; dev = &tmp; + ret = -EBUSY; if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) - return -EBUSY; + goto out_unmap; /* Quick register check to see if the device is really there. */ - if ((reg0 = ei_ibp(ioaddr)) == 0xFF) { - release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); - return (ENODEV); - } + ret = -ENODEV; + if ((reg0 = ei_ibp(ioaddr)) == 0xFF) + goto out_region; /* * That worked. Now a more thorough check, using the multicast @@ -134,13 +137,11 @@ /* It's no good. Fix things back up and leave. */ + ret = -ENODEV; if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) { ei_obp(reg0, ioaddr); ei_obp(regd, ioaddr + 0x0D); - dev->base_addr = 0; - - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (-ENODEV); + goto out_region; } /* @@ -149,10 +150,9 @@ */ dev = init_etherdev(NULL, 0); - if (!dev) { - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (-ENOMEM); - } + ret = -ENOMEM; + if (!dev) + goto out_region; SET_MODULE_OWNER(dev); oaknet_devs = dev; @@ -166,10 +166,10 @@ /* Allocate 8390-specific device-private area and fields. */ + ret = -ENOMEM; if (ethdev_init(dev)) { printk(" unable to get memory for dev->priv.\n"); - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (-ENOMEM); + goto out_dev; } /* @@ -182,12 +182,11 @@ /* Attempt to get the interrupt line */ + ret = -EAGAIN; if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) { printk("%s: unable to request interrupt %d.\n", dev->name, dev->irq); - kfree(dev->priv); - release_region(dev->base_addr, OAKNET_IO_SIZE); - return (EAGAIN); + goto out_priv; } /* Tell the world about what and where we've found. */ @@ -218,6 +217,16 @@ NS8390_init(dev, FALSE); return (0); +out_priv: + kfree(dev->priv); +out_dev: + unregister_netdev(dev); + kfree(dev); +out_region: + release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); +out_unmap: + iounmap(ioaddr); + return ret; } /* @@ -303,8 +312,6 @@ ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD); ei_status.txing = 0; ei_status.dmaing = 0; - - return; } /* @@ -365,8 +372,6 @@ outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ ei_status.dmaing &= ~0x01; - - return; } /* @@ -444,8 +449,6 @@ #ifdef OAKNET_DISINT restore_flags(flags); #endif - - return; } /* @@ -627,8 +630,6 @@ ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */ ei_status.dmaing &= ~0x01; - - return; } /* @@ -636,7 +637,7 @@ * * Description: * This routine prints out a last-ditch informative message to the console - * indicating that a DMA error occured. If you see this, it's the last + * indicating that a DMA error occurred. If you see this, it's the last * thing you'll see. * * Input(s): @@ -658,8 +659,6 @@ "[DMAstat:%d][irqlock:%d][intr:%ld]\n", dev->name, name, ei_status.dmaing, ei_status.irqlock, dev->interrupt); - - return; } /* @@ -686,12 +685,13 @@ void *priv = oaknet_devs->priv; free_irq(oaknet_devs->irq, oaknet_devs); release_region(ioaddr, OAKNET_IO_SIZE); + iounmap(ioaddr); unregister_netdev(oaknet_dev); kfree(priv); } - oaknet_devs = NULL; - + /* Convert to loop once driver supports multiple devices. */ + kfree(oaknet_devs); } module_init(oaknet_init_module); diff -u --recursive --new-file v2.4.2/linux/drivers/net/pci-skeleton.c linux/drivers/net/pci-skeleton.c --- v2.4.2/linux/drivers/net/pci-skeleton.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pci-skeleton.c Tue Mar 6 19:28:34 2001 @@ -609,6 +609,11 @@ SET_MODULE_OWNER(dev); tp = dev->priv; + /* enable device (incl. PCI PM wakeup), and bus-mastering */ + rc = pci_enable_device (pdev); + if (rc) + goto err_out; + pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); pio_flags = pci_resource_flags (pdev, 0); @@ -623,8 +628,6 @@ * we talk to the chip directly */ DPRINTK("PIO region size == 0x%02X\n", pio_len); DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); - if (pio_len == RTL8139B_IO_SIZE) - tp->chipset = CH_8139B; /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { @@ -648,24 +651,9 @@ goto err_out; } - /* make sure our PIO region in PCI space is available */ - if (!request_region (pio_start, pio_len, dev->name)) { - printk (KERN_ERR PFX "no I/O resource available, aborting\n"); - rc = -EBUSY; - goto err_out; - } - - /* make sure our MMIO region in PCI space is available */ - if (!request_mem_region (mmio_start, mmio_len, dev->name)) { - printk (KERN_ERR PFX "no mem resource available, aborting\n"); - rc = -EBUSY; - goto err_out_free_pio; - } - - /* enable device (incl. PCI PM wakeup), and bus-mastering */ - rc = pci_enable_device (pdev); + rc = pci_request_regions (pdev, dev->name); if (rc) - goto err_out_free_mmio; + goto err_out; pci_set_master (pdev); @@ -677,7 +665,7 @@ if (ioaddr == NULL) { printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; - goto err_out_free_mmio; + goto err_out_free_res; } #endif /* USE_IO_OPS */ @@ -692,14 +680,7 @@ udelay (10); /* Bring the chip out of low-power mode. */ - if (tp->chipset == CH_8139B) { - NETDRV_W8 (Config1, NETDRV_R8 (Config1) & ~(1<<4)); - NETDRV_W8 (Config4, NETDRV_R8 (Config4) & ~(1<<2)); - } else { - /* handle RTL8139A and RTL8139 cases */ - /* XXX from becker driver. is this right?? */ - NETDRV_W8 (Config1, 0); - } + /* */ #ifndef USE_IO_OPS /* sanity checks -- ensure PIO and MMIO registers agree */ @@ -709,19 +690,6 @@ assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig)); #endif /* !USE_IO_OPS */ - /* make sure chip thinks PIO and MMIO are enabled */ - tmp8 = NETDRV_R8 (Config1); - if ((tmp8 & Cfg1_PIO) == 0) { - printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); - rc = -EIO; - goto err_out_iounmap; - } - if ((tmp8 & Cfg1_MMIO) == 0) { - printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); - rc = -EIO; - goto err_out_iounmap; - } - /* identify chip attached to board */ tmp = NETDRV_R8 (ChipVersion); for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--) @@ -747,15 +715,10 @@ *dev_out = dev; return 0; -err_out_iounmap: - assert (ioaddr > 0); #ifndef USE_IO_OPS - iounmap (ioaddr); +err_out_free_res: + pci_release_regions (pdev); #endif /* !USE_IO_OPS */ -err_out_free_mmio: - release_mem_region (mmio_start, mmio_len); -err_out_free_pio: - release_region (pio_start, pio_len); err_out: unregister_netdev (dev); kfree (dev); @@ -828,7 +791,7 @@ tp->mmio_addr = ioaddr; tp->lock = SPIN_LOCK_UNLOCKED; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); tp->phys[0] = 32; @@ -879,14 +842,14 @@ static void __devexit netdrv_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct netdrv_private *np; DPRINTK ("ENTER\n"); assert (dev != NULL); - np = (struct netdrv_private *) (dev->priv); + np = dev->priv; assert (np != NULL); unregister_netdev (dev); @@ -895,10 +858,7 @@ iounmap (np->mmio_addr); #endif /* !USE_IO_OPS */ - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + pci_release_regions (pdev); #ifndef NETDRV_NDEBUG /* poison memory before freeing */ @@ -909,7 +869,7 @@ kfree (dev); - pdev->driver_data = NULL; + pci_set_drvdata (pdev, NULL); pci_power_off (pdev, -1); @@ -2117,7 +2077,7 @@ static void netdrv_suspend (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); struct netdrv_private *tp = (struct netdrv_private *) dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; @@ -2142,7 +2102,7 @@ static void netdrv_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); pci_power_on (pdev); netif_device_attach (dev); diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c --- v2.4.2/linux/drivers/net/pcmcia/3c574_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/3c574_cs.c Fri Mar 2 11:02:15 2001 @@ -1166,7 +1166,9 @@ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } else { DEBUG(1, "%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c --- v2.4.2/linux/drivers/net/pcmcia/3c589_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/3c589_cs.c Fri Mar 2 11:02:15 2001 @@ -4,7 +4,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - 3c589_cs.c 1.154 2000/09/30 17:39:04 + 3c589_cs.c 1.156 2001/02/07 00:19:41 The network driver code is based on Donald Becker's 3c589 code: @@ -117,7 +117,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"3c589_cs.c 1.154 2000/09/30 17:39:04 (David Hinds)"; +"3c589_cs.c 1.156 2001/02/07 00:19:41 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -993,8 +993,9 @@ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += pkt_len; } else { DEBUG(1, "%s: couldn't allocate a sk_buff of" " size %d.\n", dev->name, pkt_len); diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c --- v2.4.2/linux/drivers/net/pcmcia/fmvj18x_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/fmvj18x_cs.c Fri Mar 2 11:02:15 2001 @@ -1,5 +1,5 @@ /*====================================================================== - fmvj18x_cs.c,v 2.0 2000/10/01 03:13:53 root Exp + fmvj18x_cs.c 2.2 2001/01/07 A fmvj18x (and its compatibles) PCMCIA client driver @@ -19,7 +19,7 @@ Director, National Security Agency. This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. + of the GNU General Public License, incorporated herein by reference. The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of Excellence in Space Data and Information Sciences @@ -87,8 +87,7 @@ driver version infomation */ #ifdef PCMCIA_DEBUG -static char *version = - "fmvj18x_cs.c,v 2.0 2000/10/01 03:13:53 root Exp"; +static char *version = "fmvj18x_cs.c 2.2 2001/01/07"; #endif /*====================================================================*/ @@ -96,6 +95,7 @@ PCMCIA event handlers */ static void fmvj18x_config(dev_link_t *link); +static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id); static void fmvj18x_release(u_long arg); static int fmvj18x_event(event_t event, int priority, event_callback_args_t *args); @@ -103,7 +103,7 @@ static void fmvj18x_detach(dev_link_t *); /* - LAN controler(MBH86960A) specific routines + LAN controller(MBH86960A) specific routines */ static int fjn_config(struct net_device *dev, struct ifmap *map); static int fjn_open(struct net_device *dev); @@ -122,7 +122,9 @@ /* card type */ -typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN } cardtype_t; +typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN, + XXX10304 +} cardtype_t; #define MANFID_UNGERMANN 0x02c0 @@ -223,8 +225,8 @@ #define RECV_ALL 0x03 /* (RX_MODE) */ #define CONFIG0_DFL 0x5a /* 16bit bus, 4K x 2 Tx queues */ #define CONFIG0_DFL_1 0x5e /* 16bit bus, 8K x 2 Tx queues */ -#define CONFIG0_RST 0xda /* Data Link Controler off (CONFIG_0) */ -#define CONFIG0_RST_1 0xde /* Data Link Controler off (CONFIG_0) */ +#define CONFIG0_RST 0xda /* Data Link Controller off (CONFIG_0) */ +#define CONFIG0_RST_1 0xde /* Data Link Controller off (CONFIG_0) */ #define BANK_0 0xa0 /* bank 0 (CONFIG_1) */ #define BANK_1 0xa4 /* bank 1 (CONFIG_1) */ #define BANK_2 0xa8 /* bank 2 (CONFIG_1) */ @@ -235,8 +237,8 @@ #define MANU_MODE 0x03 /* Stop and skip packet on 16 col */ #define TDK_AUTO_MODE 0x47 /* Auto skip packet on 16 col detected */ #define TDK_MANU_MODE 0x43 /* Stop and skip packet on 16 col */ -#define INTR_OFF 0x0d /* LAN controler ignores interrupts */ -#define INTR_ON 0x1d /* LAN controler will catch interrupts */ +#define INTR_OFF 0x0d /* LAN controller ignores interrupts */ +#define INTR_ON 0x1d /* LAN controller will catch interrupts */ #define TX_TIMEOUT ((400*HZ)/1000) @@ -321,8 +323,10 @@ ether_setup(dev); dev->open = &fjn_open; dev->stop = &fjn_close; +#ifdef HAVE_TX_TIMEOUT dev->tx_timeout = fjn_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#endif /* Register with Card Services */ link->next = dev_list; @@ -438,6 +442,12 @@ switch (le16_to_cpu(buf[0])) { case MANFID_TDK: cardtype = TDK; + if (le16_to_cpu(buf[1]) == PRODID_TDK_CF010) { + cs_status_t status; + CardServices(GetStatus, handle, &status); + if (status.CardState & CS_EVENT_3VCARD) + link->conf.Vcc = 33; /* inserted in 3.3V slot */ + } break; case MANFID_CONTEC: cardtype = CONTEC; @@ -461,6 +471,15 @@ else buf[0] = 0xffff; switch (le16_to_cpu(buf[0])) { + case MANFID_FUJITSU: + if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10304) { + cardtype = XXX10304; /* MBH10304 with buggy CIS */ + link->conf.ConfigIndex = 0x20; + } else { + cardtype = MBH10302; + link->conf.ConfigIndex = 1; + } + break; case MANFID_UNGERMANN: cardtype = UNGERMANN; /* @@ -505,7 +524,7 @@ else outb(BANK_0, ioaddr + CONFIG_1); - /* Reset controler */ + /* Reset controller */ if( sram_config == 0 ) outb(CONFIG0_RST, ioaddr + CONFIG_0); else @@ -550,6 +569,19 @@ dev->dev_addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i); card_name = "Access/CARD"; break; + case XXX10304: + /* Read MACID from Buggy CIS */ + if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) { + printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net + address."); + unregister_netdev(dev); + goto failed; + } + for (i = 0 ; i < 6; i++) { + dev->dev_addr[i] = tuple.TupleData[i]; + } + card_name = "FMV-J182"; + break; case MBH10302: default: /* Read MACID from register */ @@ -580,7 +612,60 @@ fmvj18x_release((u_long)link); } /* fmvj18x_config */ - +/*====================================================================*/ + +static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id) +{ + win_req_t req; + memreq_t mem; + u_char *base; + int i, j; + + /* Allocate a small memory window */ + req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; + req.Base = 0; req.Size = 0; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + i = CardServices(RequestWindow, &link->win, &req); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestWindow, i); + return -1; + } + + base = ioremap(req.Base, req.Size); + mem.Page = 0; + mem.CardOffset = 0; + CardServices(MapMemPage, link->win, &mem); + + /* + * MBH10304 CISTPL_FUNCE_LAN_NODE_ID format + * 22 0d xx xx xx 04 06 yy yy yy yy yy yy ff + * 'xx' is garbage. + * 'yy' is MAC address. + */ + for (i = 0; i < 0x200; i++) { + if (readb(base+i*2) == 0x22) { + if (readb(base+(i-1)*2) == 0xff + && readb(base+(i+5)*2) == 0x04 + && readb(base+(i+6)*2) == 0x06 + && readb(base+(i+13)*2) == 0xff) + break; + } + } + + if (i != 0x200) { + for (j = 0 ; j < 6; j++,i++) { + node_id[j] = readb(base+(i+7)*2); + } + } + + iounmap(base); + j = CardServices(ReleaseWindow, link->win); + if (j != CS_SUCCESS) + cs_error(link->handle, ReleaseWindow, j); + return (i != 0x200) ? 0 : -1; + +} /* fmvj18x_get_hwinfo */ /*====================================================================*/ static void fmvj18x_release(u_long arg) @@ -775,7 +860,7 @@ lp->sent = 0; lp->open_time = jiffies; sti(); - netif_start_queue(dev); + netif_wake_queue(dev); } static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -923,7 +1008,7 @@ outb(D_TX_INTR, ioaddr + TX_INTR); outb(D_RX_INTR, ioaddr + RX_INTR); - /* Turn on interrupts from LAN card controler */ + /* Turn on interrupts from LAN card controller */ if( lp->cardtype != TDK ) outb(INTR_ON, ioaddr + LAN_CTRL); } /* fjn_reset */ @@ -995,8 +1080,9 @@ #endif netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += pkt_len; } if (--boguscount <= 0) break; diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/i82593.h linux/drivers/net/pcmcia/i82593.h --- v2.4.2/linux/drivers/net/pcmcia/i82593.h Wed Oct 20 21:33:12 1999 +++ linux/drivers/net/pcmcia/i82593.h Fri Mar 2 11:02:15 2001 @@ -221,4 +221,4 @@ #define I82593_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ -#endif _I82593_H +#endif /* _I82593_H */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c --- v2.4.2/linux/drivers/net/pcmcia/netwave_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/netwave_cs.c Fri Mar 2 11:02:15 2001 @@ -1463,16 +1463,16 @@ skb->protocol = eth_type_trans(skb,dev); /* Queue packet for network layer */ netif_rx(skb); - + + dev->last_rx = jiffies; + priv->stats.rx_packets++; + priv->stats.rx_bytes += rcvLen; + /* Got the packet, tell the adapter to skip it */ wait_WOC(iobase); writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0); writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); DEBUG(3, "Packet reception ok\n"); - - priv->stats.rx_packets++; - - priv->stats.rx_bytes += skb->len; } return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c --- v2.4.2/linux/drivers/net/pcmcia/nmclan_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/nmclan_cs.c Fri Mar 2 11:02:15 2001 @@ -1288,9 +1288,9 @@ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ - + dev->last_rx = jiffies; lp->linux_stats.rx_packets++; - lp->linux_stats.rx_bytes += skb->len; + lp->linux_stats.rx_bytes += pkt_len; outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ continue; } else { diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c --- v2.4.2/linux/drivers/net/pcmcia/pcnet_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/pcnet_cs.c Fri Mar 2 11:02:15 2001 @@ -11,7 +11,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - pcnet_cs.c 1.126 2000/10/02 20:38:23 + pcnet_cs.c 1.132 2001/02/09 03:13:29 The network driver code is based on Donald Becker's NE2000 code: @@ -72,7 +72,7 @@ MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"pcnet_cs.c 1.126 2000/10/02 20:38:23 (David Hinds)"; +"pcnet_cs.c 1.132 2001/02/09 03:13:29 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -137,7 +137,7 @@ #define HAS_IBM_MISC 0x08 #define IS_DL10019 0x10 #define IS_DL10022 0x20 -#define IS_AX88190 0x40 +#define HAS_MII 0x40 #define USE_SHMEM 0x80 /* autodetected */ static hw_info_t hw_info[] = { @@ -204,8 +204,8 @@ #define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t)) static hw_info_t default_info = { 0, 0, 0, 0, 0 }; -static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019 }; -static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10019|IS_DL10022 }; +static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII }; +static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII }; typedef struct pcnet_dev_t { struct net_device dev; /* so &dev == &pcnet_dev_t */ @@ -507,10 +507,10 @@ if (link->conf.ConfigBase != 0x03c0) return NULL; - outb_p(0x01, EN0_DCFG); /* Set word-wide access. */ - outb_p(0x00, EN0_RSARLO); /* DMA starting at 0x0400. */ - outb_p(0x04, EN0_RSARHI); - outb_p(E8390_RREAD+E8390_START, E8390_CMD); + outb_p(0x01, ioaddr + EN0_DCFG); /* Set word-wide access. */ + outb_p(0x00, ioaddr + EN0_RSARLO); /* DMA starting at 0x0400. */ + outb_p(0x04, ioaddr + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, ioaddr + E8390_CMD); for (i = 0; i < 6; i += 2) { j = inw(ioaddr + PCNET_DATAPORT); @@ -718,6 +718,7 @@ info->flags |= (delay_output) ? DELAY_OUTPUT : 0; if ((manfid == MANFID_SOCKET) && ((prodid == PRODID_SOCKET_LPE) || + (prodid == PRODID_SOCKET_LPE_CF) || (prodid == PRODID_SOCKET_EIO))) info->flags &= ~USE_BIG_BUF; if (!use_big_buf) @@ -746,13 +747,11 @@ link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; - if (info->flags & IS_DL10019) { + if (info->flags & (IS_DL10019|IS_DL10022)) { dev->do_ioctl = &do_ioctl; printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ", dev->name, ((info->flags & IS_DL10022) ? 22 : 19), inb(dev->base_addr + 0x1a)); - } else if (info->flags & IS_AX88190) { - printk(KERN_INFO "%s: NE2000 (AX88190): ", dev->name); } else printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name); printk("io %#3lx, irq %d,", dev->base_addr, dev->irq); @@ -1024,6 +1023,8 @@ ei_status.txing = ei_status.dmaing = 0; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD); + outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET); for (i = 0; i < 100; i++) { @@ -1092,10 +1093,17 @@ return; } - if (!(info->flags & IS_DL10019)) + if (!(info->flags & HAS_MII)) + goto reschedule; + + link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1); + if (!link || (link == 0xffff)) { + printk(KERN_INFO "%s: MII is missing!\n", dev->name); + info->flags &= ~HAS_MII; goto reschedule; + } - link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1) & 0x0004; + link &= 0x0004; if (link != info->link_status) { u_short p = mdio_read(dev->base_addr + DLINK_GPIO, 0, 5); printk(KERN_INFO "%s: %s link beat\n", dev->name, diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c --- v2.4.2/linux/drivers/net/pcmcia/ray_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/ray_cs.c Fri Mar 2 11:02:15 2001 @@ -2219,9 +2219,9 @@ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - + dev->last_rx = jiffies; local->stats.rx_packets++; - local->stats.rx_bytes += skb->len; + local->stats.rx_bytes += total_len; /* Gather signal strength per address */ #ifdef WIRELESS_SPY diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c --- v2.4.2/linux/drivers/net/pcmcia/smc91c92_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/smc91c92_cs.c Fri Mar 2 11:02:15 2001 @@ -8,7 +8,7 @@ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - smc91c92_cs.c 1.104 2000/08/31 21:25:13 + smc91c92_cs.c 1.106 2001/02/07 00:19:58 This driver contains code written by Donald Becker (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au), @@ -231,7 +231,7 @@ RxEnable = 0x0100, RxStripCRC = 0x0200}; #define RCR_SOFTRESET 0x8000 /* resets the chip */ #define RCR_STRIP_CRC 0x200 /* strips CRC */ -#define RCR_ENABLE 0x100 /* IFF this is set, we can recieve packets */ +#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */ #define RCR_ALMUL 0x4 /* receive all multicast packets */ #define RCR_PROMISC 0x2 /* enable promiscuous mode */ @@ -1617,8 +1617,9 @@ skb->dev = dev; netif_rx(skb); + dev->last_rx = jiffies; smc->stats.rx_packets++; - smc->stats.rx_bytes += skb->len; + smc->stats.rx_bytes += packet_length; if (rx_status & RS_MULTICAST) smc->stats.multicast++; } else { diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/wavelan.h linux/drivers/net/pcmcia/wavelan.h --- v2.4.2/linux/drivers/net/pcmcia/wavelan.h Wed Oct 20 21:33:12 1999 +++ linux/drivers/net/pcmcia/wavelan.h Fri Mar 2 11:02:15 2001 @@ -7,11 +7,11 @@ * Original copyright follow. See wavelan_cs.h for details. * * This file contain the declarations of the Wavelan hardware. Note that - * the Pcmcia Wavelan include a i82593 controler (see definitions in + * the Pcmcia Wavelan include a i82593 controller (see definitions in * file i82593.h). * * The main difference between the pcmcia hardware and the ISA one is - * the Ethernet Controler (i82593 instead of i82586). The i82593 allow + * the Ethernet Controller (i82593 instead of i82586). The i82593 allow * only one send buffer. The PSA (Parameter Storage Area : EEprom for * permanent storage of various info) is memory mapped, but not the * MMI (Modem Management Interface). diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c --- v2.4.2/linux/drivers/net/pcmcia/wavelan_cs.c Thu Jan 4 12:50:12 2001 +++ linux/drivers/net/pcmcia/wavelan_cs.c Fri Mar 2 11:02:15 2001 @@ -37,6 +37,12 @@ * Apr 2 '98 made changes to bring the i82593 control/int handling in line * with offical specs... * + * Changes: + * Arnaldo Carvalho de Melo - 08/08/2000 + * - reorganize kmallocs in wavelan_attach, checking all for failure + * and releasing the previous allocations if one fails + * + * **************************************************************************** * Copyright 1995 * Anthony D. Joseph @@ -512,7 +518,7 @@ /* Do not remove this unless you have a good reason */ printk(KERN_NOTICE "%s: Warning, you have enabled roaming on" " device %s !\n", dev->name, dev->name); - printk(KERN_NOTICE "Roaming is currently an experimental unsuported feature" + printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature" " of the Wavelan driver.\n"); printk(KERN_NOTICE "It may work, but may also make the driver behave in" " erratic ways or crash.\n"); @@ -820,7 +826,7 @@ /************************ I82593 SUBROUTINES *************************/ /* - * Usefull subroutines to manage the Ethernet controler + * Useful subroutines to manage the Ethernet controller */ /*------------------------------------------------------------------*/ @@ -853,7 +859,7 @@ /* We are waiting for command completion */ wv_wait_completed = TRUE; - /* Issue the command to the controler */ + /* Issue the command to the controller */ outb(cmd, LCCR(base)); /* If we don't have to check the result of the command */ @@ -1774,7 +1780,7 @@ #if WIRELESS_EXT > 7 const int BAND_NUM = 10; /* Number of bands */ int c = 0; /* Channel number */ -#endif WIRELESS_EXT +#endif /* WIRELESS_EXT */ /* Read the frequency table */ fee_read(base, 0x71 /* frequency table */, @@ -1792,7 +1798,7 @@ (c < BAND_NUM)) c++; list[i].i = c; /* Set the list index */ -#endif WIRELESS_EXT +#endif /* WIRELESS_EXT */ /* put in the list */ list[i].m = (((freq + 24) * 5) + 24000L) * 10000; @@ -2727,8 +2733,9 @@ netif_rx(skb); /* Keep stats up to date */ + dev->last_rx = jiffies; lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += sksize; #ifdef DEBUG_RX_TRACE printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); @@ -2949,7 +2956,7 @@ /*------------------------------------------------------------------*/ /* * This routine is called when we want to send a packet (NET3 callback) - * In this routine, we check if the the harware is ready to accept + * In this routine, we check if the hardware is ready to accept * the packet. We also prevent reentrance. Then, we call the function * to send the packet... */ @@ -2974,7 +2981,7 @@ * In other words, prevent reentering this routine. */ if (1) { - /* If somebody has asked to reconfigure the controler, we can do it now */ + /* If somebody has asked to reconfigure the controller, we can do it now */ if (lp->reconfig_82593) { lp->reconfig_82593 = FALSE; wv_82593_config (dev); @@ -3332,7 +3339,7 @@ /*------------------------------------------------------------------*/ /* - * This routine does a standard config of the WaveLAN controler (i82593). + * This routine does a standard config of the WaveLAN controller (i82593). * In the ISA driver, this is integrated in wavelan_hardware_reset() * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit()) */ @@ -3596,7 +3603,7 @@ hacr_write_slow(base, HACR_RESET); hacr_write(base, HACR_DEFAULT); - /* Check if the the module has been powered up... */ + /* Check if the module has been powered up... */ if(hasr_read(base) & HASR_NO_CLK) { #ifdef DEBUG_CONFIG_ERRORS @@ -3614,7 +3621,7 @@ outb(OP0_RESET, LCCR(base)); mdelay(1); /* A bit crude ! */ - /* Initialize the LAN controler */ + /* Initialize the LAN controller */ if((wv_82593_config(dev) == FALSE) || (wv_diag(dev) == FALSE)) { @@ -3918,7 +3925,7 @@ * This function is the interrupt handler for the WaveLAN card. This * routine will be called whenever: * 1. A packet is received. - * 2. A packet has successfully been transfered and the unit is + * 2. A packet has successfully been transferred and the unit is * ready to transmit another packet. * 3. A command has completed execution. */ @@ -4285,7 +4292,7 @@ /* Power up (power up time is 250us) */ hacr_write(base, HACR_DEFAULT); - /* Check if the the module has been powered up... */ + /* Check if the module has been powered up... */ if(hasr_read(base) & HASR_NO_CLK) { #ifdef DEBUG_CONFIG_ERRORS @@ -4424,7 +4431,24 @@ /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) + return NULL; + + /* Allocate the generic data structure */ + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + if (!dev) + goto fail_alloc_dev; + + /* Allocate the wavelan-specific data structure. */ + lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); + if (!lp) + goto fail_alloc_dev_priv; + + memset(lp, 0, sizeof(net_local)); memset(link, 0, sizeof(struct dev_link_t)); + memset(dev, 0, sizeof(struct net_device)); + + dev->priv = lp; /* Unused for the Wavelan */ link->release.function = &wv_pcmcia_release; @@ -4454,15 +4478,8 @@ link->next = dev_list; dev_list = link; - /* Allocate the generic data structure */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0x00, sizeof(struct net_device)); link->priv = link->irq.Instance = dev; - /* Allocate the wavelan-specific data structure. */ - dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL); - memset(lp, 0x00, sizeof(net_local)); - /* Init specific data */ wv_wait_completed = 0; lp->status = FALSE; @@ -4531,6 +4548,12 @@ #endif return link; + +fail_alloc_dev_priv: + kfree(dev); +fail_alloc_dev: + kfree(link); + return NULL; } /*------------------------------------------------------------------*/ diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h --- v2.4.2/linux/drivers/net/pcmcia/wavelan_cs.h Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/wavelan_cs.h Fri Mar 2 11:02:15 2001 @@ -96,7 +96,7 @@ * * wavelan.h : Description of the hardware interface & structs * - * i82593.h : Description if the Ethernet controler + * i82593.h : Description if the Ethernet controller */ /* --------------------------- HISTORY --------------------------- */ @@ -225,7 +225,7 @@ * - wavelan_set_multicast_list : avoid reset * - add wireless extensions (ioctl & get_wireless_stats) * get/set nwid/frequency on fly, info for /proc/net/wireless - * - Supress useless stuff from lp (net_local), but add link + * - Suppress useless stuff from lp (net_local), but add link * - More inlines * - Lot of others minor details & cleanups * @@ -315,7 +315,7 @@ * o Rename wavelan_release to wv_pcmcia_release & move up * o move unregister_netdev to wavelan_detach() * o wavelan_release() no longer call wavelan_detach() - * o Supress "release" timer + * o Suppress "release" timer * o Other cleanups & fixes * - New MAC address in the probe * - Reorg PSA_CRC code (endian neutral & cleaner) @@ -430,14 +430,14 @@ #undef DEBUG_CONFIG_INFO /* What's going on... */ #define DEBUG_CONFIG_ERRORS /* Errors on configuration */ #undef DEBUG_TX_TRACE /* Transmission calls */ -#undef DEBUG_TX_INFO /* Header of the transmited packet */ +#undef DEBUG_TX_INFO /* Header of the transmitted packet */ #undef DEBUG_TX_FAIL /* Normal failure conditions */ #define DEBUG_TX_ERROR /* Unexpected conditions */ #undef DEBUG_RX_TRACE /* Transmission calls */ -#undef DEBUG_RX_INFO /* Header of the transmited packet */ +#undef DEBUG_RX_INFO /* Header of the transmitted packet */ #undef DEBUG_RX_FAIL /* Normal failure conditions */ #define DEBUG_RX_ERROR /* Unexpected conditions */ -#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen */ +#undef DEBUG_PACKET_DUMP /* Dump packet on the screen */ #undef DEBUG_IOCTL_TRACE /* Misc call by Linux */ #undef DEBUG_IOCTL_INFO /* Various debug info */ #define DEBUG_IOCTL_ERROR /* What's going wrong */ @@ -557,7 +557,7 @@ en_stats stats; /* Ethernet interface statistics */ int nresets; /* Number of hw resets */ u_char configured; /* If it is configured */ - u_char reconfig_82593; /* Need to reconfigure the controler */ + u_char reconfig_82593; /* Need to reconfigure the controller */ u_char promiscuous; /* Promiscuous mode */ u_char allmulticast; /* All Multicast mode */ int mc_count; /* Number of multicast addresses */ @@ -669,7 +669,7 @@ char *, int); static inline void - wv_82593_reconfig(device *); /* Reconfigure the controler */ + wv_82593_reconfig(device *); /* Reconfigure the controller */ /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */ static inline void wv_init_info(device *); /* display startup info */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c --- v2.4.2/linux/drivers/net/pcmcia/xirc2ps_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/xirc2ps_cs.c Fri Mar 2 11:02:15 2001 @@ -125,7 +125,7 @@ enum xirc_isr { TxBufOvr = 0x01, /* TX Buffer Overflow */ PktTxed = 0x02, /* Packet Transmitted */ - MACIntr = 0x04, /* MAC Interrupt occured */ + MACIntr = 0x04, /* MAC Interrupt occurred */ TxResGrant = 0x08, /* Tx Reservation Granted */ RxFullPkt = 0x20, /* Rx Full Packet */ RxPktRej = 0x40, /* Rx Packet Rejected */ @@ -382,6 +382,7 @@ static void do_powerdown(struct net_device *dev); static int do_stop(struct net_device *dev); + /*=============== Helper functions =========================*/ static void flush_stale_links(void) @@ -1350,7 +1351,6 @@ * packets */ lp->stats.rx_dropped++; DEBUG(2, "%s: RX drop, too much done\n", dev->name); - PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ } else if (rsr & PktRxOk) { struct sk_buff *skb; @@ -1420,13 +1420,13 @@ skb->protocol = eth_type_trans(skb, dev); skb->dev = dev; netif_rx(skb); + dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pktlen; if (!(rsr & PhyPkt)) lp->stats.multicast++; } - PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ - } else { + } else { /* bad packet */ DEBUG(5, "rsr=%#02x\n", rsr); } if (rsr & PktTooLong) { @@ -1441,6 +1441,9 @@ lp->stats.rx_fifo_errors++; /* okay ? */ DEBUG(3, "%s: Alignment error\n", dev->name); } + + /* clear the received/dropped/error packet */ + PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */ /* get the new ethernet status */ eth_status = GetByte(XIRCREG_ESR); diff -u --recursive --new-file v2.4.2/linux/drivers/net/pppoe.c linux/drivers/net/pppoe.c --- v2.4.2/linux/drivers/net/pppoe.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pppoe.c Tue Mar 6 19:44:35 2001 @@ -737,7 +737,7 @@ err = 0; break; - default: + default:; }; return err; diff -u --recursive --new-file v2.4.2/linux/drivers/net/rclanmtl.h linux/drivers/net/rclanmtl.h --- v2.4.2/linux/drivers/net/rclanmtl.h Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/rclanmtl.h Tue Mar 6 19:28:34 2001 @@ -97,7 +97,7 @@ typedef void (*PFNTXCALLBACK)(U32 Status, U16 PcktCount, PU32 BufferContext, - U16 AdaterID); + struct net_device *); /* ** type PFNRXCALLBACK @@ -445,7 +445,7 @@ /* ** Disable and Enable I2O interrupts. I2O interrupts are enabled at Init time ** but can be disabled and re-enabled through these two function calls. - ** Packets will still be put into any posted recieved buffers and packets will + ** Packets will still be put into any posted received buffers and packets will ** be sent through RCI2OSendPacket() functions. Disabling I2O interrupts ** will prevent hardware interrupt to host even though the outbound I2O msg ** queue is not emtpy. diff -u --recursive --new-file v2.4.2/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c --- v2.4.2/linux/drivers/net/rcpci45.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/rcpci45.c Tue Mar 6 19:28:34 2001 @@ -119,7 +119,7 @@ static void __exit rcpci45_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); PDPA pDpa = dev->priv; if (!dev) { @@ -134,10 +134,12 @@ unregister_netdev(dev); free_irq(dev->irq, dev); iounmap((void *)dev->base_addr); + pci_release_regions(pdev); kfree(pDpa->PLanApiPA); kfree(pDpa->pPab); kfree(pDpa); kfree(dev); + pci_set_drvdata(pdev, NULL); } static int RCinit(struct net_device *dev) @@ -156,12 +158,10 @@ { unsigned long *vaddr; PDPA pDpa; - int error = -ENOMEM; + int error; static int card_idx = -1; struct net_device *dev; - unsigned long pci_start = pci_resource_start(pdev,0); - unsigned long pci_len = pci_resource_len(pdev,0); - + unsigned long pci_start, pci_len; card_idx++; @@ -177,10 +177,20 @@ dev = init_etherdev(NULL, sizeof(*pDpa)); if (!dev) { printk(KERN_ERR "(rcpci45 driver:) unable to allocate in init_etherdev\n"); + error = -ENOMEM; + goto err_out; + } + + error = pci_enable_device(pdev); + if (error) { + printk(KERN_ERR "(rcpci45 driver:) %d: unable to enable pci device, aborting\n",card_idx); goto err_out; } + error = -ENOMEM; + pci_start = pci_resource_start(pdev,0); + pci_len = pci_resource_len(pdev,0); - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); pDpa = dev->priv; pDpa->id = card_idx; @@ -188,6 +198,7 @@ if (!pci_start || !(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { printk(KERN_ERR "(rcpci45 driver:) No PCI memory resources! Aborting.\n"); + error = -EBUSY; goto err_out_free_dev; } @@ -214,20 +225,14 @@ * I/O read/write. Thus, we need to map it to some virtual address * area in order to access the registers as normal memory. */ - if (request_mem_region(pci_start, pci_len, dev->name) == NULL) { - printk(KERN_ERR "(rcpci45 driver:) %d: resource 0x%lx @ 0x%lx busy, aborting\n",card_idx, pci_start, pci_len); - goto err_out_free_msgbuf; - } - - if (pci_enable_device(pdev)) { - printk(KERN_ERR "(rcpci45 driver:) %d: unable to enable pci device, aborting\n",card_idx); - goto err_out_free_msgbuf; - } + error = pci_request_regions(pdev, dev->name); + if (error) + goto err_out_free_msgbuf; vaddr = (ulong *) ioremap (pci_start, pci_len); if (!vaddr) { printk(KERN_ERR "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", pci_start, pci_start+pci_len); - goto err_out_free_msgbuf; + goto err_out_free_region; } dprintk("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", @@ -239,13 +244,14 @@ return 0; /* success */ - + err_out_free_region: + pci_release_regions(pdev); err_out_free_msgbuf: kfree(pDpa->msgbuf); err_out_free_dev: + unregister_netdev(dev); kfree(dev); err_out: - unregister_netdev(dev); card_idx--; return error; } @@ -384,7 +390,7 @@ /* * we'll get the context when the adapter interrupts us to tell us that - * the transmision is done. At that time, we can free skb. + * the transmission is done. At that time, we can free skb. */ ptcb->b.context = (U32)skb; ptcb->b.scount = 1; diff -u --recursive --new-file v2.4.2/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c --- v2.4.2/linux/drivers/net/rtl8129.c Sun Sep 17 09:41:29 2000 +++ linux/drivers/net/rtl8129.c Wed Dec 31 16:00:00 1969 @@ -1,1483 +0,0 @@ -/* rtl8129.c: A RealTek RTL8129 Fast Ethernet driver for Linux. */ -/* - Written 1997-1999 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - All other rights reserved. - - This driver is for boards based on the RTL8129 PCI ethernet chip. - - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - - Support and updates available at - http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html - - Twister-tuning table provided by Kinston . -*/ - -static const char *version = -"rtl8129.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n"; - -/* A few user-configurable values. */ -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; -#define rtl8129_debug debug -static int rtl8129_debug = 1; - -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). - The RTL chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; - -/* Used to pass the full-duplex flag, etc. */ -#define MAX_UNITS 8 /* More are supported, limit only on options */ -static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* Size of the in-memory receive ring. */ -#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K */ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) -/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ -#define TX_BUF_SIZE 1536 - -/* PCI Tuning Parameters - Threshold is bytes transferred to chip before transmission starts. */ -#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ - -/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. */ -#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ -#define TX_DMA_BURST 4 /* Calculate as 16< -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include - -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - -#define RUN_AT(x) (jiffies + (x)) - -#include - -#if LINUX_VERSION_CODE < 0x20123 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif -#if LINUX_VERSION_CODE <= 0x20139 -#define net_device_stats enet_statistics -#else -#define NETSTATS_VER2 -#endif -#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS) -/* Grrrr, the PCI code changed, but did not consider CardBus... */ -#include -#define PCI_SUPPORT_VER1 -#else -#define PCI_SUPPORT_VER2 -#endif - -/* The I/O extent. */ -#define RTL8129_TOTAL_SIZE 0x80 - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the RealTek RTL8129, the RealTek Fast -Ethernet controllers for PCI. This chip is used on a few clone boards. - - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS will assign the -PCI INTA signal to a (preferably otherwise unused) system IRQ line. -Note: Kernel versions earlier than 1.3.73 do not support shared PCI -interrupt lines. - -III. Driver operation - -IIIa. Rx Ring buffers - -The receive unit uses a single linear ring buffer rather than the more -common (and more efficient) descriptor-based architecture. Incoming frames -are sequentially stored into the Rx region, and the host copies them into -skbuffs. - -Comment: While it is theoretically possible to process many frames in place, -any delay in Rx processing would cause us to drop frames. More importantly, -the Linux protocol stack is not designed to operate in this manner. - -IIIb. Tx operation - -The RTL8129 uses a fixed set of four Tx descriptors in register space. -In a stunningly bad design choice, Tx frames must be 32 bit aligned. Linux -aligns the IP header on word boundaries, and 14 byte ethernet header means -that almost all frames will need to be copied to an alignment buffer. - -IVb. References - -http://www.realtek.com.tw/cn/cn.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html - -IVc. Errata - -*/ - - -/* This table drives the PCI probe routines. It's mostly boilerplate in all - of the drivers, and will likely be provided by some future kernel. - Note the matching code -- the first table entry matchs all 56** cards but - second only the 1234 card. -*/ -enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, -}; -struct pci_id_info { - const char *name; - u16 vendor_id, device_id, device_id_mask, flags; - int io_size; - struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt); -}; - -static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus, - int pci_devfn, long ioaddr, - int irq, int chp_idx, int fnd_cnt); - -static struct pci_id_info pci_tbl[] = -{{ "RealTek RTL8129 Fast Ethernet", - 0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, -#ifdef USE_8139_SUPPORT_ALSO - { "RealTek RTL8139 Fast Ethernet", - 0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "SMC1211TX EZCard 10/100 (RealTek RTL8139)", - 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, - { "Accton MPX5030 (RealTek RTL8139)", - 0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1}, -#endif - {0,}, /* 0 terminated list. */ -}; - -/* The capability table matches the chip table above. */ -enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04}; -static int rtl_cap_tbl[] = { - HAS_MII_XCVR, HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG, -}; - - -/* The rest of these values should never change. */ -#define NUM_TX_DESC 4 /* Number of Tx descriptor registers. */ - -/* Symbolic offsets to registers. */ -enum RTL8129_registers { - MAC0=0, /* Ethernet hardware address. */ - MAR0=8, /* Multicast filter. */ - TxStatus0=0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0=0x20, /* Tx descriptors (also four 32bit). */ - RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36, - ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A, - IntrMask=0x3C, IntrStatus=0x3E, - TxConfig=0x40, RxConfig=0x44, - Timer=0x48, /* A general-purpose counter. */ - RxMissed=0x4C, /* 24 bits valid, write clears. */ - Cfg9346=0x50, Config0=0x51, Config1=0x52, - FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B, - MultiIntr=0x5C, TxSummary=0x60, - MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, - NWayExpansion=0x6A, - /* Undocumented registers, but required for proper operation. */ - FIFOTMS=0x70, /* FIFO Test Mode Select */ - CSCR=0x74, /* Chip Status and Configuration Register. */ - PARA78=0x78, PARA7c=0x7c, /* Magic transceiver parameter register. */ -}; - -enum ChipCmdBits { - CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, }; - -/* Interrupt register bits, using my own meaningful names. */ -enum IntrStatusBits { - PCIErr=0x8000, PCSTimeout=0x4000, - RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10, - TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01, -}; -enum TxStatusBits { - TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000, - TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000, -}; -enum RxStatusBits { - RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000, - RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004, - RxBadAlign=0x0002, RxStatusOK=0x0001, -}; - -/* Twister tuning parameters from RealTek. - Completely undocumented, but required to tune bad links. */ -enum CSCRBits { - CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800, - CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0, - CSCR_LinkDownCmd=0x0f3c0, -}; -static const unsigned long param[4][4]={ - {0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43}, - {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, - {0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83}, - {0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83} -}; - -struct ring_info { - struct sk_buff *skb; - dma_addr_t mapping; -}; - -struct rtl8129_private { - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct net_device *next_module; - struct pci_dev *pdev; - int chip_id; - int chip_revision; - unsigned char pci_bus, pci_devfn; - struct net_device_stats stats; - struct timer_list timer; /* Media selection timer. */ - unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */ - unsigned int cur_tx, dirty_tx, tx_flag; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct ring_info tx_info[NUM_TX_DESC]; - unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ - unsigned char *rx_ring; - unsigned char *tx_bufs; /* Tx bounce buffer region. */ - dma_addr_t rx_ring_dma; - dma_addr_t tx_bufs_dma; - char phys[4]; /* MII device addresses. */ - char twistie, twist_cnt; /* Twister tune state. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int duplex_lock:1; - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ - unsigned int medialock:1; /* Don't sense media type. */ - unsigned int mediasense:1; /* Media sensing in progress. */ -}; - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("RealTek RTL8129 Fast Ethernet driver"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(multicast_filter_limit, "i"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(debug, "i"); - -static int rtl8129_open(struct net_device *dev); -static int read_eeprom(long ioaddr, int location); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int val); -static void rtl8129_timer(unsigned long data); -static void rtl8129_tx_timeout(struct net_device *dev); -static void rtl8129_init_ring(struct net_device *dev); -static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int rtl8129_rx(struct net_device *dev); -static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int rtl8129_close(struct net_device *dev); -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *rtl8129_get_stats(struct net_device *dev); -static inline u32 ether_crc(int length, unsigned char *data); -static void set_rx_mode(struct net_device *dev); - - -/* A list of all installed RTL8129 devices, for removing the driver module. */ -static struct net_device *root_rtl8129_dev = NULL; - -/* Ideally we would detect all network cards in slot order. That would - be best done a central PCI probe dispatch, which wouldn't work - well when dynamically adding drivers. So instead we detect just the - Rtl81*9 cards in slot order. */ - -static int __init rtl8129_probe(void) -{ - int cards_found = 0; - int pci_index = 0; - unsigned char pci_bus, pci_device_fn; - struct net_device *dev; - - if ( ! pcibios_present()) - return -ENODEV; - - for (; pci_index < 0xff; pci_index++) { - struct pci_dev *pdev; - u16 vendor, device, pci_command, new_command; - int chip_idx, irq; - long ioaddr; - - if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index, - &pci_bus, &pci_device_fn) - != PCIBIOS_SUCCESSFUL) - break; - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_DEVICE_ID, &device); - - for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) - if (vendor == pci_tbl[chip_idx].vendor_id - && (device & pci_tbl[chip_idx].device_id_mask) == - pci_tbl[chip_idx].device_id) - break; - if (pci_tbl[chip_idx].vendor_id == 0) /* Compiled out! */ - continue; - - pdev = pci_find_slot(pci_bus, pci_device_fn); - - ioaddr = pci_resource_start(pdev, 0); - irq = pdev->irq; - - if (pci_enable_device(pdev)) - continue; - - if ((pci_tbl[chip_idx].flags & PCI_USES_IO) && - check_region(ioaddr, pci_tbl[chip_idx].io_size)) - continue; - - /* Activate the card: fix for brain-damaged Win98 BIOSes. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - new_command = pci_command | (pci_tbl[chip_idx].flags & 7); - if (pci_command != new_command) { - printk(KERN_INFO " The PCI BIOS has not enabled the" - " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", - pci_bus, pci_device_fn, pci_command, new_command); - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, new_command); - } - - dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found); - - if (dev && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) { - u8 pci_latency; - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 32) { - printk(KERN_NOTICE " PCI latency timer (CFLT) is " - "unreasonably low at %d. Setting to 64 clocks.\n", - pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 64); - } - } - dev = 0; - cards_found++; - } - - return cards_found ? 0 : -ENODEV; -} - -static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus, - int pci_devfn, long ioaddr, - int irq, int chip_idx, int found_cnt) -{ - static int did_version = 0; /* Already printed version info. */ - struct rtl8129_private *tp; - int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0; - struct net_device *dev; - - if (rtl8129_debug > 0 && did_version++ == 0) - printk(KERN_INFO "%s", version); - - dev = init_etherdev(NULL, 0); - if (dev == NULL) - goto out; - - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", - dev->name, pci_tbl[chip_idx].name, ioaddr, irq); - - /* Bring the chip out of low-power mode. */ - outb(0x00, ioaddr + Config1); - - if (read_eeprom(ioaddr, 0) != 0xffff) { - for (i = 0; i < 3; i++) { - ((u16 *)(dev->dev_addr))[i] = - le16_to_cpu(read_eeprom(ioaddr, i + 7)); - } - } else { - for (i = 0; i < 6; i++) - dev->dev_addr[i] = inb(ioaddr + MAC0 + i); - } - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); - - /* We do a request_region() to register /proc/ioports info. */ - if (!request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name)) - goto out_free_dev; - - dev->base_addr = ioaddr; - dev->irq = irq; - - /* Some data structures must be quadword aligned. */ - tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); - if (tp == NULL) - goto out_release_region; - - memset(tp, 0, sizeof(*tp)); - dev->priv = tp; - - tp->next_module = root_rtl8129_dev; - root_rtl8129_dev = dev; - - tp->pdev = pdev; - tp->chip_id = chip_idx; - tp->pci_bus = pci_bus; - tp->pci_devfn = pci_devfn; - - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, but - takes too much time. */ - if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) { - int phy, phy_idx; - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); - phy++) { - int mii_status = mdio_read(dev, phy, 1); - if (mii_status != 0xffff && mii_status != 0x0000) { - tp->phys[phy_idx++] = phy; - printk(KERN_INFO "%s: MII transceiver found at address %d.\n", - dev->name, phy); - } - } - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM " - "transceiver.\n", - dev->name); - tp->phys[0] = -1; - } - } else - tp->phys[0] = 32; - - /* Put the chip into low-power mode. */ - outb(0xC0, ioaddr + Cfg9346); - outb(0x03, ioaddr + Config1); - outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ - - /* The lower four bits are the media type. */ - if (option > 0) { - tp->full_duplex = (option & 0x200) ? 1 : 0; - tp->default_port = option & 15; - if (tp->default_port) - tp->medialock = 1; - } - - if (found_cnt < MAX_UNITS && full_duplex[found_cnt] > 0) - tp->full_duplex = full_duplex[found_cnt]; - - if (tp->full_duplex) { - printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); - mdio_write(dev, tp->phys[0], 4, 0x141); - tp->duplex_lock = 1; - } - - /* The Rtl8129-specific entries in the device structure. */ - dev->open = &rtl8129_open; - dev->hard_start_xmit = &rtl8129_start_xmit; - dev->tx_timeout = &rtl8129_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = &rtl8129_close; - dev->get_stats = &rtl8129_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; - return dev; - -out_release_region: - release_region(ioaddr, pci_tbl[chip_idx].io_size); -out_free_dev: - unregister_netdev(dev); - kfree(dev); -out: - return NULL; -} - -/* Serial EEPROM section. */ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ -#define EE_CS 0x08 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */ -#define EE_WRITE_0 0x00 -#define EE_WRITE_1 0x02 -#define EE_DATA_READ 0x01 /* EEPROM chip data out. */ -#define EE_ENB (0x80 | EE_CS) - -/* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. - */ - -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ_CMD (6 << 6) -#define EE_ERASE_CMD (7 << 6) - -static int read_eeprom(long ioaddr, int location) -{ - int i; - unsigned retval = 0; - long ee_addr = ioaddr + Cfg9346; - int read_cmd = location | EE_READ_CMD; - - outb(EE_ENB & ~EE_CS, ee_addr); - outb(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { - int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outb(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - } - outb(EE_ENB, ee_addr); - eeprom_delay(); - - for (i = 16; i > 0; i--) { - outb(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); - outb(EE_ENB, ee_addr); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outb(~EE_CS, ee_addr); - return retval; -} - -/* MII serial management: mostly bogus for now. */ -/* Read and write the MII management registers using software-generated - serial MDIO protocol. - The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues. */ -#define MDIO_DIR 0x80 -#define MDIO_DATA_OUT 0x04 -#define MDIO_DATA_IN 0x02 -#define MDIO_CLK 0x01 -#define MDIO_WRITE0 (MDIO_DIR) -#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT) - -#define mdio_delay() inb(mdio_addr) - -static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert, - NWayLPAR, NWayExpansion, 0 }; - -/* Syncronize the MII management interface by shifting 32 one bits out. */ -static void mdio_sync(long mdio_addr) -{ - int i; - - for (i = 32; i >= 0; i--) { - outb(MDIO_WRITE1, mdio_addr); - mdio_delay(); - outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr); - mdio_delay(); - } - return; -} -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - long mdio_addr = dev->base_addr + MII_SMI; - int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int retval = 0; - int i; - - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - return location < 8 && mii_2_8139_map[location] ? - inw(dev->base_addr + mii_2_8139_map[location]) : 0; - } - mdio_sync(mdio_addr); - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0; - - outb(MDIO_DIR | dataval, mdio_addr); - mdio_delay(); - outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr); - mdio_delay(); - } - - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - outb(0, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0); - outb(MDIO_CLK, mdio_addr); - mdio_delay(); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - long mdio_addr = dev->base_addr + MII_SMI; - int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - int i; - - if (phy_id > 31) { /* Really a 8139. Use internal registers. */ - if (location < 8 && mii_2_8139_map[location]) - outw(value, dev->base_addr + mii_2_8139_map[location]); - return; - } - mdio_sync(mdio_addr); - - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; - outb(dataval, mdio_addr); - mdio_delay(); - outb(dataval | MDIO_CLK, mdio_addr); - mdio_delay(); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outb(0, mdio_addr); - mdio_delay(); - outb(MDIO_CLK, mdio_addr); - mdio_delay(); - } - return; -} - - -static int -rtl8129_open(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int i, retval; - - MOD_INC_USE_COUNT; - - /* Soft reset the chip. */ - outb(CmdReset, ioaddr + ChipCmd); - - if ((retval = request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev))) { - MOD_DEC_USE_COUNT; - return retval; - } - - tp->tx_bufs = pci_alloc_consistent(tp->pdev, - TX_BUF_SIZE * NUM_TX_DESC, - &tp->tx_bufs_dma); - tp->rx_ring = pci_alloc_consistent(tp->pdev, - RX_BUF_LEN + 16, - &tp->rx_ring_dma); - if (tp->tx_bufs == NULL || tp->rx_ring == NULL) { - free_irq(dev->irq, dev); - if (tp->tx_bufs) - pci_free_consistent(tp->pdev, - TX_BUF_SIZE * NUM_TX_DESC, - tp->tx_bufs, tp->tx_bufs_dma); - if (tp->rx_ring) - pci_free_consistent(tp->pdev, - RX_BUF_LEN + 16, - tp->rx_ring, tp->rx_ring_dma); - if (rtl8129_debug > 0) - printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", - dev->name, RX_BUF_LEN); - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - rtl8129_init_ring(dev); - - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) - break; - - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + MAC0 + i); - - /* Must enable Tx/Rx before setting transfer thresholds! */ - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), - ioaddr + RxConfig); - outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig); - tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000; - - tp->full_duplex = tp->duplex_lock; - if (tp->phys[0] >= 0 || (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) { - u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5); - if (mii_reg5 == 0xffff) - ; /* Not there */ - else if ((mii_reg5 & 0x0100) == 0x0100 - || (mii_reg5 & 0x00C0) == 0x0040) - tp->full_duplex = 1; - if (rtl8129_debug > 1) - printk(KERN_INFO"%s: Setting %s%s-duplex based on" - " auto-negotiated partner ability %4.4x.\n", dev->name, - mii_reg5 == 0 ? "" : - (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ", - tp->full_duplex ? "full" : "half", mii_reg5); - } - - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - - outl(tp->rx_ring_dma, ioaddr + RxBuf); - - /* Start the chip's Tx and Rx process. */ - outl(0, ioaddr + RxMissed); - set_rx_mode(dev); - - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - - /* Enable all known interrupts by setting the interrupt mask. */ - outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); - - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d" - " GP Pins %2.2x %s-duplex.\n", - dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData), - tp->full_duplex ? "full" : "half"); - - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&tp->timer); - tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ - tp->timer.data = (unsigned long)dev; - tp->timer.function = &rtl8129_timer; - add_timer(&tp->timer); - - return 0; -} - -static void rtl8129_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - int mii_reg5 = mdio_read(dev, tp->phys[0], 5); - - if (! tp->duplex_lock && mii_reg5 != 0xffff) { - int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" - " partner ability of %4.4x.\n", dev->name, - tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - } - } - /* Check for bogusness. */ - if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) { - int status = inw(ioaddr + IntrStatus); - if (status & (TxOK | RxOK)) { /* Double check */ - printk(KERN_ERR "%s: RTL8129 Interrupt line blocked, status %x.\n", - dev->name, status); - rtl8129_interrupt(dev->irq, dev, 0); - } - } - if (netif_queue_stopped(dev) && - (jiffies - dev->trans_start) >= 2*TX_TIMEOUT) - rtl8129_tx_timeout(dev); - -#if 0 - if (tp->twistie) { - unsigned int CSCRval = inw(ioaddr + CSCR); /* Read link status. */ - if (tp->twistie == 1) { - if (CSCRval & CSCR_LinkOKBit) { - outw(CSCR_LinkDownOffCmd, ioaddr + CSCR); - tp->twistie = 2; - next_tick = HZ/10; - } else { - outw(CSCR_LinkDownCmd, ioaddr + CSCR); - outl(FIFOTMS_default,ioaddr + FIFOTMS); - outl(PARA78_default ,ioaddr + PARA78); - outl(PARA7c_default ,ioaddr + PARA7c); - tp->twistie = 0; - } - } else if (tp->twistie == 2) { - int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12; - int row; - if (linkcase >= 0x7000) row = 3; - else if (linkcase >= 0x3000) row = 2; - else if (linkcase >= 0x1000) row = 1; - else row = 0; - tp->twistie == row + 3; - outw(0,ioaddr+FIFOTMS); - outl(param[row][0], ioaddr+PARA7c); - tp->twist_cnt = 1; - } else { - outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c); - if (++tp->twist_cnt < 4) { - next_tick = HZ/10; - } else if (tp->twistie-3 == 3) { - if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) { - outl(PARA7c_xxx, ioaddr+PARA7c); - next_tick = HZ/10; /* 100ms. */ - outl(FIFOTMS_default, ioaddr+FIFOTMS); - outl(PARA78_default, ioaddr+PARA78); - outl(PARA7c_default, ioaddr+PARA7c); - tp->twistie == 3 + 3; - outw(0,ioaddr+FIFOTMS); - outl(param[3][0], ioaddr+PARA7c); - tp->twist_cnt = 1; - } - } - } - } -#endif - - if (rtl8129_debug > 2) { - if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR) - printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n", - dev->name, inb(ioaddr + GPPinData)); - else - printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n", - dev->name, inw(ioaddr + NWayLPAR)); - printk(KERN_DEBUG"%s: Other registers are IntMask %4.4x IntStatus %4.4x" - " RxStatus %4.4x.\n", - dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus), - inl(ioaddr + RxEarlyStatus)); - printk(KERN_DEBUG"%s: Chip config %2.2x %2.2x.\n", - dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1)); - } - - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void rtl8129_tx_timeout(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int mii_reg, i; - - if (rtl8129_debug > 0) - printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x " - "media %2.2x.\n", - dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus), - inb(ioaddr + GPPinData)); - - /* Disable interrupts by clearing the interrupt mask. */ - outw(0x0000, ioaddr + IntrMask); - /* Emit info to figure out what went wrong. */ - printk("%s: Tx queue start entry %d dirty entry %d.\n", - dev->name, tp->cur_tx, tp->dirty_tx); - for (i = 0; i < NUM_TX_DESC; i++) - printk(KERN_DEBUG"%s: Tx descriptor %d is %8.8x.%s\n", - dev->name, i, inl(ioaddr + TxStatus0 + i*4), - i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : ""); - printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]); - for (mii_reg = 0; mii_reg < 8; mii_reg++) - printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg)); - printk(".\n"); - - /* Soft reset the chip. */ - outb(CmdReset, ioaddr + ChipCmd); - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) - break; - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + MAC0 + i); - - outb(0x00, ioaddr + Cfg9346); - tp->cur_rx = 0; - /* Must enable Tx/Rx before setting transfer thresholds! */ - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8), - ioaddr + RxConfig); - outl((TX_DMA_BURST<<8), ioaddr + TxConfig); - set_rx_mode(dev); - { /* Save the unsent Tx packets. */ - struct sk_buff *saved_skb[NUM_TX_DESC], *skb; - int j; - for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) { - struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC]; - - saved_skb[j] = rp->skb; - if (rp->mapping != 0) { - pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE); - rp->mapping = 0; - } - } - tp->dirty_tx = tp->cur_tx = 0; - - for (i = 0; i < j; i++) { - skb = tp->tx_info[i].skb = saved_skb[i]; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ - memcpy(tp->tx_buf[i], skb->data, skb->len); - outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs), - ioaddr + TxAddr0 + i*4); - } else { - tp->tx_info[i].mapping = - pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4); - } - /* Note: the chip doesn't have auto-pad! */ - outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), - ioaddr + TxStatus0 + i*4); - } - tp->cur_tx = i; - while (i < NUM_TX_DESC) { - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - i++; - } - if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */ - netif_wake_queue(dev); - tp->tx_full = 0; - } else { - tp->tx_full = 1; - netif_stop_queue(dev); - } - } - - dev->trans_start = jiffies; - tp->stats.tx_errors++; - /* Enable all known interrupts by setting the interrupt mask. */ - outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver - | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask); - return; -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void -rtl8129_init_ring(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int i; - - tp->tx_full = 0; - tp->cur_rx = 0; - tp->dirty_tx = tp->cur_tx = 0; - - for (i = 0; i < NUM_TX_DESC; i++) { - tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE]; - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - } -} - -static int -rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - int entry; - - netif_stop_queue(dev); - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % NUM_TX_DESC; - - tp->tx_info[entry].skb = skb; - if ((long)skb->data & 3) { /* Must use alignment buffer. */ - tp->tx_info[entry].mapping = 0; - memcpy(tp->tx_buf[entry], skb->data, skb->len); - outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs), - ioaddr + TxAddr0 + entry*4); - } else { - tp->tx_info[entry].mapping = - pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4); - } - /* Note: the chip doesn't have auto-pad! */ - outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN), - ioaddr + TxStatus0 + entry*4); - - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) { /* Typical path */ - netif_start_queue(dev); - } else { - tp->tx_full = 1; - } - - dev->trans_start = jiffies; - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n", - dev->name, skb->data, (int)skb->len, entry); - - return 0; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int boguscnt = max_interrupt_work; - int status, link_changed = 0; - long ioaddr = dev->base_addr; - - do { - status = inw(ioaddr + IntrStatus); - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if ((status & RxUnderrun) && inw(ioaddr+CSCR) & CSCR_LinkChangeBit) - link_changed = 1; - outw(status, ioaddr + IntrStatus); - - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", - dev->name, status, inw(ioaddr + IntrStatus)); - - if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver - |TxErr|TxOK|RxErr|RxOK)) == 0) - break; - - if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */ - rtl8129_rx(dev); - - if (status & (TxOK | TxErr)) { - unsigned int dirty_tx = tp->dirty_tx; - - while (tp->cur_tx - dirty_tx > 0) { - int entry = dirty_tx % NUM_TX_DESC; - int txstatus = inl(ioaddr + TxStatus0 + entry*4); - - if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted))) - break; /* It still hasn't been Txed */ - - /* Note: TxCarrierLost is always asserted at 100mbps. */ - if (txstatus & (TxOutOfWindow | TxAborted)) { - /* There was an major error, log it. */ - if (rtl8129_debug > 1) - printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n", - dev->name, txstatus); - tp->stats.tx_errors++; - if (txstatus&TxAborted) { - tp->stats.tx_aborted_errors++; - outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig); - } - if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++; - if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++; -#ifdef ETHER_STATS - if ((txstatus & 0x0f000000) == 0x0f000000) - tp->stats.collisions16++; -#endif - } else { - if (txstatus & TxUnderrun) { - /* Add 64 to the Tx FIFO threshold. */ - if (tp->tx_flag < 0x00300000) - tp->tx_flag += 0x00020000; - tp->stats.tx_fifo_errors++; - } - tp->stats.collisions += (txstatus >> 24) & 15; -#if LINUX_VERSION_CODE > 0x20119 - tp->stats.tx_bytes += txstatus & 0x7ff; -#endif - tp->stats.tx_packets++; - } - - if (tp->tx_info[entry].mapping != 0) { - pci_unmap_single(tp->pdev, - tp->tx_info[entry].mapping, - tp->tx_info[entry].skb->len, - PCI_DMA_TODEVICE); - tp->tx_info[entry].mapping = 0; - } - - /* Free the original skb. */ - dev_kfree_skb_irq(tp->tx_info[entry].skb); - tp->tx_info[entry].skb = NULL; - if (tp->tx_full) { - /* The ring is no longer full, wake the queue. */ - tp->tx_full = 0; - netif_wake_queue(dev); - } - dirty_tx++; - } - -#ifndef final_version - if (tp->cur_tx - dirty_tx > NUM_TX_DESC) { - printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, tp->cur_tx, tp->tx_full); - dirty_tx += NUM_TX_DESC; - } -#endif - tp->dirty_tx = dirty_tx; - } - - /* Check uncommon events with one test. */ - if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver - |TxErr|RxErr)) { - if (rtl8129_debug > 2) - printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n", - dev->name, status); - - if (status == 0xffffffff) - break; - /* Update the error count. */ - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - - if ((status & RxUnderrun) && link_changed && - (rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) { - /* Really link-change on new chips. */ - int lpar = inw(ioaddr + NWayLPAR); - int duplex = (lpar&0x0100)||(lpar & 0x01C0) == 0x0040; - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - outb(0xC0, ioaddr + Cfg9346); - outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1); - outb(0x00, ioaddr + Cfg9346); - } - status &= ~RxUnderrun; - } - if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver)) - tp->stats.rx_errors++; - - if (status & (PCSTimeout)) tp->stats.rx_length_errors++; - if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++; - if (status & RxOverflow) { - tp->stats.rx_over_errors++; - tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN; - outw(tp->cur_rx - 16, ioaddr + RxBufPtr); - } - if (status & PCIErr) { - u32 pci_cmd_status; - pcibios_read_config_dword(tp->pci_bus, tp->pci_devfn, - PCI_COMMAND, &pci_cmd_status); - - printk(KERN_ERR "%s: PCI Bus error %4.4x.\n", - dev->name, pci_cmd_status); - } - } - if (--boguscnt < 0) { - printk(KERN_WARNING"%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outw(0xffff, ioaddr + IntrStatus); - break; - } - } while (1); - - if (rtl8129_debug > 3) - printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, inl(ioaddr + IntrStatus)); - return; -} - -/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the - field alignments and semantics. */ -static int rtl8129_rx(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - unsigned char *rx_ring = tp->rx_ring; - u16 cur_rx = tp->cur_rx; - - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", - dev->name, cur_rx, inw(ioaddr + RxBufAddr), - inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); - - while ((inb(ioaddr + ChipCmd) & 1) == 0) { - int ring_offset = cur_rx % RX_BUF_LEN; - u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset)); - int rx_size = rx_status >> 16; - - if (rtl8129_debug > 4) { - int i; - printk(KERN_DEBUG"%s: rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n", - dev->name, rx_status, rx_size, cur_rx); - printk(KERN_DEBUG"%s: Frame contents ", dev->name); - for (i = 0; i < 70; i++) - printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i])); - printk(".\n"); - } - if (rx_status & RxTooLong) { - if (rtl8129_debug > 0) - printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n", - dev->name, rx_status); - tp->stats.rx_length_errors++; - } else if (rx_status & - (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) { - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: Ethernet frame had errors," - " status %4.4x.\n", dev->name, rx_status); - tp->stats.rx_errors++; - if (rx_status & (RxBadSymbol|RxBadAlign)) - tp->stats.rx_frame_errors++; - if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++; - if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++; - /* Reset the receiver, based on RealTek recommendation. (Bug?) */ - tp->cur_rx = 0; - outb(CmdTxEnb, ioaddr + ChipCmd); - outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd); - outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | - (RX_DMA_BURST<<8), ioaddr + RxConfig); - } else { - /* Malloc up new buffer, compatible with net-2e. */ - /* Omit the four octet CRC from the length. */ - struct sk_buff *skb; - int pkt_size = rx_size - 4; - - skb = dev_alloc_skb(pkt_size + 2); - if (skb == NULL) { - printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; - break; - } - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the IP fields. */ - if (ring_offset+rx_size > RX_BUF_LEN) { - int semi_count = RX_BUF_LEN - ring_offset - 4; - memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], - semi_count); - memcpy(skb_put(skb, pkt_size-semi_count), rx_ring, - pkt_size-semi_count); - if (rtl8129_debug > 4) { - int i; - printk(KERN_DEBUG"%s: Frame wrap @%d", - dev->name, semi_count); - for (i = 0; i < 16; i++) - printk(" %2.2x", le32_to_cpu(rx_ring[i])); - printk(".\n"); - memset(rx_ring, 0xcc, 16); - } - } else { -#if 1 /* USE_IP_COPYSUM */ - eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], - pkt_size, 0); - skb_put(skb, pkt_size); -#else - memcpy(skb_put(skb, pkt_size), &rx_ring[ring_offset + 4], - pkt_size); -#endif - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); -#if LINUX_VERSION_CODE > 0x20119 - tp->stats.rx_bytes += pkt_size; -#endif - tp->stats.rx_packets++; - } - - cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; - outw(cur_rx - 16, ioaddr + RxBufPtr); - } - if (rtl8129_debug > 4) - printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", - dev->name, cur_rx, inw(ioaddr + RxBufAddr), - inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd)); - tp->cur_rx = cur_rx; - return 0; -} - -static int -rtl8129_close(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - int i; - - netif_stop_queue(dev); - - del_timer_sync(&tp->timer); - - if (rtl8129_debug > 1) - printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", - dev->name, inw(ioaddr + IntrStatus)); - - /* Disable interrupts by clearing the interrupt mask. */ - outw(0x0000, ioaddr + IntrMask); - - /* Stop the chip's Tx and Rx DMA processes. */ - outb(0x00, ioaddr + ChipCmd); - - /* Update the error counts. */ - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - - free_irq(dev->irq, dev); - - for (i = 0; i < NUM_TX_DESC; i++) { - struct sk_buff *skb = tp->tx_info[i].skb; - dma_addr_t mapping = tp->tx_info[i].mapping; - - if (skb) { - if (mapping) - pci_unmap_single(tp->pdev, mapping, skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb(skb); - } - tp->tx_info[i].skb = NULL; - tp->tx_info[i].mapping = 0; - } - pci_free_consistent(tp->pdev, RX_BUF_LEN + 16, - tp->rx_ring, tp->rx_ring_dma); - pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC, - tp->tx_bufs, tp->tx_bufs_dma); - tp->rx_ring = NULL; - tp->tx_bufs = NULL; - - /* Green! Put the chip in low-power mode. */ - outb(0xC0, ioaddr + Cfg9346); - outb(0x03, ioaddr + Config1); - outb('H', ioaddr + HltClk); /* 'R' would leave the clock running. */ - - MOD_DEC_USE_COUNT; - - return 0; -} - -static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - u16 *data = (u16 *)&rq->ifr_data; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = tp->phys[0] & 0x3f; - /* Fall Through */ - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - data[3] = mdio_read(dev, data[0], data[1] & 0x1f); - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - mdio_write(dev, data[0], data[1] & 0x1f, data[2]); - return 0; - default: - return -EOPNOTSUPP; - } -} - -static struct net_device_stats * -rtl8129_get_stats(struct net_device *dev) -{ - struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (netif_running(dev)) { - tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); - outl(0, ioaddr + RxMissed); - } - - return &tp->stats; -} - -/* Set or clear the multicast filter for this adaptor. - This routine is not state sensitive and need not be SMP locked. */ - -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while (--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - -/* Bits in RxConfig. */ -enum rx_mode_bits { - AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08, - AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01, -}; - -static void set_rx_mode(struct net_device *dev) -{ - long ioaddr = dev->base_addr; - u32 mc_filter[2]; /* Multicast hash filter */ - int i, rx_mode; - - if (rtl8129_debug > 3) - printk(KERN_DEBUG"%s: set_rx_mode(%4.4x) done -- Rx config %8.8x.\n", - dev->name, dev->flags, inl(ioaddr + RxConfig)); - - /* Note: do not reorder, GCC is clever about common statements. */ - if (dev->flags & IFF_PROMISC) { - /* Unconditionally log net taps. */ - printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name); - rx_mode = AcceptBroadcast|AcceptMulticast|AcceptMyPhys|AcceptAllPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter perfectly -- accept all multicasts. */ - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0xffffffff; - } else { - struct dev_mc_list *mclist; - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); - } - /* We can safely update without stopping the chip. */ - outb(rx_mode, ioaddr + RxConfig); - outl(mc_filter[0], ioaddr + MAR0 + 0); - outl(mc_filter[1], ioaddr + MAR0 + 4); - return; -} - - -static void __exit rtl8129_cleanup (void) -{ - struct net_device *next_dev; - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (root_rtl8129_dev) { - struct rtl8129_private *tp = - (struct rtl8129_private *)root_rtl8129_dev->priv; - next_dev = tp->next_module; - unregister_netdev(root_rtl8129_dev); - release_region(root_rtl8129_dev->base_addr, - pci_tbl[tp->chip_id].io_size); - kfree(tp); - kfree(root_rtl8129_dev); - root_rtl8129_dev = next_dev; - } -} - -module_init(rtl8129_probe); -module_exit(rtl8129_cleanup); - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/sb1000.c linux/drivers/net/sb1000.c --- v2.4.2/linux/drivers/net/sb1000.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/sb1000.c Tue Mar 6 19:44:36 2001 @@ -137,6 +137,14 @@ static inline int sb1000_rx(struct net_device *dev); static inline void sb1000_error_dpc(struct net_device *dev); +static struct isapnp_device_id id_table[] = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('G','I','C'), ISAPNP_FUNCTION(0x1000), 0 }, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, id_table); + /* probe for SB1000 using Plug-n-Play mechanism */ int sb1000_probe(struct net_device *dev) diff -u --recursive --new-file v2.4.2/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c --- v2.4.2/linux/drivers/net/sgiseeq.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/sgiseeq.c Tue Mar 6 19:28:35 2001 @@ -149,7 +149,7 @@ #define RCNTCFG_INIT (HPCDMA_OWN | HPCDMA_EORP | HPCDMA_XIE) #define RCNTINFO_INIT (RCNTCFG_INIT | (PKT_BUF_SZ & HPCDMA_BCNT)) -static void seeq_init_ring(struct net_device *dev) +static int seeq_init_ring(struct net_device *dev) { struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; volatile struct sgiseeq_init_block *ib = &sp->srings; @@ -173,6 +173,8 @@ unsigned long buffer; buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL); + if (!buffer) + return -ENOMEM; ib->tx_desc[i].buf_vaddr = KSEG1ADDR(buffer); ib->tx_desc[i].tdma.pbuf = PHYSADDR(buffer); // flush_cache_all(); @@ -186,6 +188,8 @@ unsigned long buffer; buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL); + if (!buffer) + return -ENOMEM; ib->rx_desc[i].buf_vaddr = KSEG1ADDR(buffer); ib->rx_desc[i].rdma.pbuf = PHYSADDR(buffer); // flush_cache_all(); @@ -193,6 +197,7 @@ ib->rx_desc[i].rdma.cntinfo = (RCNTINFO_INIT); } ib->rx_desc[i - 1].rdma.cntinfo |= (HPCDMA_EOR); + return 0; } #ifdef DEBUG @@ -242,13 +247,16 @@ #define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2) #define RDMACFG_INIT (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ) -static void init_seeq(struct net_device *dev, struct sgiseeq_private *sp, +static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, volatile struct sgiseeq_regs *sregs) { volatile struct hpc3_ethregs *hregs = sp->hregs; + int err; reset_hpc3_and_seeq(hregs, sregs); - seeq_init_ring(dev); + err = seeq_init_ring(dev); + if (err) + return err; /* Setup to field the proper interrupt types. */ if (sp->is_edlc) { @@ -265,6 +273,7 @@ hregs->tx_ndptr = PHYSADDR(&sp->srings.tx_desc[0]); seeq_go(sp, hregs, sregs); + return 0; } static inline void record_rx_errors(struct sgiseeq_private *sp, @@ -440,6 +449,7 @@ struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv; volatile struct sgiseeq_regs *sregs = sp->sregs; unsigned long flags; + int err; save_flags(flags); cli(); if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) { @@ -448,7 +458,9 @@ return -EAGAIN; } - init_seeq(dev, sp, sregs); + err = init_seeq(dev, sp, sregs); + if (err) + return err; netif_start_queue(dev); restore_flags(flags); @@ -474,8 +486,11 @@ { struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; volatile struct sgiseeq_regs *sregs = sp->sregs; + int err; - init_seeq(dev, sp, sregs); + err = init_seeq(dev, sp, sregs); + if (err) + return err; dev->trans_start = jiffies; netif_wake_queue(dev); diff -u --recursive --new-file v2.4.2/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.4.2/linux/drivers/net/sis900.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/sis900.c Tue Mar 6 19:28:34 2001 @@ -18,6 +18,7 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm + Rev 1.07.09 Feb. 9 2001 Dave Jones PCI enable cleanup Rev 1.07.08 Jan. 8 2001 Lei-Chun Chang added RTL8201 PHY support Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix Rev 1.07.06 Nov. 7 2000 Jeff Garzik some bug fix and cleaning @@ -60,7 +61,7 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.07.08 1/8/2001\n"; +"sis900.c: v1.07.09 2/9/2001\n"; static int max_interrupt_work = 20; static int multicast_filter_limit = 128; @@ -252,10 +253,10 @@ static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct sis900_private *sis_priv; - long ioaddr = pci_resource_start(pci_dev, 0); + long ioaddr; struct net_device *net_dev; - int irq = pci_dev->irq; - int i, ret = 0; + int irq; + int i, ret; u8 revision; char *card_name = card_names[pci_id->driver_data]; @@ -266,10 +267,14 @@ } /* setup various bits in PCI command register */ - if (pci_enable_device (pci_dev)) - return -ENODEV; + ret = pci_enable_device (pci_dev); + if (ret) return ret; + pci_set_master(pci_dev); + irq = pci_dev->irq; + ioaddr = pci_resource_start(pci_dev, 0); + net_dev = init_etherdev(NULL, sizeof(struct sis900_private)); if (!net_dev) return -ENOMEM; @@ -315,7 +320,7 @@ goto err_out_region; } - pci_dev->driver_data = net_dev; + pci_set_drvdata(pci_dev, net_dev); pci_dev->dma_mask = SIS900_DMA_MASK; /* The SiS900-specific entries in the device structure. */ @@ -1469,14 +1474,14 @@ tx_status = sis_priv->tx_ring[entry].cmdsts; if (tx_status & OWN) { - /* The packet is not transmited yet (owned by hardware) ! + /* The packet is not transmitted yet (owned by hardware) ! Note: the interrupt is generated only when Tx Machine is idle, so this is an almost impossible case */ break; } if (tx_status & (ABORT | UNDERRUN | OWCOLL)) { - /* packet unsuccessfully transmited */ + /* packet unsuccessfully transmitted */ if (sis900_debug > 3) printk(KERN_INFO "%s: Transmit " "error, Tx status %8.8x.\n", @@ -1491,7 +1496,7 @@ if (tx_status & OWCOLL) sis_priv->stats.tx_window_errors++; } else { - /* packet successfully transmited */ + /* packet successfully transmitted */ sis_priv->stats.collisions += (tx_status & COLCNT) >> 16; sis_priv->stats.tx_bytes += tx_status & DSIZE; sis_priv->stats.tx_packets++; @@ -1838,11 +1843,12 @@ static void __devexit sis900_remove(struct pci_dev *pci_dev) { - struct net_device *net_dev = pci_dev->driver_data; + struct net_device *net_dev = pci_get_drvdata(pci_dev); unregister_netdev(net_dev); release_region(net_dev->base_addr, SIS900_TOTAL_SIZE); kfree(net_dev); + pci_set_drvdata(pci_dev, NULL); } #define SIS900_MODULE_NAME "sis900" diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c --- v2.4.2/linux/drivers/net/sk98lin/skge.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skge.c Tue Mar 6 19:28:34 2001 @@ -109,7 +109,7 @@ * Transmit descriptor polling was not reenabled after SkGePortInit. * * Revision 1.16 1999/07/27 15:17:29 cgoos - * Added some "\n" in output strings (removed while debuging...). + * Added some "\n" in output strings (removed while debugging...). * * Revision 1.15 1999/07/23 12:09:30 cgoos * Performance optimization, rx checksumming, large frame support. @@ -260,7 +260,7 @@ #define VER_STRING "3.05" -/* for debuging on x86 only */ +/* for debugging on x86 only */ /* #define BREAKPOINT() asm(" int $3"); */ /* use of a transmit complete interrupt */ @@ -518,6 +518,12 @@ } /* FreeResources */ +static struct pci_device_id skge_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, skge_pci_tbl); + MODULE_AUTHOR("Christoph Goos "); MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver"); MODULE_PARM(AutoNeg_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s"); @@ -2616,7 +2622,7 @@ * Description: * This function is called if an ioctl is issued on the device. * There are three subfunction for reading, writing and test-writing - * the private MIB data structure (usefull for SysKonnect-internal tools). + * the private MIB data structure (useful for SysKonnect-internal tools). * * Returns: * 0, if everything is ok diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c --- v2.4.2/linux/drivers/net/skfp/skfddi.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/skfp/skfddi.c Tue Mar 6 19:28:34 2001 @@ -182,12 +182,17 @@ extern void enable_tx_irq(struct s_smc *smc, u_short queue); extern void mac_drv_clear_txd(struct s_smc *smc); +static struct pci_device_id skfddi_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl); // Define module-wide (static) variables -static int num_boards = 0; /* total number of adapters configured */ -static int num_fddi = 0; -static int autoprobed = 0; +static int num_boards; /* total number of adapters configured */ +static int num_fddi; +static int autoprobed; #ifdef MODULE int init_module(void); @@ -195,7 +200,7 @@ static struct net_device *unlink_modules(struct net_device *p); static int loading_module = 1; #else -static int loading_module = 0; +static int loading_module; #endif // MODULE #ifdef DRIVERDEBUG @@ -1632,7 +1637,7 @@ * This function is called by the hardware dependent module. * It allocates the memory for the RxD and TxD descriptors. * - * This memory must be non-cached, non-movable and non-swapable. + * This memory must be non-cached, non-movable and non-swappable. * This memory should start at a physical page boundary. * Args * smc - A pointer to the SMT context struct. diff -u --recursive --new-file v2.4.2/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v2.4.2/linux/drivers/net/slhc.c Thu Jul 6 19:27:48 2000 +++ linux/drivers/net/slhc.c Tue Mar 6 22:44:16 2001 @@ -81,8 +81,6 @@ #include #include -int last_retran; - static unsigned char *encode(unsigned char *cp, unsigned short n); static long decode(unsigned char **cpp); static unsigned char * put16(unsigned char *cp, unsigned short x); @@ -256,8 +254,7 @@ ip = (struct iphdr *) icp; /* Bail if this packet isn't TCP, or is an IP fragment */ - if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) || - (ip->frag_off & 32)){ + if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { /* Send as regular IP */ if(ip->protocol != IPPROTO_TCP) comp->sls_o_nontcp++; @@ -351,10 +348,9 @@ */ oth = &cs->cs_tcp; - if(last_retran - || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl || ip->tos != cs->cs_ip.tos - || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64) + || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) || ip->ttl != cs->cs_ip.ttl || th->doff != cs->cs_tcp.doff || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) diff -u --recursive --new-file v2.4.2/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c --- v2.4.2/linux/drivers/net/smc-mca.c Mon Dec 11 13:38:29 2000 +++ linux/drivers/net/smc-mca.c Sun Mar 4 14:05:04 2001 @@ -213,7 +213,7 @@ dev->mem_start = 0; num_pages = 40; - switch (j) { /* 'j' = card-# in const array above [hs] */ + switch (adapter) { /* card-# in const array above [hs] */ case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A: case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A: { @@ -373,9 +373,9 @@ #ifdef notdef /* Officially this is what we are doing, but the readl() is faster */ - memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); + isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); #else - ((unsigned int*)hdr)[0] = readl(hdr_start); + ((unsigned int*)hdr)[0] = isa_readl(hdr_start); #endif } @@ -390,12 +390,12 @@ if (xfer_start + count > dev->rmem_end) { /* We must wrap the input move. */ int semi_count = dev->rmem_end - xfer_start; - memcpy_fromio(skb->data, xfer_start, semi_count); + isa_memcpy_fromio(skb->data, xfer_start, semi_count); count -= semi_count; - memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); + isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + isa_eth_io_copy_and_sum(skb, xfer_start, count, 0); } } @@ -405,7 +405,7 @@ { unsigned long shmem = dev->mem_start + ((start_page - START_PG) << 8); - memcpy_toio(shmem, buf, count); + isa_memcpy_toio(shmem, buf, count); } static int ultramca_close_card(struct net_device *dev) diff -u --recursive --new-file v2.4.2/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c --- v2.4.2/linux/drivers/net/smc9194.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/smc9194.c Sat Mar 3 10:55:48 2001 @@ -238,12 +238,12 @@ . This is a separate procedure to handle the receipt of a packet, to . leave the interrupt code looking slightly cleaner */ -inline static void smc_rcv( struct net_device *dev ); +static inline void smc_rcv( struct net_device *dev ); /* . This handles a TX interrupt, which is only called when an error . relating to a packet is sent. */ -inline static void smc_tx( struct net_device * dev ); +static inline void smc_tx( struct net_device * dev ); /* ------------------------------------------------------------ @@ -616,7 +616,7 @@ if ( packet_no & 0x80 ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); - dev_kfree_skb_irq(skb); + dev_kfree_skb_any(skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; @@ -679,7 +679,7 @@ PRINTK2((CARDNAME": Sent packet of length %d \n",length)); lp->saved_skb = NULL; - dev_kfree_skb_irq (skb); + dev_kfree_skb_any (skb); dev->trans_start = jiffies; @@ -1341,9 +1341,9 @@ skb = dev_alloc_skb( packet_length + 5); if ( skb == NULL ) { - printk(KERN_NOTICE CARDNAME - ": Low memory, packet dropped.\n"); + printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n"); lp->stats.rx_dropped++; + goto done; } /* @@ -1396,6 +1396,8 @@ lp->stats.rx_length_errors++; if ( status & RS_BADCRC) lp->stats.rx_crc_errors++; } + +done: /* error or good, tell the card to get rid of this packet */ outw( MC_RELEASE, ioaddr + MMU_CMD ); diff -u --recursive --new-file v2.4.2/linux/drivers/net/sonic.h linux/drivers/net/sonic.h --- v2.4.2/linux/drivers/net/sonic.h Tue Jul 11 11:12:24 2000 +++ linux/drivers/net/sonic.h Sat Mar 3 10:55:47 2001 @@ -445,7 +445,7 @@ struct sonic_local { sonic_cda_t cda; /* virtual CPU address of CDA */ sonic_td_t tda[SONIC_NUM_TDS]; /* transmit descriptor area */ - sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource arrea */ + sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource area */ sonic_rd_t rda[SONIC_NUM_RDS]; /* receive descriptor area */ struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */ unsigned int tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c --- v2.4.2/linux/drivers/net/sun3lance.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/sun3lance.c Tue Mar 6 19:28:35 2001 @@ -148,9 +148,9 @@ int new_rx, new_tx; /* The next free ring entry */ int old_tx, old_rx; /* ring entry to be processed */ struct net_device_stats stats; -/* These two must be ints for set_bit() */ - int tx_full; - int lock; +/* These two must be longs for set_bit() */ + long tx_full; + long lock; }; /* I/O register access macros */ @@ -303,8 +303,11 @@ } init_etherdev( dev, sizeof(struct lance_private) ); - if (!dev->priv) + if (!dev->priv) { dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); + if (!dev->priv) + return 0; + } lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)sun3_dvma_malloc(sizeof(struct lance_memory)); diff -u --recursive --new-file v2.4.2/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c --- v2.4.2/linux/drivers/net/sunbmac.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/sunbmac.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: sunbmac.c,v 1.23 2001/01/20 03:36:40 davem Exp $ +/* $Id: sunbmac.c,v 1.25 2001/02/18 08:10:21 davem Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -902,19 +902,15 @@ static int bigmac_open(struct net_device *dev) { struct bigmac *bp = (struct bigmac *) dev->priv; - int res; + int ret; - if (request_irq(dev->irq, &bigmac_interrupt, - SA_SHIRQ, "BIG MAC", (void *) bp)) { + ret = request_irq(dev->irq, &bigmac_interrupt, SA_SHIRQ, dev->name, bp); + if (ret) { printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq); - return -EAGAIN; + return ret; } init_timer(&bp->bigmac_timer); - res = bigmac_init(bp, 0); - if (!res) { - MOD_INC_USE_COUNT; - } - return res; + return bigmac_init(bp, 0); } static int bigmac_close(struct net_device *dev) @@ -928,7 +924,6 @@ bigmac_stop(bp); bigmac_clean_rings(bp); free_irq(dev->irq, (void *)bp); - MOD_DEC_USE_COUNT; return 0; } @@ -1058,7 +1053,10 @@ int i; /* Get a new device struct for this interface. */ - dev = init_etherdev(0, sizeof(struct bigmac)); + dev = init_etherdev(NULL, sizeof(struct bigmac)); + if (!dev) + return -ENOMEM; + SET_MODULE_OWNER(dev); if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -1075,7 +1073,7 @@ printk("\n"); /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */ - bp = (struct bigmac *) dev->priv; + bp = dev->priv; bp->qec_sdev = qec_sdev; bp->bigmac_sdev = qec_sdev->child; diff -u --recursive --new-file v2.4.2/linux/drivers/net/sundance.c linux/drivers/net/sundance.c --- v2.4.2/linux/drivers/net/sundance.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/sundance.c Tue Mar 6 19:28:34 2001 @@ -314,6 +314,7 @@ #define PRIV_ALIGN 15 /* Required alignment mask */ /* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment within the structure. */ +#define MII_CNT 4 struct netdev_private { /* Descriptor rings first for alignment. */ struct netdev_desc rx_ring[RX_RING_SIZE]; @@ -346,7 +347,7 @@ /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ + unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ }; /* The station address location in the EEPROM. */ @@ -379,7 +380,7 @@ struct netdev_private *np; static int card_idx; int chip_idx = ent->driver_data; - int irq = pdev->irq; + int irq; int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; long ioaddr; @@ -387,19 +388,20 @@ return -EIO; pci_set_master(pdev); + irq = pdev->irq; + dev = init_etherdev(NULL, sizeof(*np)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); + if (pci_request_regions(pdev, dev->name)) + goto err_out_netdev; + #ifdef USE_IO_OPS ioaddr = pci_resource_start(pdev, 0); - if (!request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) - goto err_out_netdev; #else ioaddr = pci_resource_start(pdev, 1); - if (!request_mem_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) - goto err_out_netdev; ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); if (!ioaddr) goto err_out_iomem; @@ -456,7 +458,7 @@ if (1) { int phy, phy_idx = 0; np->phys[0] = 1; /* Default setting */ - for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; @@ -485,8 +487,7 @@ #ifndef USE_IO_OPS err_out_iomem: - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[chip_idx].io_size); + pci_release_regions(pdev); #endif err_out_netdev: unregister_netdev (dev); @@ -604,7 +605,7 @@ static int netdev_open(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; @@ -667,7 +668,7 @@ static void check_duplex(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int mii_reg5 = mdio_read(dev, np->phys[0], 5); int negotiated = mii_reg5 & np->advertising; @@ -689,7 +690,7 @@ static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; @@ -706,7 +707,7 @@ static void tx_timeout(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %2.2x," @@ -735,14 +736,16 @@ dev->trans_start = jiffies; np->stats.tx_errors++; - return; + + if (!np->tx_full) + netif_wake_queue(dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void init_ring(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; np->tx_full = 0; @@ -784,7 +787,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; struct netdev_desc *txdesc; unsigned entry; @@ -838,7 +841,7 @@ int boguscnt = max_interrupt_work; ioaddr = dev->base_addr; - np = (struct netdev_private *)dev->priv; + np = dev->priv; spin_lock(&np->lock); do { @@ -935,7 +938,7 @@ for clarity and better register allocation. */ static int netdev_rx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int entry = np->cur_rx % RX_RING_SIZE; int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; @@ -1026,7 +1029,7 @@ static void netdev_error(struct net_device *dev, int intr_status) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; if (intr_status & IntrDrvRqst) { /* Stop the down counter and turn interrupts back on. */ @@ -1055,7 +1058,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; /* We should lock this segment of code for SMP eventually, although @@ -1165,7 +1168,7 @@ static int netdev_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; netif_stop_queue(dev); @@ -1227,23 +1230,19 @@ static void __devexit sundance_remove1 (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (dev) { - struct netdev_private *np = (void *)(dev->priv); unregister_netdev(dev); -#ifdef USE_IO_OPS - release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size); -#else - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[np->chip_id].io_size); + pci_release_regions(pdev); +#ifndef USE_IO_OPS iounmap((char *)(dev->base_addr)); #endif kfree(dev); } - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); } static struct pci_driver sundance_driver = { diff -u --recursive --new-file v2.4.2/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.4.2/linux/drivers/net/sunlance.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/sunlance.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.105 2000/10/22 16:08:38 davem Exp $ +/* $Id: sunlance.c,v 1.107 2001/02/18 08:10:21 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -965,9 +965,6 @@ sbus_writew(LE_C0_INEA | LE_C0_TDMD, lp->lregs + RDP); } - if (!status) - MOD_INC_USE_COUNT; - return status; } @@ -981,7 +978,6 @@ STOP_LANCE(lp); free_irq(dev->irq, (void *) dev); - MOD_DEC_USE_COUNT; return 0; } @@ -1467,6 +1463,7 @@ } lp->dev = dev; + SET_MODULE_OWNER(dev); dev->open = &lance_open; dev->stop = &lance_close; dev->hard_start_xmit = &lance_start_xmit; diff -u --recursive --new-file v2.4.2/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.4.2/linux/drivers/net/sunqe.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/sunqe.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: sunqe.c,v 1.47 2000/10/22 16:08:38 davem Exp $ +/* $Id: sunqe.c,v 1.50 2001/02/18 08:10:21 davem Exp $ * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed @@ -438,7 +438,7 @@ len, 0); skb->protocol = eth_type_trans(skb, qep->dev); netif_rx(skb); - dev->last_rx = jiffies; + qep->dev->last_rx = jiffies; qep->net_stats.rx_packets++; qep->net_stats.rx_bytes += len; } @@ -503,16 +503,11 @@ static int qe_open(struct net_device *dev) { struct sunqe *qep = (struct sunqe *) dev->priv; - int res; qep->mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB | MREGS_MCONFIG_MBAENAB); - res = qe_init(qep, 0); - if (!res) - MOD_INC_USE_COUNT; - - return res; + return qe_init(qep, 0); } static int qe_close(struct net_device *dev) @@ -520,7 +515,6 @@ struct sunqe *qep = (struct sunqe *) dev->priv; qe_stop(qep); - MOD_DEC_USE_COUNT; return 0; } @@ -882,6 +876,7 @@ } for (i = 0; i < 4; i++) { + SET_MODULE_OWNER(qe_devs[i]); qe_devs[i]->open = qe_open; qe_devs[i]->stop = qe_close; qe_devs[i]->hard_start_xmit = qe_start_xmit; diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/Config.in linux/drivers/net/tokenring/Config.in --- v2.4.2/linux/drivers/net/tokenring/Config.in Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/Config.in Tue Mar 6 19:28:35 2001 @@ -5,21 +5,29 @@ mainmenu_option next_comment comment 'Token Ring devices' -bool 'Token Ring driver support' CONFIG_TR +# So far, we only have PCI, ISA, and MCA token ring devices +if [ "$CONFIG_PCI" = "y" -o "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then + bool 'Token Ring driver support' CONFIG_TR +else + define_bool CONFIG_TR n +fi + if [ "$CONFIG_TR" != "n" ]; then - dep_tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR $CONFIG_TR - dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR - dep_tristate ' IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR - dep_tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR $CONFIG_TR + if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then + tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR + fi + dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR $CONFIG_PCI + dep_tristate ' IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR $CONFIG_PCI + tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR if [ "$CONFIG_TMS380TR" != "n" ]; then - dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_TMS380TR - dep_tristate ' Generic TMS380 ISA support' CONFIG_TMSISA $CONFIG_TMS380TR - dep_tristate ' Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_TMS380TR - if [ "$CONFIG_MCA" = "y" ]; then - dep_tristate ' Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR - fi + dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_PCI + dep_tristate ' Generic TMS380 ISA support' CONFIG_TMSISA $CONFIG_ISA + dep_tristate ' Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_PCI + dep_tristate ' Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_MCA + fi + if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then + tristate ' SMC ISA/MCA adapter support' CONFIG_SMCTR fi - dep_tristate ' SMC ISA/MCA adapter support' CONFIG_SMCTR $CONFIG_TR fi endmenu diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c --- v2.4.2/linux/drivers/net/tokenring/olympic.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/olympic.c Tue Mar 6 19:28:35 2001 @@ -1,6 +1,6 @@ /* * olympic.c (c) 1999 Peter De Schrijver All Rights Reserved - * 1999 Mike Phillips (phillim@amtrak.com) + * 1999 Mike Phillips (mikep@linuxtr.net) * * Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic * chipset. @@ -38,10 +38,11 @@ * Fixing the hardware descriptors was another matter, * because they weren't going through read[wl](), there all * the results had to be in memory in le32 values. kdaaker - * + * 12/23/00 - Added minimal Cardbus support (Thanks Donald). * * To Do: - * + * Complete full Cardbus / hot-swap support. + * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult @@ -99,7 +100,7 @@ */ static char *version = -"Olympic.c v0.5.0 3/10/00 - Peter De Schrijver & Mike Phillips" ; +"Olympic.c v0.5.C 12/23/00 - Peter De Schrijver & Mike Phillips" ; static struct pci_device_id olympic_pci_tbl[] __initdata = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, PCI_ANY_ID, PCI_ANY_ID, }, @@ -191,11 +192,9 @@ if (pci_enable_device(pci_device)) continue; - /* These lines are needed by the PowerPC, it appears -that these flags - * are not being set properly for the PPC, this may -well be fixed with - * the new PCI code */ + /* These lines are needed by the PowerPC, it appears that these flags + * are not being set properly for the PPC, this may well be fixed with + * the new PCI code */ pci_read_config_word(pci_device, PCI_COMMAND, &pci_command); pci_command |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_write_config_word(pci_device, PCI_COMMAND,pci_command); @@ -224,7 +223,7 @@ #endif dev->irq=pci_device->irq; dev->base_addr=pci_resource_start(pci_device, 0); - dev->init=&olympic_init; + dev->init=&olympic_init; /* AKPM: Not needed */ olympic_priv->olympic_card_name = (char *)pci_device->resource[0].name ; olympic_priv->olympic_mmio = ioremap(pci_resource_start(pci_device,1),256); @@ -240,7 +239,6 @@ olympic_priv->olympic_message_level = message_level[card_no] ; if(olympic_init(dev)==-1) { - unregister_netdevice(dev); kfree(dev->priv); return 0; } @@ -287,6 +285,10 @@ } spin_lock_init(&olympic_priv->olympic_lock) ; + + /* Needed for cardbus */ + if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) + writel(readl(olympic_priv->olympic_mmio+FERMASK)|FERMASK_INT_BIT, olympic_mmio+FERMASK); #if OLYMPIC_DEBUG printk("BCTL: %x\n",readl(olympic_mmio+BCTL)); diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/olympic.h linux/drivers/net/tokenring/olympic.h --- v2.4.2/linux/drivers/net/tokenring/olympic.h Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/olympic.h Tue Mar 6 19:28:35 2001 @@ -1,6 +1,6 @@ /* * olympic.h (c) 1999 Peter De Schrijver All Rights Reserved - * 1999 Mike Phillips (phillim@amtrak.com) + * 1999 Mike Phillips (mikep@linuxtr.net) * * Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset. * @@ -19,6 +19,7 @@ #define BCTL 0x70 #define BCTL_SOFTRESET (1<<15) #define BCTL_MIMREB (1<<6) +#define BCTL_MODE_INDICATOR (1<<5) #define GPR 0x4a #define GPR_OPTI_BF (1<<6) @@ -124,6 +125,9 @@ #define TXSTATQCNT_2 0xe4 #define TXCSA_1 0xc8 #define TXCSA_2 0xe8 +/* Cardbus */ +#define FERMASK 0xf4 +#define FERMASK_INT_BIT (1<<15) #define OLYMPIC_IO_SPACE 256 diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c --- v2.4.2/linux/drivers/net/tokenring/smctr.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/smctr.c Tue Mar 6 19:28:34 2001 @@ -4383,7 +4383,7 @@ smctr_clear_trc_reset(ioaddr); mdelay(200); /* ~2 ms */ - /* Remove any latched interrupts that occured prior to reseting the + /* Remove any latched interrupts that occurred prior to reseting the * adapter or possibily caused by line glitches due to the reset. */ outb(tp->trc_mask | CSR_CLRTINT | CSR_CLRCBUSY, ioaddr + CSR); diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c --- v2.4.2/linux/drivers/net/tokenring/tms380tr.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/tms380tr.c Sat Mar 3 10:55:47 2001 @@ -2203,6 +2203,7 @@ skb_trim(skb,Length); skb->protocol = tr_type_trans(skb,dev); netif_rx(skb); + dev->last_rx = jiffies; } } else /* Invalid frame */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/tms380tr.h linux/drivers/net/tokenring/tms380tr.h --- v2.4.2/linux/drivers/net/tokenring/tms380tr.h Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/tms380tr.h Tue Mar 6 19:28:34 2001 @@ -395,7 +395,7 @@ /* OPEN Options (high-low) */ #define WRAP_INTERFACE 0x0080 /* Inserting omitted for test * purposes; transmit data appears - * as receive data. (usefull for + * as receive data. (useful for * testing; change: CLOSE necessary) */ #define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog --- v2.4.2/linux/drivers/net/tulip/ChangeLog Sat Feb 3 19:51:28 2001 +++ linux/drivers/net/tulip/ChangeLog Fri Mar 2 11:02:14 2001 @@ -1,3 +1,54 @@ +2001-02-20 Jeff Garzik + + * media.c (tulip_select_media): No need to initialize + new_csr6, all cases initialize it properly. + +2001-02-18 Manfred Spraul + + * interrupt.c (tulip_refill_rx): Make public. + If PNIC chip stops due to lack of Rx buffers, restart it. + (tulip_interrupt): PNIC doesn't have a h/w timer, emulate + with software timers. + * pnic.c (pnic_check_duplex): New function, PNIC-specific + version of tulip_check_duplex. + (pnic_lnk_change): Call pnic_check_duplex. If we use an + external MII, then we mustn't use the internal negotiation. + (pnic_timer): Support Rx refilling on work overflow in + interrupt handler, as PNIC doesn't support a h/w timer. + * tulip_core.c (tulip_tbl[]): Modify default csr6 + +2001-02-11 Jeff Garzik + + * tulip_core.c (tulip_init_one): Call pci_enable_device + to ensure wakeup/resource assignment before checking those + values. + (tulip_init_one): Replace PCI ids with constants from pci_id.h. + (tulip_suspend, tulip_resume, tulip_remove_one): Call + pci_power_on/off (commented out for now). + +2001-02-10 Jeff Garzik + + * tulip.h: Add CFDD_xxx bits for Tulip power management + * tulip_core.c (tulip_set_power_state): New function, + manipulating Tulip chip power state where supported. + (tulip_up, tulip_down, tulip_init_one): Use it. + +2001-02-10 Jeff Garzik + + * tulip_core.c (tulip_tx_timeout): Call netif_wake_queue + to ensure the next Tx is always sent to us. + +2001-01-27 Jeff Garzik + + * tulip_core.c (tulip_remove_one): Fix mem leak by freeing + tp->media_tbl. Add check for !dev, reformat code appropriately. + +2001-01-27 Jeff Garzik + + * tulip_tbl[]: Comment all entries to make order and chip_id + relationship more clear. + * tulip_pci_tbl[]: Add new Accton PCI id (COMET chipset). + 2001-01-16 Jeff Garzik * tulip_core.c: static vars no longer explicitly diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c --- v2.4.2/linux/drivers/net/tulip/interrupt.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tulip/interrupt.c Fri Mar 2 11:02:14 2001 @@ -23,7 +23,7 @@ -static int tulip_refill_rx(struct net_device *dev) +int tulip_refill_rx(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; int entry; @@ -50,6 +50,14 @@ } tp->rx_ring[entry].status = cpu_to_le32(DescOwned); } + if(tp->chip_id == LC82C168) { + if(((inl(dev->base_addr + CSR5)>>17)&0x07) == 4) { + /* Rx stopped due to out of buffers, + * restart it + */ + outl(0x01, dev->base_addr + CSR2); + } + } return refilled; } @@ -332,7 +340,11 @@ /* Josip Loncaric at ICASE did extensive experimentation to develop a good interrupt mitigation setting.*/ outl(0x8b240000, ioaddr + CSR11); - } else { + } else if (tp->chip_id == LC82C168) { + /* the LC82C168 doesn't have a hw timer.*/ + outl(0x00, ioaddr + CSR7); + mod_timer(&tp->timer, RUN_AT(HZ/50)); + } else { /* Mask all interrupting sources, set timer to re-enable. */ outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); @@ -355,14 +367,19 @@ if (tp->rx_buffers[entry].skb == NULL) { if (tulip_debug > 1) printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); - if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); - outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, - ioaddr + CSR7); - outl(TimerInt, ioaddr + CSR5); - outl(12, ioaddr + CSR11); - tp->ttimer = 1; + if (tp->chip_id == LC82C168) { + outl(0x00, ioaddr + CSR7); + mod_timer(&tp->timer, RUN_AT(HZ/50)); + } else { + if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); + outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, + ioaddr + CSR7); + outl(TimerInt, ioaddr + CSR5); + outl(12, ioaddr + CSR11); + tp->ttimer = 1; + } } } diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c --- v2.4.2/linux/drivers/net/tulip/media.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tulip/media.c Fri Mar 2 11:02:14 2001 @@ -148,7 +148,7 @@ long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; struct mediatable *mtable = tp->mtable; - u32 new_csr6=0; + u32 new_csr6; int i; if (mtable) { diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c --- v2.4.2/linux/drivers/net/tulip/pnic.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tulip/pnic.c Fri Mar 2 11:02:14 2001 @@ -50,6 +50,61 @@ } } +/* Modified version of tulip_check_duplex: + * Always update the 100mbps bit, even if the + * full duplex bit didn't change. + * Manfred Spraul + */ +int pnic_check_duplex(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int mii_reg1, mii_reg5, negotiated, duplex; + int new_csr6; + + mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5); + if (tulip_debug > 1) + printk(KERN_INFO "%s: MII status %4.4x, Link partner report " + "%4.4x.\n", dev->name, mii_reg1, mii_reg5); + if (mii_reg1 == 0xffff) + return -2; + if ((mii_reg1 & 0x0004) == 0) { + int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + if ((new_reg1 & 0x0004) == 0) { + if (tulip_debug > 1) + printk(KERN_INFO "%s: No link beat on the MII interface," + " status %4.4x.\n", dev->name, new_reg1); + return -1; + } + } + negotiated = mii_reg5 & tp->advertising[0]; + /* 100baseTx-FD or 10T-FD, but not 100-HD */ + duplex = ((negotiated & 0x0300) == 0x0100 + || (negotiated & 0x00C0) == 0x0040) || + tp->full_duplex_lock; + + new_csr6 = tp->csr6; + if (negotiated & 0x0380) /* 100mbps. */ + new_csr6 &= ~0x00400000; + else + new_csr6 |= 0x00400000; + if (duplex) + new_csr6 |= 0x0200; + else + new_csr6 &= ~0x0200; + if (new_csr6 != tp->csr6) { + tp->full_duplex = duplex; + tp->csr6 = new_csr6; + if (tulip_debug > 0) + printk(KERN_INFO "%s: Setting %s-duplex based on MII" + "#%d link partner capability of %4.4x.\n", + dev->name, tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + tulip_restart_rxtx(tp, tp->csr6); + return 1; + } + return 0; +} void pnic_lnk_change(struct net_device *dev, int csr5) { @@ -62,6 +117,11 @@ dev->name, phy_reg, csr5); if (inl(ioaddr + CSR5) & TPLnkFail) { outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); + /* If we use an external MII, then we mustn't use the + * internal negotiation. + */ + if (tulip_media_cap[dev->if_port] & MediaIsMII) + return; if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); tulip_outl_csr(tp, tp->csr6, CSR6); @@ -70,11 +130,18 @@ dev->trans_start = jiffies; } } else if (inl(ioaddr + CSR5) & TPLnkPass) { - pnic_do_nway(dev); + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + spin_lock(&tp->lock); + pnic_check_duplex(dev); + spin_unlock(&tp->lock); + } else { + pnic_do_nway(dev); + } outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); } } +int tulip_refill_rx(struct net_device *dev); void pnic_timer(unsigned long data) { @@ -82,10 +149,21 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; + + if(!inl(ioaddr + CSR7)) { + /* the timer was called due to a work overflow + * in the interrupt handler. Skip the connection + * checks, the nic is definitively speaking with + * his link partner. + */ + goto too_good_connection; + } if (tulip_media_cap[dev->if_port] & MediaIsMII) { - if (tulip_check_duplex(dev) > 0) + spin_lock_irq(&tp->lock); + if (pnic_check_duplex(dev) > 0) next_tick = 3*HZ; + spin_unlock_irq(&tp->lock); } else { int csr12 = inl(ioaddr + CSR12); int new_csr6 = tp->csr6 & ~0x40C40200; @@ -137,7 +215,14 @@ } } } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); +too_good_connection: + mod_timer(&tp->timer, RUN_AT(next_tick)); + if(!inl(ioaddr + CSR7)) { + if (tulip_debug > 1) + printk(KERN_INFO "%s: sw timer wakeup.\n", dev->name); + disable_irq(dev->irq); + tulip_refill_rx(dev); + enable_irq(dev->irq); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + } } - diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h --- v2.4.2/linux/drivers/net/tulip/tulip.h Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tulip/tulip.h Tue Mar 6 22:44:16 2001 @@ -18,6 +18,7 @@ #include #include #include +#include @@ -107,7 +108,14 @@ CSR12 = 0x60, CSR13 = 0x68, CSR14 = 0x70, - CSR15 = 0x78 + CSR15 = 0x78, +}; + +/* register offset and bits for CFDD PCI config reg */ +enum pci_cfg_driver_reg { + CFDD = 0x40, + CFDD_Sleep = (1 << 31), + CFDD_Snooze = (1 << 30), }; diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.4.2/linux/drivers/net/tulip/tulip_core.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tulip/tulip_core.c Fri Mar 2 11:02:14 2001 @@ -28,7 +28,7 @@ #include static char version[] __devinitdata = - "Linux Tulip driver version 0.9.13a (January 20, 2001)\n"; + "Linux Tulip driver version 0.9.14 (February 20, 2001)\n"; /* A few user-configurable values. */ @@ -120,37 +120,63 @@ */ struct tulip_chip_table tulip_tbl[] = { + /* DC21040 */ { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, + + /* DC21041 */ { "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer }, + + /* DC21140 */ { "Digital DS21140 Tulip", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, + + /* DC21142, DC21143 */ { "Digital DS21143 Tulip", 128, 0x0801fbff, HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY | HAS_INTR_MITIGATION, t21142_timer }, - { "Lite-On 82c168 PNIC", 256, 0x0001ebef, + + /* LC82C168 */ + { "Lite-On 82c168 PNIC", 256, 0x0001fbef, HAS_MII | HAS_PNICNWAY, pnic_timer }, + + /* MX98713 */ { "Macronix 98713 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + + /* MX98715 */ { "Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, + + /* MX98725 */ { "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, + + /* AX88140 */ { "ASIX AX88140", 128, 0x0001fbff, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer }, + + /* PNIC2 */ { "Lite-On PNIC-II", 256, 0x0801fbff, HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer }, + + /* COMET */ { "ADMtek Comet", 256, 0x0001abef, MC_HASH_ONLY, comet_timer }, + + /* COMPEX9881 */ { "Compex 9881 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + + /* I21145 */ { "Intel DS21145 Tulip", 128, 0x0801fbff, HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY, t21142_timer }, + + /* DM910X */ { "Davicom DM9102/DM9102A", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI, tulip_timer }, - {0}, }; @@ -176,6 +202,7 @@ { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X }, + { 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, {0, } }; @@ -212,6 +239,24 @@ +static void tulip_set_power_state (struct tulip_private *tp, + int sleep, int snooze) +{ + if (tp->flags & HAS_ACPI) { + u32 tmp, newtmp; + pci_read_config_dword (tp->pdev, CFDD, &tmp); + newtmp = tmp & ~(CFDD_Sleep | CFDD_Snooze); + if (sleep) + newtmp |= CFDD_Sleep; + else if (snooze) + newtmp |= CFDD_Snooze; + if (tmp != newtmp) + pci_write_config_dword (tp->pdev, CFDD, newtmp); + } + +} + + static void tulip_up(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -222,8 +267,7 @@ DPRINTK("ENTER\n"); /* Wake the chip from sleep/snooze mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword(tp->pdev, 0x40, 0); + tulip_set_power_state (tp, 0, 0); /* On some chip revs we must set the MII/SYM port before the reset!? */ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) @@ -532,8 +576,9 @@ tp->stats.tx_errors++; out: - dev->trans_start = jiffies; spin_unlock_irqrestore (&tp->lock, flags); + dev->trans_start = jiffies; + netif_wake_queue (dev); } @@ -670,8 +715,7 @@ dev->if_port = tp->saved_if_port; /* Leave the driver in snooze, not sleep, mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword (tp->pdev, 0x40, 0x40000000); + tulip_set_power_state (tp, 0, 1); } @@ -1049,7 +1093,7 @@ * different driver (lmc driver) */ - if( pdev->subsystem_vendor == 0x1376 ){ + if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) { printk (KERN_ERR PFX "skipping LMC card.\n"); return -ENODEV; } @@ -1080,16 +1124,24 @@ thankfully its an old 486 chipset. */ - if (pci_find_device(PCI_VENDOR_ID_INTEL, 0x0483, NULL)) + if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL)) csr0 = 0x00A04800; /* The dreaded SiS496 486 chipset. Same workaround as above. */ - if (pci_find_device(PCI_VENDOR_ID_SI, 0x0496, NULL)) + if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL)) csr0 = 0x00A04800; /* * And back to business */ + i = pci_enable_device(pdev); + if (i) { + printk (KERN_ERR PFX + "Cannot enable tulip board #%d, aborting\n", + board_idx); + return i; + } + ioaddr = pci_resource_start (pdev, 0); irq = pdev->irq; @@ -1126,12 +1178,6 @@ goto err_out_free_pio_res; } - if (pci_enable_device(pdev)) { - printk (KERN_ERR PFX "%s: Cannot enable PCI device, aborting\n", - dev->name); - goto err_out_free_mmio_res; - } - pci_set_master(pdev); pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); @@ -1443,8 +1489,7 @@ } /* put the chip in snooze mode until opened */ - if (tulip_tbl[chip_idx].flags & HAS_ACPI) - pci_write_config_dword(pdev, 0x40, 0x40000000); + tulip_set_power_state (tp, 0, 1); return 0; @@ -1468,8 +1513,8 @@ if (dev && netif_device_present (dev)) { netif_device_detach (dev); tulip_down (dev); + /* pci_power_off(pdev, -1); */ } -// pci_set_power_state(pdev, 3); } @@ -1477,8 +1522,11 @@ { struct net_device *dev = pci_get_drvdata(pdev); - pci_enable_device(pdev); +#if 1 + pci_enable_device (pdev); +#endif if (dev && !netif_device_present (dev)) { + /* pci_power_on(pdev); */ tulip_up (dev); netif_device_attach (dev); } @@ -1487,24 +1535,29 @@ static void __devexit tulip_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = pci_get_drvdata (pdev); + struct tulip_private *tp; - if (dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - pci_free_consistent(pdev, - sizeof(struct tulip_rx_desc) * RX_RING_SIZE + - sizeof(struct tulip_tx_desc) * TX_RING_SIZE, - tp->rx_ring, - tp->rx_ring_dma); - unregister_netdev(dev); - release_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); - release_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - kfree(dev); + if (!dev) + return; - pci_set_drvdata(pdev, NULL); - } + tp = dev->priv; + pci_free_consistent (pdev, + sizeof (struct tulip_rx_desc) * RX_RING_SIZE + + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, + tp->rx_ring, tp->rx_ring_dma); + unregister_netdev (dev); + release_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); + release_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + if (tp->mtable) + kfree (tp->mtable); + kfree (dev); + + pci_set_drvdata (pdev, NULL); + + /* pci_power_off (pdev, -1); */ } diff -u --recursive --new-file v2.4.2/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.4.2/linux/drivers/net/via-rhine.c Mon Dec 11 13:38:29 2000 +++ linux/drivers/net/via-rhine.c Tue Mar 6 22:44:16 2001 @@ -55,6 +55,9 @@ LK1.1.6: - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio) set netif_running_on/off on startup, del_timer_sync + + LK1.1.7: + - Manfred Spraul: added reset into tx_timeout */ @@ -114,20 +117,22 @@ #include #include #include -#include +#include #include #include #include #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include +#include /* These identify the driver base version and may not be removed. */ static char version1[] __devinitdata = -"via-rhine.c:v1.08b-LK1.1.6 8/9/2000 Written by Donald Becker\n"; +"via-rhine.c:v1.08b-LK1.1.7 8/9/2000 Written by Donald Becker\n"; static char version2[] __devinitdata = " http://www.scyld.com/network/via-rhine.html\n"; @@ -213,7 +218,7 @@ most useful with small frames. Since the VIA chips are only able to transfer data to buffers on 32 bit -boundaries, the the IP header at offset 14 in an ethernet frame isn't +boundaries, the IP header at offset 14 in an ethernet frame isn't longword aligned for further processing. Copying these unaligned buffers has the beneficial effect of 16-byte aligning the IP header. @@ -380,6 +385,7 @@ CmdNoTxPoll=0x0800, CmdReset=0x8000, }; +#define MAX_MII_CNT 4 struct netdev_private { /* Descriptor rings */ struct rx_desc *rx_ring; @@ -421,7 +427,8 @@ /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ + unsigned char phys[MAX_MII_CNT]; /* MII device addresses. */ + unsigned int mii_cnt; /* number of MIIs found, but only the first one is used */ u16 mii_status; /* last read MII status */ }; @@ -431,7 +438,6 @@ static void via_rhine_check_duplex(struct net_device *dev); static void via_rhine_timer(unsigned long data); static void via_rhine_tx_timeout(struct net_device *dev); -static void via_rhine_init_ring(struct net_device *dev); static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static void via_rhine_tx(struct net_device *dev); @@ -443,6 +449,25 @@ static int via_rhine_close(struct net_device *dev); static inline void clear_tally_counters(long ioaddr); +static void wait_for_reset(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + int i; + + i = 0; + do { + udelay(5); + i++; + if(i > 2000) { + printk(KERN_ERR "%s: reset did not complete in 10 ms.\n", + dev->name); + break; + } + } while(readw(ioaddr + ChipCmd) & CmdReset); + if (debug > 1) + printk(KERN_INFO "%s: reset finished after %d microseconds.\n", + dev->name, 5*i); +} static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -451,14 +476,11 @@ struct netdev_private *np; int i, option; int chip_id = (int) ent->driver_data; - int irq = pdev->irq; static int card_idx = -1; static int did_version = 0; long ioaddr; int io_size; int pci_flags; - void *ring; - dma_addr_t ring_dma; /* print version once and once only */ if (! did_version++) { @@ -471,6 +493,9 @@ io_size = via_rhine_chip_info[chip_id].io_size; pci_flags = via_rhine_chip_info[chip_id].pci_flags; + if (pci_enable_device (pdev)) + goto err_out; + /* this should always be supported */ if (!pci_dma_supported(pdev, 0xffffffff)) { printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n"); @@ -484,20 +509,7 @@ goto err_out; } - /* allocate pci dma space for rx and tx descriptor rings */ - ring = pci_alloc_consistent(pdev, - RX_RING_SIZE * sizeof(struct rx_desc) + - TX_RING_SIZE * sizeof(struct tx_desc), - &ring_dma); - if (!ring) { - printk(KERN_ERR "Could not allocate DMA memory.\n"); - goto err_out; - } - ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1); - - if (pci_enable_device (pdev)) - goto err_out_free_dma; if (pci_flags & PCI_USES_MASTER) pci_set_master (pdev); @@ -506,26 +518,12 @@ if (dev == NULL) { printk (KERN_ERR "init_ethernet failed for card #%d\n", card_idx); - goto err_out_free_dma; + goto err_out; } SET_MODULE_OWNER(dev); - /* request all PIO and MMIO regions just to make sure - * noone else attempts to use any portion of our I/O space */ - if (!request_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0), dev->name)) { - printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n", - dev->name, io_size, - pci_resource_start (pdev, 0)); + if (pci_request_regions(pdev, dev->name)) goto err_out_free_netdev; - } - if (!request_mem_region (pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1), dev->name)) { - printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n", - dev->name, io_size, - pci_resource_start (pdev, 1)); - goto err_out_free_pio; - } #ifndef USE_IO ioaddr = (long) ioremap (ioaddr, io_size); @@ -533,7 +531,7 @@ printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n", dev->name, io_size, pci_resource_start (pdev, 1)); - goto err_out_free_mmio; + goto err_out_free_res; } #endif @@ -545,23 +543,20 @@ dev->dev_addr[i] = readb(ioaddr + StationAddr + i); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); /* Reset the chip to erase previous misconfiguration. */ writew(CmdReset, ioaddr + ChipCmd); + wait_for_reset(dev); dev->base_addr = ioaddr; - dev->irq = irq; + dev->irq = pdev->irq; np = dev->priv; spin_lock_init (&np->lock); np->chip_id = chip_id; np->drv_flags = via_rhine_chip_info[chip_id].drv_flags; np->pdev = pdev; - np->rx_ring = ring; - np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc); - np->rx_ring_dma = ring_dma; - np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); if (dev->mem_start) option = dev->mem_start; @@ -588,12 +583,12 @@ dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; np->phys[0] = 1; /* Standard for this chip. */ - for (phy = 1; phy < 32 && phy_idx < 4; phy++) { + for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; @@ -610,6 +605,7 @@ netif_carrier_off(dev); } } + np->mii_cnt = phy_idx; } return 0; @@ -617,27 +613,209 @@ #ifndef USE_IO /* note this is ifdef'd because the ioremap is ifdef'd... * so additional exit conditions above this must move - * release_mem_region outside of the ifdef */ -err_out_free_mmio: - release_mem_region(pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + * pci_release_regions outside of the ifdef */ +err_out_free_res: + pci_release_regions(pdev); #endif -err_out_free_pio: - release_region(pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); err_out_free_netdev: unregister_netdev (dev); kfree (dev); -err_out_free_dma: - pci_free_consistent(pdev, +err_out: + return -ENODEV; +} + +static int alloc_ring(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + void *ring; + dma_addr_t ring_dma; + + ring = pci_alloc_consistent(np->pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + &ring_dma); + if (!ring) { + printk(KERN_ERR "Could not allocate DMA memory.\n"); + return -ENOMEM; + } + np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, + &np->tx_bufs_dma); + if (np->tx_bufs == NULL) { + pci_free_consistent(np->pdev, RX_RING_SIZE * sizeof(struct rx_desc) + TX_RING_SIZE * sizeof(struct tx_desc), ring, ring_dma); -err_out: - return -ENODEV; + return -ENOMEM; + } + + np->rx_ring = ring; + np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc); + np->rx_ring_dma = ring_dma; + np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); + + + return 0; +} + +void free_ring(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + + pci_free_consistent(np->pdev, + RX_RING_SIZE * sizeof(struct rx_desc) + + TX_RING_SIZE * sizeof(struct tx_desc), + np->rx_ring, np->rx_ring_dma); + + pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, + np->tx_bufs, np->tx_bufs_dma); + } +static void alloc_rbufs(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + dma_addr_t next; + int i; + + np->dirty_rx = np->cur_rx = 0; + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_head_desc = &np->rx_ring[0]; + next = np->rx_ring_dma; + + /* Init the ring entries */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].rx_status = 0; + np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); + next += sizeof(struct rx_desc); + np->rx_ring[i].next_desc = cpu_to_le32(next); + np->rx_skbuff[i] = 0; + } + /* Mark the last entry as wrapping the ring. */ + np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + + np->rx_skbuff_dma[i] = + pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + + np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]); + np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); +} + +static void free_rbufs(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + int i; + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].rx_status = 0; + np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ + if (np->rx_skbuff[i]) { + pci_unmap_single(np->pdev, + np->rx_skbuff_dma[i], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } +} + +static void alloc_tbufs(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + dma_addr_t next; + int i; + + np->dirty_tx = np->cur_tx = 0; + next = np->tx_ring_dma; + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].tx_status = 0; + np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + next += sizeof(struct tx_desc); + np->tx_ring[i].next_desc = cpu_to_le32(next); + np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ]; + } + np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma); + +} + +static void free_tbufs(struct net_device* dev) +{ + struct netdev_private *np = dev->priv; + int i; + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].tx_status = 0; + np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); + np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ + if (np->tx_skbuff[i]) { + if (np->tx_skbuff_dma[i]) { + pci_unmap_single(np->pdev, + np->tx_skbuff_dma[i], + np->tx_skbuff[i]->len, PCI_DMA_TODEVICE); + } + dev_kfree_skb(np->tx_skbuff[i]); + } + np->tx_skbuff[i] = 0; + np->tx_buf[i] = 0; + } +} + +static void init_registers(struct net_device *dev) +{ + struct netdev_private *np = dev->priv; + long ioaddr = dev->base_addr; + int i; + + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + i); + + /* Initialize other registers. */ + writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ + /* Configure the FIFO thresholds. */ + writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */ + np->tx_thresh = 0x20; + np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + writel(np->rx_ring_dma, ioaddr + RxRingPtr); + writel(np->tx_ring_dma, ioaddr + TxRingPtr); + + via_rhine_set_rx_mode(dev); + + /* Enable interrupts by setting the interrupt mask. */ + writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| + IntrTxDone | IntrTxAbort | IntrTxUnderrun | + IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange, + ioaddr + IntrEnable); + + np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; + if (np->duplex_lock) + np->chip_cmd |= CmdFDuplex; + writew(np->chip_cmd, ioaddr + ChipCmd); + + via_rhine_check_duplex(dev); + + /* The LED outputs of various MII xcvrs should be configured. */ + /* For NS or Mison phys, turn on bit 1 in register 0x17 */ + /* For ESI phys, turn on bit 7 in register 0x17. */ + mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) | + (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001); +} /* Read and write over the MII Management Data I/O (MDIO) interface. */ static int mdio_read(struct net_device *dev, int phy_id, int regnum) @@ -660,7 +838,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int boguscnt = 1024; @@ -691,75 +869,36 @@ static int via_rhine_open(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; /* Reset the chip. */ writew(CmdReset, ioaddr + ChipCmd); - i = request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev); + i = request_irq(np->pdev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev); if (i) return i; if (debug > 1) printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n", - dev->name, dev->irq); - - np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, - &np->tx_bufs_dma); - if (np->tx_bufs == NULL) { - free_irq(dev->irq, dev); - return -ENOMEM; - } - - via_rhine_init_ring(dev); - - writel(np->rx_ring_dma, ioaddr + RxRingPtr); - writel(np->tx_ring_dma, ioaddr + TxRingPtr); - - for (i = 0; i < 6; i++) - writeb(dev->dev_addr[i], ioaddr + StationAddr + i); - - /* Initialize other registers. */ - writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ - /* Configure the FIFO thresholds. */ - writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */ - np->tx_thresh = 0x20; - np->rx_thresh = 0x60; /* Written in via_rhine_set_rx_mode(). */ - - if (dev->if_port == 0) - dev->if_port = np->default_port; - - netif_start_queue(dev); - - via_rhine_set_rx_mode(dev); - - /* Enable interrupts by setting the interrupt mask. */ - writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped| - IntrTxDone | IntrTxAbort | IntrTxUnderrun | - IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange, - ioaddr + IntrEnable); - - np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; - if (np->duplex_lock) - np->chip_cmd |= CmdFDuplex; - writew(np->chip_cmd, ioaddr + ChipCmd); - - via_rhine_check_duplex(dev); - - /* The LED outputs of various MII xcvrs should be configured. */ - /* For NS or Mison phys, turn on bit 1 in register 0x17 */ - /* For ESI phys, turn on bit 7 in register 0x17. */ - mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) | - (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001); - + dev->name, np->pdev->irq); + + i = alloc_ring(dev); + if (i) + return i; + alloc_rbufs(dev); + alloc_tbufs(dev); + wait_for_reset(dev); + init_registers(dev); if (debug > 2) printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x " "MII status: %4.4x.\n", dev->name, readw(ioaddr + ChipCmd), mdio_read(dev, np->phys[0], 1)); + netif_start_queue(dev); + /* Set the timer to check for link beat. */ init_timer(&np->timer); np->timer.expires = jiffies + 2; @@ -772,7 +911,7 @@ static void via_rhine_check_duplex(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int mii_reg5 = mdio_read(dev, np->phys[0], 5); int negotiated = mii_reg5 & np->advertising; @@ -799,7 +938,7 @@ static void via_rhine_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; int mii_status; @@ -832,92 +971,45 @@ static void via_rhine_tx_timeout (struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *) dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; - /* Lock to protect mdio_read and access to stats. A friendly - advice to the implementor of the XXXs in this function is to be - sure not to spin too long (whatever that means :) */ - spin_lock_irq (&np->lock); - printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status " "%4.4x, resetting...\n", dev->name, readw (ioaddr + IntrStatus), mdio_read (dev, np->phys[0], 1)); - /* XXX Perhaps we should reinitialize the hardware here. */ dev->if_port = 0; - /* Stop and restart the chip's Tx processes . */ - /* XXX to do */ - - /* Trigger an immediate transmit demand. */ - /* XXX to do */ - - dev->trans_start = jiffies; - np->stats.tx_errors++; - - spin_unlock_irq (&np->lock); -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void via_rhine_init_ring(struct net_device *dev) -{ - struct netdev_private *np = (struct netdev_private *)dev->priv; - int i; - dma_addr_t next = np->rx_ring_dma; - - np->cur_rx = np->cur_tx = 0; - np->dirty_rx = np->dirty_tx = 0; - - np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - np->rx_head_desc = &np->rx_ring[0]; - - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz); - next += sizeof(struct rx_desc); - np->rx_ring[i].next_desc = cpu_to_le32(next); - np->rx_skbuff[i] = 0; - } - /* Mark the last entry as wrapping the ring. */ - np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma); - - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ + /* protect against concurrent rx interrupts */ + disable_irq(np->pdev->irq); - np->rx_skbuff_dma[i] = - pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, - PCI_DMA_FROMDEVICE); + spin_lock(&np->lock); - np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]); - np->rx_ring[i].rx_status = cpu_to_le32(DescOwn); - } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + /* Reset the chip. */ + writew(CmdReset, ioaddr + ChipCmd); - next = np->tx_ring_dma; - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_skbuff[i] = 0; - np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); - next += sizeof(struct tx_desc); - np->tx_ring[i].next_desc = cpu_to_le32(next); - np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ]; - } - np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma); + /* clear all descriptors */ + free_tbufs(dev); + free_rbufs(dev); + alloc_tbufs(dev); + alloc_rbufs(dev); + + /* Reinitialize the hardware. */ + wait_for_reset(dev); + init_registers(dev); + + spin_unlock(&np->lock); + enable_irq(np->pdev->irq); - return; + dev->trans_start = jiffies; + np->stats.tx_errors++; + netif_wake_queue(dev); } static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; unsigned entry; /* Caution: the write order is important here, set the field @@ -1017,7 +1109,7 @@ for clarity. */ static void via_rhine_tx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE; spin_lock (&np->lock); @@ -1066,7 +1158,7 @@ for clarity and better register allocation. */ static void via_rhine_rx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int entry = np->cur_rx % RX_RING_SIZE; int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; @@ -1149,7 +1241,7 @@ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; - np->stats.rx_bytes += skb->len; + np->stats.rx_bytes += pkt_len; np->stats.rx_packets++; } entry = (++np->cur_rx) % RX_RING_SIZE; @@ -1180,7 +1272,7 @@ static void via_rhine_error(struct net_device *dev, int intr_status) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; spin_lock (&np->lock); @@ -1215,8 +1307,9 @@ "threshold setting to %2.2x.\n", dev->name, np->tx_thresh); } if ((intr_status & ~( IntrLinkChange | IntrStatsMax | - IntrTxAbort | IntrTxAborted)) && debug > 1) { - printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + IntrTxAbort | IntrTxAborted))) { + if (debug > 1) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); /* Recovery for other fault sources not known. */ writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd); @@ -1227,7 +1320,7 @@ static struct net_device_stats *via_rhine_get_stats(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; unsigned long flags; @@ -1273,7 +1366,7 @@ static void via_rhine_set_rx_mode(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; u32 mc_filter[2]; /* Multicast hash filter */ u8 rx_mode; /* Note: 0x02=accept runt, 0x01=accept errs */ @@ -1305,7 +1398,7 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; u16 *data = (u16 *)&rq->ifr_data; unsigned long flags; int retval; @@ -1338,13 +1431,11 @@ static int via_rhine_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; - int i; - unsigned long flags; + struct netdev_private *np = dev->priv; del_timer_sync(&np->timer); - spin_lock_irqsave(&np->lock, flags); + spin_lock_irq(&np->lock); netif_stop_queue(dev); @@ -1361,44 +1452,12 @@ /* Stop the chip's Tx and Rx processes. */ writew(CmdStop, ioaddr + ChipCmd); - spin_unlock_irqrestore(&np->lock, flags); - - /* Make sure there is no irq-handler running on a different CPU. */ - synchronize_irq(); + spin_unlock_irq(&np->lock); - free_irq(dev->irq, dev); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].rx_status = 0; - np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ - if (np->rx_skbuff[i]) { - pci_unmap_single(np->pdev, - np->rx_skbuff_dma[i], - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - dev_kfree_skb(np->rx_skbuff[i]); - } - np->rx_skbuff[i] = 0; - } - - /* Free all the skbuffs in the Tx queue, and also any bounce buffers. */ - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_ring[i].tx_status = 0; - np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000); - np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ - if (np->tx_skbuff[i]) { - if (np->tx_skbuff_dma[i]) { - pci_unmap_single(np->pdev, - np->tx_skbuff_dma[i], - np->tx_skbuff[i]->len, PCI_DMA_TODEVICE); - } - dev_kfree_skb(np->tx_skbuff[i]); - } - np->tx_skbuff[i] = 0; - np->tx_buf[i] = 0; - } - pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE, - np->tx_bufs, np->tx_bufs_dma); + free_irq(np->pdev->irq, dev); + free_rbufs(dev); + free_tbufs(dev); + free_ring(dev); return 0; } @@ -1406,15 +1465,12 @@ static void __devexit via_rhine_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct netdev_private *np = (struct netdev_private *)(dev->priv); unregister_netdev(dev); - release_region(pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - release_mem_region(pci_resource_start (pdev, 1), - pci_resource_len (pdev, 1)); + pci_release_regions(pdev); #ifndef USE_IO iounmap((char *)(dev->base_addr)); @@ -1426,6 +1482,8 @@ np->rx_ring, np->rx_ring_dma); kfree(dev); + + pci_set_drvdata(pdev, NULL); } diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in --- v2.4.2/linux/drivers/net/wan/Config.in Fri Aug 11 17:14:23 2000 +++ linux/drivers/net/wan/Config.in Tue Mar 6 19:44:37 2001 @@ -33,6 +33,11 @@ fi dep_tristate ' Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX fi +# +# The Etinc driver has not been tested as non-modular yet. +# + + dep_tristate ' Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m # # Lan Media's board. Currently 1000, 1200, 5200, 5245 @@ -45,6 +50,18 @@ dep_tristate ' Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m dep_tristate ' SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m + + tristate ' Generic HDLC driver' CONFIG_HDLC + if [ "$CONFIG_HDLC" != "n" ]; then + bool ' Synchronous Point-to-Point Protocol (PPP) support' CONFIG_HDLC_PPP + if [ "$CONFIG_LAPB" = "m" -a "$CONFIG_HDLC" = "m" -o "$CONFIG_LAPB" = "y" ]; then + bool ' X.25 protocol support' CONFIG_HDLC_X25 + else + comment ' X.25/LAPB support is disabled' + fi + dep_tristate ' SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC + dep_tristate ' Moxa C101 support' CONFIG_C101 $CONFIG_HDLC + fi tristate ' Frame relay DLCI support' CONFIG_DLCI if [ "$CONFIG_DLCI" != "n" ]; then diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile --- v2.4.2/linux/drivers/net/wan/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/net/wan/Makefile Tue Mar 6 19:44:37 2001 @@ -9,7 +9,7 @@ O_TARGET := wan.o -export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o +export-objs = z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o list-multi = wanpipe.o cyclomx.o wanpipe-objs = sdlamain.o $(wanpipe-y) @@ -32,6 +32,7 @@ obj-$(CONFIG_COMX_PROTO_LAPB) += comx-proto-lapb.o obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o obj-$(CONFIG_COSA) += syncppp.o cosa.o +obj-$(CONFIG_DSCC4) += dscc4.o obj-$(CONFIG_LANMEDIA) += syncppp.o obj-$(CONFIG_SYNCLINK_SYNCPPP) += syncppp.o obj-$(CONFIG_X25_ASY) += x25_asy.o @@ -48,6 +49,10 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o +obj-$(CONFIG_HDLC) += hdlc.o +obj-$(CONFIG_HDLC_PPP) += syncppp.o +obj-$(CONFIG_N2) += n2.o +obj-$(CONFIG_C101) += c101.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/c101.c linux/drivers/net/wan/c101.c --- v2.4.2/linux/drivers/net/wan/c101.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/c101.c Tue Mar 6 19:44:36 2001 @@ -0,0 +1,375 @@ +/* + * Moxa C101 synchronous serial card driver for Linux + * + * Copyright (C) 2000 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * For information see http://hq.pm.waw.pl/hdlc/ + * + * Sources of information: + * Hitachi HD64570 SCA User's Manual + * Moxa C101 User's Manual + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hd64570.h" + +#define DEBUG_RINGS +/* #define DEBUG_PKT */ + +static const char* version = "Moxa C101 driver revision: 1.02 for Linux 2.4"; +static const char* devname = "C101"; + +#define C101_PAGE 0x1D00 +#define C101_DTR 0x1E00 +#define C101_SCA 0x1F00 +#define C101_WINDOW_SIZE 0x2000 +#define C101_MAPPED_RAM_SIZE 0x4000 + +#define RAM_SIZE (256 * 1024) +#define CLOCK_BASE 9830400 /* 9.8304 MHz */ +#define PAGE0_ALWAYS_MAPPED + +static char *hw; /* pointer to hw=xxx command line string */ + + +typedef struct card_s { + hdlc_device hdlc; /* HDLC device struct - must be first */ + spinlock_t lock; /* TX lock */ + int clkmode; /* clock mode */ + int clkrate; /* clock speed */ + int line; /* loopback only */ + u8 *win0base; /* ISA window base address */ + u32 phy_winbase; /* ISA physical base address */ + u16 buff_offset; /* offset of first buffer of first channel */ + u8 rxs, txs, tmc; /* SCA registers */ + u8 irq; /* IRQ (3-15) */ + u8 ring_buffers; /* number of buffers in a ring */ + u8 page; + + u8 rxin; /* rx ring buffer 'in' pointer */ + u8 txin; /* tx ring buffer 'in' and 'last' pointers */ + u8 txlast; + u8 rxpart; /* partial frame received, next frame invalid*/ + + struct card_s *next_card; +}card_t; + +typedef card_t port_t; + + +#define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg)) +#define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg)) +#define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg)) +#define sca_outw(value, reg, card) writew(value, (card)->win0base + C101_SCA + (reg)) + +#define port_to_card(port) (port) +#define log_node(port) (0) +#define phy_node(port) (0) +#define winsize(card) (C101_WINDOW_SIZE) +#define win0base(card) ((card)->win0base) +#define winbase(card) ((card)->win0base + 0x2000) +#define get_port(card, port) ((port) == 0 ? (card) : NULL) + + +static inline u8 sca_get_page(card_t *card) +{ + return card->page; +} + +static inline void openwin(card_t *card, u8 page) +{ + card->page = page; + writeb(page, card->win0base + C101_PAGE); +} + + +#define close_windows(card) {} /* no hardware support */ + + +#include "hd6457x.c" + + +static int c101_set_clock(port_t *port, int value) +{ + u8 msci = get_msci(port); + u8 rxs = port->rxs & CLK_BRG_MASK; + u8 txs = port->txs & CLK_BRG_MASK; + + switch(value) { + case CLOCK_EXT: + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_LINE_TX; /* TXC input */ + break; + + case CLOCK_INT: + rxs |= CLK_BRG_RX; /* TX clock */ + txs |= CLK_RXCLK_TX; /* BRG output */ + break; + + case CLOCK_TXINT: + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_BRG_TX; /* BRG output */ + break; + + case CLOCK_TXFROMRX: + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_RXCLK_TX; /* RX clock */ + break; + + default: + return -EINVAL; + } + + port->rxs = rxs; + port->txs = txs; + sca_out(rxs, msci + RXS, port); + sca_out(txs, msci + TXS, port); + port->clkmode = value; + return 0; +} + + +static int c101_open(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + + MOD_INC_USE_COUNT; + writeb(1, port->win0base + C101_DTR); + sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ + sca_open(hdlc); + c101_set_clock(port, port->clkmode); + return 0; +} + + +static void c101_close(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + + sca_close(hdlc); + writeb(0, port->win0base + C101_DTR); + sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port); + MOD_DEC_USE_COUNT; +} + + +static int c101_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd) +{ + int value = ifr->ifr_ifru.ifru_ivalue; + int result = 0; + port_t *port = hdlc_to_port(hdlc); + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch(cmd) { + case HDLCSCLOCK: + result = c101_set_clock(port, value); + case HDLCGCLOCK: + value = port->clkmode; + break; + + case HDLCSCLOCKRATE: + port->clkrate = value; + sca_set_clock(port); + case HDLCGCLOCKRATE: + value = port->clkrate; + break; + + case HDLCSLINE: + result = sca_set_loopback(port, value); + case HDLCGLINE: + value = port->line; + break; + +#ifdef DEBUG_RINGS + case HDLCRUN: + sca_dump_rings(hdlc); + return 0; +#endif /* DEBUG_RINGS */ + + default: + return -EINVAL; + } + + ifr->ifr_ifru.ifru_ivalue = value; + return result; +} + + + +static void c101_destroy_card(card_t *card) +{ + if (card->irq) + free_irq(card->irq, card); + + if (card->win0base) { + iounmap(card->win0base); + release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE); + } + + kfree(card); +} + + + +static int c101_run(unsigned long irq, unsigned long winbase) +{ + card_t *card; + int result; + + if (irq<3 || irq>15 || irq == 6) /* FIXME */ { + printk(KERN_ERR "c101: invalid IRQ value\n"); + return -ENODEV; + } + + if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) { + printk(KERN_ERR "c101: invalid RAM value\n"); + return -ENODEV; + } + + card = kmalloc(sizeof(card_t), GFP_KERNEL); + if (card == NULL) { + printk(KERN_ERR "c101: unable to allocate memory\n"); + return -ENOBUFS; + } + memset(card, 0, sizeof(card_t)); + + if (request_irq(irq, sca_intr, 0, devname, card)) { + printk(KERN_ERR "c101: could not allocate IRQ\n"); + c101_destroy_card(card); + return(-EBUSY); + } + card->irq = irq; + + if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) { + printk(KERN_ERR "c101: could not request RAM window\n"); + c101_destroy_card(card); + return(-EBUSY); + } + card->phy_winbase = winbase; + card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE); + if (!card->win0base) { + printk(KERN_ERR "c101: could not map I/O address\n"); + c101_destroy_card(card); + return -EBUSY; + } + + /* 2 rings required for 1 port */ + card->ring_buffers = (RAM_SIZE -C101_WINDOW_SIZE) / (2 * HDLC_MAX_MRU); + printk(KERN_DEBUG "c101: using %u packets rings\n",card->ring_buffers); + + card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ + + readb(card->win0base + C101_PAGE); /* Resets SCA? */ + udelay(100); + writeb(0, card->win0base + C101_PAGE); + writeb(0, card->win0base + C101_DTR); /* Power-up for RAM? */ + + sca_init(card, 0); + + spin_lock_init(&card->lock); + hdlc_to_dev(&card->hdlc)->irq = irq; + hdlc_to_dev(&card->hdlc)->mem_start = winbase; + hdlc_to_dev(&card->hdlc)->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1; + hdlc_to_dev(&card->hdlc)->tx_queue_len = 50; + card->hdlc.ioctl = c101_ioctl; + card->hdlc.open = c101_open; + card->hdlc.close = c101_close; + card->hdlc.xmit = sca_xmit; + + result = register_hdlc_device(&card->hdlc); + if (result) { + printk(KERN_WARNING "c101: unable to register hdlc device\n"); + c101_destroy_card(card); + return result; + } + + sca_init_sync_port(card); /* Set up C101 memory */ + + *new_card = card; + new_card = &card->next_card; + return 0; +} + + + +static int __init c101_init(void) +{ + if (hw == NULL) { +#ifdef MODULE + printk(KERN_INFO "c101: no card initialized\n"); +#endif + return -ENOSYS; /* no parameters specified, abort */ + } + + printk(KERN_INFO "%s\n", version); + + do { + unsigned long irq, ram; + + irq = simple_strtoul(hw, &hw, 0); + + if (*hw++ != ',') + break; + ram = simple_strtoul(hw, &hw, 0); + + if (*hw == ':' || *hw == '\x0') + c101_run(irq, ram); + + if (*hw == '\x0') + return 0; + }while(*hw++ == ':'); + + printk(KERN_ERR "c101: invalid hardware parameters\n"); + return first_card ? 0 : -ENOSYS; +} + + +#ifndef MODULE +static int __init c101_setup(char *str) +{ + hw = str; + return 1; +} + +__setup("c101=", c101_setup); +#endif + + +static void __exit c101_cleanup(void) +{ + card_t *card = first_card; + + while (card) { + card_t *ptr = card; + card = card->next_card; + unregister_hdlc_device(&ptr->hdlc); + c101_destroy_card(ptr); + } +} + + +module_init(c101_init); +module_exit(c101_cleanup); + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Moxa C101 serial port driver"); +MODULE_PARM(hw, "s"); /* hw=irq,ram:irq,... */ +EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/comx-proto-fr.c linux/drivers/net/wan/comx-proto-fr.c --- v2.4.2/linux/drivers/net/wan/comx-proto-fr.c Mon Sep 18 15:02:03 2000 +++ linux/drivers/net/wan/comx-proto-fr.c Sat Mar 3 10:55:48 2001 @@ -505,9 +505,9 @@ struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC); newskb->dev=fr->master; dev_queue_xmit(newskb); - dev_kfree_skb(skb); - ch->stats.tx_packets++; ch->stats.tx_bytes += skb->len; + ch->stats.tx_packets++; + dev_kfree_skb(skb); } else { netif_stop_queue(dev); for (; dir ; dir = dir->next) { diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/comx-proto-lapb.c linux/drivers/net/wan/comx-proto-lapb.c --- v2.4.2/linux/drivers/net/wan/comx-proto-lapb.c Sat Nov 11 19:02:39 2000 +++ linux/drivers/net/wan/comx-proto-lapb.c Sat Mar 3 10:55:48 2001 @@ -311,6 +311,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + ch->dev->last_rx = jiffies; } for (; comxdir; comxdir = comxdir->next) { @@ -350,6 +351,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + ch->dev->last_rx = jiffies; } for (; comxdir; comxdir = comxdir->next) { diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/comx-proto-ppp.c linux/drivers/net/wan/comx-proto-ppp.c --- v2.4.2/linux/drivers/net/wan/comx-proto-ppp.c Mon Sep 18 15:02:03 2000 +++ linux/drivers/net/wan/comx-proto-ppp.c Tue Mar 6 19:44:36 2001 @@ -44,7 +44,7 @@ #include #include -#include "syncppp.h" +#include #include "comx.h" MODULE_AUTHOR("Author: Gergely Madarasz "); diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c --- v2.4.2/linux/drivers/net/wan/comx.c Thu Nov 16 14:08:25 2000 +++ linux/drivers/net/wan/comx.c Tue Mar 6 19:44:36 2001 @@ -73,8 +73,8 @@ #error For now, COMX really needs the /proc filesystem #endif +#include #include "comx.h" -#include "syncppp.h" MODULE_AUTHOR("Gergely Madarasz "); MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters"); @@ -380,6 +380,7 @@ } if (skb) { netif_rx(skb); + dev->last_rx = jiffies; } return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c --- v2.4.2/linux/drivers/net/wan/cosa.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/wan/cosa.c Tue Mar 6 19:44:36 2001 @@ -102,7 +102,7 @@ #include #include -#include "syncppp.h" +#include #include "cosa.h" /* Linux version stuff */ @@ -220,9 +220,9 @@ #define COSA_MTU 2000 /* FIXME: I don't know this exactly */ -#undef DEBUG_DATA 1 /* Dump the data read or written to the channel */ -#undef DEBUG_IRQS 1 /* Print the message when the IRQ is received */ -#undef DEBUG_IO 1 /* Dump the I/O traffic */ +#undef DEBUG_DATA //1 /* Dump the data read or written to the channel */ +#undef DEBUG_IRQS //1 /* Print the message when the IRQ is received */ +#undef DEBUG_IO //1 /* Dump the I/O traffic */ #define TX_TIMEOUT (5*HZ) @@ -745,7 +745,7 @@ chan->stats.rx_bytes += chan->cosa->rxsize; netif_rx(chan->rx_skb); chan->rx_skb = 0; - chan->pppdev.dev->trans_start = jiffies; + chan->pppdev.dev->last_rx = jiffies; return 0; } @@ -836,7 +836,7 @@ up(&chan->rsem); if (copy_to_user(buf, kbuf, count)) { - kfree(buf); + kfree(kbuf); return -EFAULT; } kfree(kbuf); @@ -2011,7 +2011,7 @@ /* ---------- I/O debugging routines ---------- */ /* * These routines can be used to monitor COSA/SRP I/O and to printk() - * the data being transfered on the data and status I/O port in a + * the data being transferred on the data and status I/O port in a * readable way. */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/cosa.h linux/drivers/net/wan/cosa.h --- v2.4.2/linux/drivers/net/wan/cosa.h Mon Oct 11 10:13:25 1999 +++ linux/drivers/net/wan/cosa.h Tue Mar 6 19:44:36 2001 @@ -33,7 +33,7 @@ #define SR_RX_INT_ENA 0x80 /* receiver interrupt enable bit */ /* status register - input bits */ -#define SR_USR_RQ 0x20 /* user interupt request pending */ +#define SR_USR_RQ 0x20 /* user interrupt request pending */ #define SR_TX_RDY 0x40 /* transmitter empty (ready) */ #define SR_RX_RDY 0x80 /* receiver data ready */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c --- v2.4.2/linux/drivers/net/wan/cycx_x25.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/wan/cycx_x25.c Sat Mar 3 10:55:48 2001 @@ -3,7 +3,7 @@ * * Author: Arnaldo Carvalho de Melo * -* Copyright: (c) 1998-2000 Arnaldo Carvalho de Melo +* Copyright: (c) 1998-2001 Arnaldo Carvalho de Melo * * Based on sdla_x25.c by Gene Kozin * @@ -12,6 +12,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* 2001/01/12 acme use dev_kfree_skb_irq on interrupt context * 2000/04/02 acme dprintk, cycx_debug * fixed the bug introduced in get_dev_by_lcn and * get_dev_by_dte_addr by the anonymous hacker @@ -794,7 +795,7 @@ if (skb_tailroom(skb) < pktlen) { /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); chan->rx_skb = NULL; if (bitm) @@ -812,14 +813,14 @@ if (bitm) return; /* more data is coming */ - dev->last_rx = jiffies; /* timestamp */ chan->rx_skb = NULL; /* dequeue packet */ ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; + chan->ifstats.rx_bytes += pktlen; skb->mac.raw = skb->data; netif_rx(skb); + dev->last_rx = jiffies; /* timestamp */ } /* Connect interrupt handler. */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c --- v2.4.2/linux/drivers/net/wan/dlci.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/wan/dlci.c Sat Mar 3 10:55:48 2001 @@ -227,8 +227,10 @@ /* we've set up the protocol, so discard the header */ skb->mac.raw = skb->data; skb_pull(skb, header); + dlp->stats.rx_bytes += skb->len; netif_rx(skb); dlp->stats.rx_packets++; + dev->last_rx = jiffies; } else dev_kfree_skb(skb); diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/dscc4.c linux/drivers/net/wan/dscc4.c --- v2.4.2/linux/drivers/net/wan/dscc4.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/dscc4.c Tue Mar 6 19:44:36 2001 @@ -0,0 +1,1769 @@ +/* + * drivers/net/wan/dscc4/dscc4_main.c: a DSCC4 HDLC driver for Linux + * + * This software may be used and distributed according to the terms of the + * GNU Public License. + * + * The author may be reached as romieu@cogenit.fr. + * Specific bug reports/asian food will be welcome. + * + * Special thanks to the nice people at CS-Telecom for the hardware and the + * access to the test/measure tools. + * + * + * Theory of Operation + * + * I. Board Compatibility + * + * This device driver is designed for the Siemens PEB20534 4 ports serial + * controller as found on Etinc PCISYNC cards. The documentation for the + * chipset is available at http://www.infineon.com: + * - Data Sheet "DSCC4, DMA Supported Serial Communication Controller with + * 4 Channels, PEB 20534 Version 2.1, PEF 20534 Version 2.1"; + * - Application Hint "Management of DSCC4 on-chip FIFO resources". + * Jens David has built an adapter based on the same chipset. Take a look + * at http://www.afthd.tu-darmstadt.de/~dg1kjd/pciscc4 for a specific + * driver. + * Sample code (2 revisions) is available at Infineon. + * + * II. Board-specific settings + * + * Pcisync can transmit some clock signal to the outside world on the + * *first two* ports provided you put a quartz and a line driver on it and + * remove the jumpers. The operation is described on Etinc web site. If you + * go DCE on these ports, don't forget to use an adequate cable. + * + * Sharing of the PCI interrupt line for this board is possible. + * + * III. Driver operation + * + * The rx/tx operations are based on a linked list of descriptor. I haven't + * tried the start/stop descriptor method as this one looks like the cheapest + * in terms of PCI manipulation. + * + * Tx direction + * Once the data section of the current descriptor processed, the next linked + * descriptor is loaded if the HOLD bit isn't set in the current descriptor. + * If HOLD is met, the transmission is stopped until the host unsets it and + * signals the change via TxPOLL. + * When the tx ring is full, the xmit routine issues a call to netdev_stop. + * The device is supposed to be enabled again during an ALLS irq (we could + * use HI but as it's easy to loose events, it's fscked). + * + * Rx direction + * The received frames aren't supposed to span over multiple receiving areas. + * I may implement it some day but it isn't the highest ranked item. + * + * IV. Notes + * The chipset is buggy. Typically, under some specific load patterns (I + * wouldn't call them "high"), the irq queues and the descriptors look like + * some event has been lost. Even assuming some fancy PCI feature, it won't + * explain the reproductible missing "C" bit in the descriptors. Faking an + * irq in the periodic timer isn't really elegant but at least it seems + * reliable. + * The current error (XDU, RFO) recovery code is untested. + * So far, RDO takes his RX channel down and the right sequence to enable it + * again is still a mistery. If RDO happens, plan a reboot. More details + * in the code (NB: as this happens, TX still works). + * Don't mess the cables during operation, especially on DTE ports. I don't + * suggest it for DCE either but at least one can get some messages instead + * of a complete instant freeze. + * Tests are done on Rev. 20 of the silicium. The RDO handling changes with + * the documentation/chipset releases. An on-line errata would be welcome. + * + * TODO: + * - some trivial error lurk, + * - the stats are fscked, + * - use polling at high irq/s, + * - performance analysis, + * - endianness. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Version */ +static const char * version = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n"; +static int debug; + + +/* Module parameters */ +MODULE_AUTHOR("Maintainer: Francois Romieu "); +MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller"); +MODULE_PARM(debug,"i"); + +/* Structures */ +struct TxFD { + u32 state; + u32 next; + u32 data; + u32 complete; + u32 jiffies; /* more hack to come :o) */ +}; + +struct RxFD { + u32 state1; + u32 next; + u32 data; + u32 state2; + u32 end; +}; + +#define DEBUG +#define DEBUG_PARANOID +#define TX_RING_SIZE 32 +#define RX_RING_SIZE 32 +#define IRQ_RING_SIZE 64 /* Keep it A multiple of 32 */ +#define TX_TIMEOUT (HZ/10) +#define BRR_DIVIDER_MAX 64*0x00008000 +#define dev_per_card 4 + +#define SOURCE_ID(flags) ((flags >> 28 ) & 0x03) +#define TO_SIZE(state) ((state >> 16) & 0x1fff) +#define TO_STATE(len) cpu_to_le32((len & TxSizeMax) << 16) +#define RX_MAX(len) ((((len) >> 5) + 1) << 5) +#define SCC_REG_START(id) SCC_START+(id)*SCC_OFFSET + +#undef DEBUG + +struct dscc4_pci_priv { + u32 *iqcfg; + int cfg_cur; + spinlock_t lock; + struct pci_dev *pdev; + + struct net_device *root; + dma_addr_t iqcfg_dma; + u32 xtal_hz; +}; + +struct dscc4_dev_priv { + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + + struct RxFD *rx_fd; + struct TxFD *tx_fd; + u32 *iqrx; + u32 *iqtx; + + u32 rx_current; + u32 tx_current; + u32 iqrx_current; + u32 iqtx_current; + + u32 tx_dirty; + int bad_tx_frame; + int bad_rx_frame; + int rx_needs_refill; + + dma_addr_t tx_fd_dma; + dma_addr_t rx_fd_dma; + dma_addr_t iqtx_dma; + dma_addr_t iqrx_dma; + + struct net_device_stats stats; + struct timer_list timer; + + struct dscc4_pci_priv *pci_priv; + spinlock_t lock; + + int dev_id; + u32 flags; + u32 timer_help; + u32 hi_expected; + + struct hdlc_device_struct hdlc; + int usecount; +}; + +/* GLOBAL registers definitions */ +#define GCMDR 0x00 +#define GSTAR 0x04 +#define GMODE 0x08 +#define IQLENR0 0x0C +#define IQLENR1 0x10 +#define IQRX0 0x14 +#define IQTX0 0x24 +#define IQCFG 0x3c +#define FIFOCR1 0x44 +#define FIFOCR2 0x48 +#define FIFOCR3 0x4c +#define FIFOCR4 0x34 +#define CH0CFG 0x50 +#define CH0BRDA 0x54 +#define CH0BTDA 0x58 + +/* SCC registers definitions */ +#define SCC_START 0x0100 +#define SCC_OFFSET 0x80 +#define CMDR 0x00 +#define STAR 0x04 +#define CCR0 0x08 +#define CCR1 0x0c +#define CCR2 0x10 +#define BRR 0x2C +#define RLCR 0x40 +#define IMR 0x54 +#define ISR 0x58 + +/* Bit masks */ +#define IntRxScc0 0x10000000 +#define IntTxScc0 0x01000000 + +#define TxPollCmd 0x00000400 +#define RxActivate 0x08000000 +#define MTFi 0x04000000 +#define Rdr 0x00400000 +#define Rdt 0x00200000 +#define Idr 0x00100000 +#define Idt 0x00080000 +#define TxSccRes 0x01000000 +#define RxSccRes 0x00010000 +#define TxSizeMax 0x1ffc +#define RxSizeMax 0x1ffc + +#define Ccr0ClockMask 0x0000003f +#define Ccr1LoopMask 0x00000200 +#define BrrExpMask 0x00000f00 +#define BrrMultMask 0x0000003f +#define EncodingMask 0x00700000 +#define Hold 0x40000000 +#define SccBusy 0x10000000 +#define FrameOk (FrameVfr | FrameCrc) +#define FrameVfr 0x80 +#define FrameRdo 0x40 +#define FrameCrc 0x20 +#define FrameAborted 0x00000200 +#define FrameEnd 0x80000000 +#define DataComplete 0x40000000 +#define LengthCheck 0x00008000 +#define SccEvt 0x02000000 +#define NoAck 0x00000200 +#define Action 0x00000001 +#define HiDesc 0x20000000 + +/* SCC events */ +#define RxEvt 0xf0000000 +#define TxEvt 0x0f000000 +#define Alls 0x00040000 +#define Xdu 0x00010000 +#define Xmr 0x00002000 +#define Xpr 0x00001000 +#define Rdo 0x00000080 +#define Rfs 0x00000040 +#define Rfo 0x00000002 +#define Flex 0x00000001 + +/* DMA core events */ +#define Cfg 0x00200000 +#define Hi 0x00040000 +#define Fi 0x00020000 +#define Err 0x00010000 +#define Arf 0x00000002 +#define ArAck 0x00000001 + +/* Misc */ +#define NeedIDR 0x00000001 +#define NeedIDT 0x00000002 +#define RdoSet 0x00000004 + +/* Functions prototypes */ +static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *, struct net_device *); +static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *, struct net_device *); +static int dscc4_found1(struct pci_dev *, unsigned long ioaddr); +static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent); +static int dscc4_open(struct net_device *); +static int dscc4_start_xmit(struct sk_buff *, struct net_device *); +static int dscc4_close(struct net_device *); +static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int dscc4_change_mtu(struct net_device *dev, int mtu); +static int dscc4_init_ring(struct net_device *); +static void dscc4_release_ring(struct dscc4_dev_priv *); +static void dscc4_timer(unsigned long); +static void dscc4_tx_timeout(struct net_device *); +static void dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs); +static struct net_device_stats *dscc4_get_stats(struct net_device *); +static int dscc4_attach_hdlc_device(struct net_device *); +static void dscc4_unattach_hdlc_device(struct net_device *); +static int dscc4_hdlc_open(struct hdlc_device_struct *); +static void dscc4_hdlc_close(struct hdlc_device_struct *); +static int dscc4_hdlc_ioctl(struct hdlc_device_struct *, struct ifreq *, int); +static int dscc4_hdlc_xmit(hdlc_device *, struct sk_buff *); +#ifdef EXPERIMENTAL_POLLING +static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *); +#endif + +void inline reset_TxFD(struct TxFD *tx_fd) { + /* FIXME: test with the last arg (size specification) = 0 */ + tx_fd->state = FrameEnd | Hold | 0x00100000; + tx_fd->complete = 0x00000000; +} + +void inline dscc4_release_ring_skbuff(struct sk_buff **p, int n) +{ + for(; n > 0; n--) { + if (*p) + dev_kfree_skb(*p); + p++; + } +} + +static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) +{ + struct pci_dev *pdev = dpriv->pci_priv->pdev; + + pci_free_consistent(pdev, TX_RING_SIZE*sizeof(struct TxFD), + dpriv->tx_fd, dpriv->tx_fd_dma); + pci_free_consistent(pdev, RX_RING_SIZE*sizeof(struct RxFD), + dpriv->rx_fd, dpriv->rx_fd_dma); + dscc4_release_ring_skbuff(dpriv->tx_skbuff, TX_RING_SIZE); + dscc4_release_ring_skbuff(dpriv->rx_skbuff, RX_RING_SIZE); +} + +void inline try_get_rx_skb(struct dscc4_dev_priv *priv, int cur, struct net_device *dev) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(RX_MAX(dev->mtu+2)); + priv->rx_skbuff[cur] = skb; + if (!skb) { + priv->rx_fd[cur--].data = (u32) NULL; + priv->rx_fd[cur%RX_RING_SIZE].state1 |= Hold; + priv->rx_needs_refill++; + return; + } + skb->dev = dev; + skb->protocol = htons(ETH_P_IP); + skb->mac.raw = skb->data; + priv->rx_fd[cur].data = pci_map_single(priv->pci_priv->pdev, skb->data, + skb->len, PCI_DMA_FROMDEVICE); +} + +/* + * IRQ/thread/whatever safe + */ +static int dscc4_wait_ack_cec(u32 ioaddr, struct net_device *dev, char *msg) +{ + s16 i = 0; + + while (readl(ioaddr + STAR) & SccBusy) { + if (i++ < 0) { + printk(KERN_ERR "%s: %s timeout\n", dev->name, msg); + return -1; + } + } + printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name, msg, i); + return 0; +} + +static int dscc4_do_action(struct net_device *dev, char *msg) +{ + unsigned long ioaddr = dev->base_addr; + u32 state; + s16 i; + + writel(Action, ioaddr + GCMDR); + ioaddr += GSTAR; + for (i = 0; i >= 0; i++) { + state = readl(ioaddr); + if (state & Arf) { + printk(KERN_ERR "%s: %s failed\n", dev->name, msg); + writel(Arf, ioaddr); + return -1; + } else if (state & ArAck) { + printk(KERN_DEBUG "%s: %s ack (%d try)\n", + dev->name, msg, i); + writel(ArAck, ioaddr); + return 0; + } + } + printk(KERN_ERR "%s: %s timeout\n", dev->name, msg); + return -1; +} + +static __inline__ int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv) +{ + int cur; + s16 i; + + cur = dpriv->iqtx_current%IRQ_RING_SIZE; + for (i = 0; i >= 0; i++) { + if (!(dpriv->flags & (NeedIDR | NeedIDT)) || + (dpriv->iqtx[cur] & Xpr)) + return 0; + } + printk(KERN_ERR "%s: %s timeout\n", "dscc4", "XPR"); + return -1; +} + +static __inline__ void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur, + struct RxFD *rx_fd, struct net_device *dev) +{ + struct pci_dev *pdev = dpriv->pci_priv->pdev; + struct sk_buff *skb; + int pkt_len; + + skb = dpriv->rx_skbuff[cur]; + pkt_len = TO_SIZE(rx_fd->state2); + pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE); + if((skb->data[pkt_len - 1] & FrameOk) == FrameOk) { + pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE); + dpriv->stats.rx_packets++; + dpriv->stats.rx_bytes += pkt_len; + skb->tail += pkt_len; + skb->len = pkt_len; + if (netif_running(hdlc_to_dev(&dpriv->hdlc))) + hdlc_netif_rx(&dpriv->hdlc, skb); + else + netif_rx(skb); + try_get_rx_skb(dpriv, cur, dev); + } else { + if(skb->data[pkt_len - 1] & FrameRdo) + dpriv->stats.rx_fifo_errors++; + else if(!(skb->data[pkt_len - 1] | ~FrameCrc)) + dpriv->stats.rx_crc_errors++; + else if(!(skb->data[pkt_len - 1] | ~FrameVfr)) + dpriv->stats.rx_length_errors++; + else + dpriv->stats.rx_errors++; + } + rx_fd->state1 |= Hold; + rx_fd->state2 = 0x00000000; + rx_fd->end = 0xbabeface; + if (!rx_fd->data) + return; + rx_fd--; + if (!cur) + rx_fd += RX_RING_SIZE; + rx_fd->state1 &= ~Hold; +} + +static int __init dscc4_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct dscc4_pci_priv *priv; + struct dscc4_dev_priv *dpriv; + int i; + static int cards_found = 0; + unsigned long ioaddr; + + printk(KERN_DEBUG "%s", version); + + if (pci_enable_device(pdev)) + goto err_out; + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), "registers")) { + printk (KERN_ERR "dscc4: can't reserve MMIO region (regs)\n"); + goto err_out; + } + if (!request_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1), "LBI interface")) { + printk (KERN_ERR "dscc4: can't reserve MMIO region (lbi)\n"); + goto err_out_free_mmio_region0; + } + ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!ioaddr) { + printk(KERN_ERR "dscc4: cannot remap MMIO region %lx @ %lx\n", + pci_resource_len(pdev, 0), pci_resource_start(pdev, 0)); + goto err_out_free_mmio_region; + } + printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d.\n", + pci_resource_start(pdev, 0), + pci_resource_start(pdev, 1), pdev->irq); + + /* High PCI latency useless. Cf app. note. */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x10); + pci_set_master(pdev); + + if (dscc4_found1(pdev, ioaddr)) + goto err_out_iounmap; + + priv = (struct dscc4_pci_priv *)pci_get_drvdata(pdev); + + if (request_irq(pdev->irq, &dscc4_irq, SA_SHIRQ, "dscc4", priv->root)) { + printk(KERN_WARNING "dscc4: IRQ %d is busy\n", pdev->irq); + goto err_out_iounmap; + } + priv->pdev = pdev; + + /* power up/little endian/dma core controlled via hold bit */ + writel(0x00000000, ioaddr + GMODE); + /* Shared interrupt queue */ + { + u32 bits; + + bits = (IRQ_RING_SIZE >> 5) - 1; + bits |= bits << 4; + bits |= bits << 8; + bits |= bits << 16; + writel(bits, ioaddr + IQLENR0); + } + /* Global interrupt queue */ + writel((u32)(((IRQ_RING_SIZE >> 5) - 1) << 20), ioaddr + IQLENR1); + priv->iqcfg = (u32 *) pci_alloc_consistent(pdev, + IRQ_RING_SIZE*sizeof(u32), &priv->iqcfg_dma); + if (!priv->iqcfg) + goto err_out_free_irq; + writel(priv->iqcfg_dma, ioaddr + IQCFG); + + /* + * SCC 0-3 private rx/tx irq structures + * IQRX/TXi needs to be set soon. Learned it the hard way... + */ + for(i = 0; i < dev_per_card; i++) { + dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv; + dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev, + IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma); + if (!dpriv->iqtx) + goto err_out_free_iqtx; + writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4); + } + for(i = 0; i < dev_per_card; i++) { + dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv; + dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev, + IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma); + if (!dpriv->iqrx) + goto err_out_free_iqrx; + writel(dpriv->iqrx_dma, ioaddr + IQRX0 + i*4); + } + + /* + * Cf application hint. Beware of hard-lock condition on + * threshold . + */ + writel(0x42104000, ioaddr + FIFOCR1); + //writel(0x9ce69800, ioaddr + FIFOCR2); + writel(0xdef6d800, ioaddr + FIFOCR2); + //writel(0x11111111, ioaddr + FIFOCR4); + writel(0x18181818, ioaddr + FIFOCR4); + // FIXME: should depend on the chipset revision + writel(0x0000000e, ioaddr + FIFOCR3); + + writel(0xff200001, ioaddr + GCMDR); + + cards_found++; + return 0; + +err_out_free_iqrx: + while (--i >= 0) { + dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv; + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), + dpriv->iqrx, dpriv->iqrx_dma); + } + i = dev_per_card; +err_out_free_iqtx: + while (--i >= 0) { + dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv; + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), + dpriv->iqtx, dpriv->iqtx_dma); + } + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), priv->iqcfg, + priv->iqcfg_dma); +err_out_free_irq: + free_irq(pdev->irq, priv->root); +err_out_iounmap: + iounmap ((void *)ioaddr); +err_out_free_mmio_region: + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); +err_out_free_mmio_region0: + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); +err_out: + return -ENODEV; +}; + +static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr) +{ + struct dscc4_pci_priv *ppriv; + struct dscc4_dev_priv *dpriv; + struct net_device *dev; + int i = 0; + + dpriv = (struct dscc4_dev_priv *) + kmalloc(dev_per_card*sizeof(struct dscc4_dev_priv), GFP_KERNEL); + if (!dpriv) { + printk(KERN_ERR "dscc4: can't allocate data\n"); + goto err_out; + } + memset(dpriv, 0, dev_per_card*sizeof(struct dscc4_dev_priv)); + + dev = (struct net_device *) + kmalloc(dev_per_card*sizeof(struct net_device), GFP_KERNEL); + if (!dev) { + printk(KERN_ERR "dscc4: can't allocate net_device\n"); + goto err_dealloc_priv; + } + memset(dev, 0, dev_per_card*sizeof(struct net_device)); + + ppriv = (struct dscc4_pci_priv *) + kmalloc(sizeof(struct dscc4_pci_priv), GFP_KERNEL); + if (!ppriv) { + printk(KERN_ERR "dscc4: can't allocate pci private data.\n"); + goto err_dealloc_dev; + } + memset(ppriv, 0, sizeof(struct dscc4_pci_priv)); + + for (i = 0; i < dev_per_card; i++) { + struct dscc4_dev_priv *p; + struct net_device *d; + + d = dev + i; + d->base_addr = ioaddr; + d->init = NULL; + d->irq = pdev->irq; + /* The card adds the crc */ + d->type = ARPHRD_RAWHDLC; + d->open = dscc4_open; + d->stop = dscc4_close; + d->hard_start_xmit = dscc4_start_xmit; + d->set_multicast_list = NULL; + d->do_ioctl = dscc4_ioctl; + d->get_stats = dscc4_get_stats; + d->change_mtu = dscc4_change_mtu; + d->mtu = HDLC_MAX_MTU; + d->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; + d->tx_timeout = dscc4_tx_timeout; + d->watchdog_timeo = TX_TIMEOUT; + + p = dpriv + i; + p->dev_id = i; + p->pci_priv = ppriv; + spin_lock_init(&p->lock); + d->priv = p; + + if (dev_alloc_name(d, "scc%d")<0) { + printk(KERN_ERR "dev_alloc_name failed for scc.\n"); + goto err_dealloc_dev; + } + if (register_netdev(d)) { + printk(KERN_ERR "%s: register_netdev != 0.\n", d->name); + goto err_dealloc_dev; + } + dscc4_attach_hdlc_device(d); + SET_MODULE_OWNER(d); + } + ppriv->root = dev; + ppriv->pdev = pdev; + spin_lock_init(&ppriv->lock); + pdev->driver_data = ppriv; + pci_set_drvdata(pdev, ppriv); + return 0; + +err_dealloc_dev: + while (--i >= 0) + unregister_netdev(dev + i); + kfree(dev); +err_dealloc_priv: + kfree(dpriv); +err_out: + return -1; +}; + +static void dscc4_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct dscc4_dev_priv *dpriv; + struct dscc4_pci_priv *ppriv; + + dpriv = dev->priv; + if (netif_queue_stopped(dev) && + ((jiffies - dev->trans_start) > TX_TIMEOUT)) { + ppriv = dpriv->pci_priv; + if (dpriv->iqtx[dpriv->iqtx_current%IRQ_RING_SIZE]) { + u32 flags; + + printk(KERN_DEBUG "%s: pending events\n", dev->name); + dev->trans_start = jiffies; + spin_lock_irqsave(&ppriv->lock, flags); + dscc4_tx_irq(ppriv, dev); + spin_unlock_irqrestore(&ppriv->lock, flags); + } else { + struct TxFD *tx_fd; + struct sk_buff *skb; + int i,j; + + printk(KERN_DEBUG "%s: missing events\n", dev->name); + i = dpriv->tx_dirty%TX_RING_SIZE; + j = dpriv->tx_current - dpriv->tx_dirty; + dpriv->stats.tx_dropped += j; + while(j--) { + skb = dpriv->tx_skbuff[i]; + tx_fd = dpriv->tx_fd + i; + if (skb) { + dpriv->tx_skbuff[i] = NULL; + pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + } else + printk(KERN_INFO "%s: hardware on drugs!\n", dev->name); + tx_fd->data = 0; /* DEBUG */ + tx_fd->complete &= ~DataComplete; + i++; + i %= TX_RING_SIZE; + } + dpriv->tx_dirty = dpriv->tx_current; + dev->trans_start = jiffies; + netif_wake_queue(dev); + printk(KERN_DEBUG "%s: re-enabled\n", dev->name); + } + } + dpriv->timer.expires = jiffies + TX_TIMEOUT; + add_timer(&dpriv->timer); +} + +static void dscc4_tx_timeout(struct net_device *dev) +{ + /* FIXME: something is missing there */ +}; + +static int dscc4_open(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; + struct dscc4_pci_priv *ppriv; + u32 ioaddr = 0; + + MOD_INC_USE_COUNT; + + ppriv = dpriv->pci_priv; + + if (dscc4_init_ring(dev)) + goto err_out; + + ioaddr = dev->base_addr + SCC_REG_START(dpriv->dev_id); + + /* FIXME: VIS */ + writel(readl(ioaddr + CCR0) | 0x80001000, ioaddr + CCR0); + + writel(LengthCheck | (dev->mtu >> 5), ioaddr + RLCR); + + /* no address recognition/crc-CCITT/cts enabled */ + writel(readl(ioaddr + CCR1) | 0x021c8000, ioaddr + CCR1); + + /* Ccr2.Rac = 0 */ + writel(0x00050008 & ~RxActivate, ioaddr + CCR2); + +#ifdef EXPERIMENTAL_POLLING + writel(0xfffeef7f, ioaddr + IMR); /* Interrupt mask */ +#else + /* Don't mask RDO. Ever. */ + //writel(0xfffaef7f, ioaddr + IMR); /* Interrupt mask */ + writel(0xfffaef7e, ioaddr + IMR); /* Interrupt mask */ +#endif + /* IDT+IDR during XPR */ + dpriv->flags = NeedIDR | NeedIDT; + + /* + * The following is a bit paranoid... + * + * NB: the datasheet "...CEC will stay active if the SCC is in + * power-down mode or..." and CCR2.RAC = 1 are two different + * situations. + */ + if (readl(ioaddr + STAR) & SccBusy) { + printk(KERN_ERR "%s busy. Try later\n", dev->name); + goto err_free_ring; + } + writel(TxSccRes | RxSccRes, ioaddr + CMDR); + + /* ... the following isn't */ + if (dscc4_wait_ack_cec(ioaddr, dev, "Cec")) + goto err_free_ring; + + /* + * I would expect XPR near CE completion (before ? after ?). + * At worst, this code won't see a late XPR and people + * will have to re-issue an ifconfig (this is harmless). + * WARNING, a really missing XPR usually means a hardware + * reset is needed. Suggestions anyone ? + */ + if (dscc4_xpr_ack(dpriv)) + goto err_free_ring; + + netif_start_queue(dev); + + init_timer(&dpriv->timer); + dpriv->timer.expires = jiffies + 10*HZ; + dpriv->timer.data = (unsigned long)dev; + dpriv->timer.function = &dscc4_timer; + add_timer(&dpriv->timer); + netif_carrier_on(dev); + + return 0; + +err_free_ring: + dscc4_release_ring(dpriv); +err_out: + MOD_DEC_USE_COUNT; + return -EAGAIN; +} + +#ifdef EXPERIMENTAL_POLLING +static int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev) +{ + /* FIXME: it's gonna be easy (TM), for sure */ +} +#endif /* EXPERIMENTAL_POLLING */ + +static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + struct dscc4_pci_priv *ppriv; + struct TxFD *tx_fd; + int cur, next; + + ppriv = dpriv->pci_priv; + cur = dpriv->tx_current++%TX_RING_SIZE; + next = dpriv->tx_current%TX_RING_SIZE; + dpriv->tx_skbuff[next] = skb; + tx_fd = dpriv->tx_fd + next; + tx_fd->state = FrameEnd | Hold | TO_STATE(skb->len & TxSizeMax); + tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + tx_fd->complete = 0x00000000; + mb(); // FIXME: suppress ? + +#ifdef EXPERIMENTAL_POLLING + spin_lock(&dpriv->lock); + while(dscc4_tx_poll(dpriv, dev)); + spin_unlock(&dpriv->lock); +#endif + /* + * I know there's a window for a race in the following lines but + * dscc4_timer will take good care of it. The chipset eats events + * (especially the net_dev re-enabling ones) thus there is no + * reason to try and be smart. + */ + if ((dpriv->tx_dirty + 16) < dpriv->tx_current) { + netif_stop_queue(dev); + dpriv->hi_expected = 2; + } + tx_fd = dpriv->tx_fd + cur; + tx_fd->state &= ~Hold; + mb(); // FIXME: suppress ? + + /* + * One may avoid some pci transactions during intense TX periods. + * Not sure it's worth the pain... + */ + writel((TxPollCmd << dpriv->dev_id) | NoAck, dev->base_addr + GCMDR); + dev->trans_start = jiffies; + return 0; +} + +static int dscc4_close(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; + u32 ioaddr = dev->base_addr; + int dev_id; + + del_timer_sync(&dpriv->timer); + netif_stop_queue(dev); + + dev_id = dpriv->dev_id; + + writel(0x00050000, ioaddr + SCC_REG_START(dev_id) + CCR2); + writel(MTFi|Rdr|Rdt, ioaddr + CH0CFG + dev_id*0x0c); /* Reset Rx/Tx */ + writel(0x00000001, ioaddr + GCMDR); + + dscc4_release_ring(dpriv); + + MOD_DEC_USE_COUNT; + return 0; +} + +static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state) +{ + struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; + u32 brr; + + *state &= ~Ccr0ClockMask; + if (*bps) { /* DCE */ + u32 n = 0, m = 0, divider; + int xtal; + + xtal = dpriv->pci_priv->xtal_hz; + if (!xtal) + return -1; + divider = xtal / *bps; + if (divider > BRR_DIVIDER_MAX) { + divider >>= 4; + *state |= 0x00000036; /* Clock mode 6b (BRG/16) */ + } else + *state |= 0x00000037; /* Clock mode 7b (BRG) */ + if (divider >> 22) { + n = 63; + m = 15; + } else if (divider) { + /* Extraction of the 6 highest weighted bits */ + m = 0; + while (0xffffffc0 & divider) { + m++; + divider >>= 1; + } + n = divider; + } + brr = (m << 8) | n; + divider = n << m; + if (!(*state & 0x00000001)) /* Clock mode 6b */ + divider <<= 4; + *bps = xtal / divider; + } else { /* DTE */ + /* + * "state" already reflects Clock mode 0a. + * Nothing more to be done + */ + brr = 0; + } + writel(brr, dev->base_addr + BRR + SCC_REG_START(dpriv->dev_id)); + + return 0; +} + +#ifdef LATER_PLEASE +/* + * -*- [RFC] Configuring Synchronous Interfaces in Linux -*- + */ + +// FIXME: MEDIA already defined in linux/hdlc.h +#define HDLC_MEDIA_V35 0 +#define HDLC_MEDIA_RS232 1 +#define HDLC_MEDIA_X21 2 +#define HDLC_MEDIA_E1 3 +#define HDLC_MEDIA_HSSI 4 + +#define HDLC_CODING_NRZ 0 +#define HDLC_CODING_NRZI 1 +#define HDLC_CODING_FM0 2 +#define HDLC_CODING_FM1 3 +#define HDLC_CODING_MANCHESTER 4 + +#define HDLC_CRC_NONE 0 +#define HDLC_CRC_16 1 +#define HDLC_CRC_32 2 +#define HDLC_CRC_CCITT 3 + +/* RFC: add the crc reset value ? */ +struct hdlc_physical { + u8 media; + u8 coding; + u32 rate; + u8 crc; + u8 crc_siz; /* 2 or 4 bytes */ + u8 shared_flags; /* Discouraged on the DSCC4 */ +}; + +// FIXME: PROTO already defined in linux/hdlc.h +#define HDLC_PROTO_RAW 0 +#define HDLC_PROTO_FR 1 +#define HDLC_PROTO_X25 2 +#define HDLC_PROTO_PPP 3 +#define HDLC_PROTO_CHDLC 4 + +struct hdlc_protocol { + u8 proto; + + union { + } u; +}; + +struct screq { + u16 media_group; + + union { + struct hdlc_physical hdlc_phy; + struct hdlc_protocol hdlc_proto; + } u; +}; + +// FIXME: go sub-module +static struct { + u16 coding; + u16 bits; +} map[] = { + {HDLC_CODING_NRZ, 0x00}, + {HDLC_CODING_NRZI, 0x20}, + {HDLC_CODING_FM0, 0x40}, + {HDLC_CODING_FM1, 0x50}, + {HDLC_CODING_MANCHESTER, 0x60}, + {65535, 0x00} +}; +#endif /* LATER_PLEASE */ + +static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + u32 state, ioaddr; + + if (dev->flags & IFF_UP) + return -EBUSY; + + switch (cmd) { + /* Set built-in quartz frequency */ + case SIOCDEVPRIVATE: { + u32 hz; + + hz = ifr->ifr_ifru.ifru_ivalue; + if (hz >= 33000000) /* 33 MHz */ + return -EOPNOTSUPP; + dpriv->pci_priv->xtal_hz = hz; + return 0; + } + /* Set/unset loopback */ + case SIOCDEVPRIVATE+1: { + u32 flags; + + ioaddr = dev->base_addr + CCR1 + + SCC_REG_START(dpriv->dev_id); + state = readl(ioaddr); + flags = ifr->ifr_ifru.ifru_ivalue; + if (flags & 0x00000001) { + printk(KERN_DEBUG "%s: loopback\n", dev->name); + state |= 0x00000100; + } else { + printk(KERN_DEBUG "%s: normal\n", dev->name); + state &= ~0x00000100; + } + writel(state, ioaddr); + return 0; + } + +#ifdef LATER_PLEASE + case SIOCDEVPRIVATE+2: { + { + struct screq scr; + + err = copy_from_user(&scr, ifr->ifr_ifru.ifru_data, sizeof(struct screq)); + if (err) + return err; + do { + if (scr.u.hdlc_phy.coding == map[i].coding) + break; + } while (map[++i].coding != 65535); + if (!map[i].coding) + return -EOPNOTSUPP; + + ioaddr = dev->base_addr + CCR0 + + SCC_REG_START(dpriv->dev_id); + state = readl(ioaddr) & ~EncodingMask; + state |= (u32)map[i].bits << 16; + writel(state, ioaddr); + printk("state: %08x\n", state); /* DEBUG */ + return 0; + } + case SIOCDEVPRIVATE+3: { + struct screq *scr = (struct screq *)ifr->ifr_ifru.ifru_data; + + ioaddr = dev->base_addr + CCR0 + + SCC_REG_START(dpriv->dev_id); + state = (readl(ioaddr) & EncodingMask) >> 16; + do { + if (state == map[i].bits) + break; + } while (map[++i].coding); + return put_user(map[i].coding, (u16 *)scr->u.hdlc_phy.coding); + } +#endif /* LATER_PLEASE */ + + case HDLCSCLOCKRATE: + { + u32 state, bps; + + bps = ifr->ifr_ifru.ifru_ivalue; + ioaddr = dev->base_addr + CCR0 + + SCC_REG_START(dpriv->dev_id); + state = readl(ioaddr); + if(dscc4_set_clock(dev, &bps, &state) < 0) + return -EOPNOTSUPP; + if (bps) { /* DCE */ + printk(KERN_DEBUG "%s: generated RxClk (DCE)\n", + dev->name); + ifr->ifr_ifru.ifru_ivalue = bps; + } else { /* DTE */ + state = 0x80001000; + printk(KERN_DEBUG "%s: external RxClk (DTE)\n", + dev->name); + } + writel(state, ioaddr); + return 0; + } + case HDLCGCLOCKRATE: { + u32 brr; + int bps; + + brr = readl(dev->base_addr + BRR + + SCC_REG_START(dpriv->dev_id)); + bps = dpriv->pci_priv->xtal_hz >> (brr >> 8); + bps /= (brr & 0x3f) + 1; + ifr->ifr_ifru.ifru_ivalue = bps; + return 0; + } + + default: + return -EOPNOTSUPP; + } +} + +static int dscc4_change_mtu(struct net_device *dev, int mtu) +{ + /* FIXME: chainsaw coded... */ + if ((mtu <= 3) || (mtu > 65531)) + return -EINVAL; + if(dev->flags & IFF_UP) + return -EBUSY; + dev->mtu = mtu; + return(0); +} + +static void dscc4_irq(int irq, void *dev_instance, struct pt_regs *ptregs) +{ + struct net_device *dev = dev_instance; + struct dscc4_pci_priv *priv; + u32 ioaddr, state; + unsigned long flags; + int i; + + priv = ((struct dscc4_dev_priv *)dev->priv)->pci_priv; + /* + * FIXME: shorten the protected area (set some bit telling we're + * in an interrupt or increment some work-to-do counter etc...) + */ + spin_lock_irqsave(&priv->lock, flags); + + ioaddr = dev->base_addr; + + state = readl(ioaddr + GSTAR); + if (!state) + goto out; + writel(state, ioaddr + GSTAR); + + if (state & Arf) { + printk(KERN_ERR "%s: failure (Arf). Harass the maintener\n", + dev->name); + goto out; + } + state &= ~ArAck; + if (state & Cfg) { + if (debug) + printk(KERN_DEBUG "CfgIV\n"); + if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf) + printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG"); + if (!(state &= ~Cfg)) + goto out; + } + if (state & RxEvt) { + i = dev_per_card - 1; + do { + dscc4_rx_irq(priv, dev + i); + } while (--i >= 0); + state &= ~RxEvt; + } + if (state & TxEvt) { + i = dev_per_card - 1; + do { + dscc4_tx_irq(priv, dev + i); + } while (--i >= 0); + state &= ~TxEvt; + } +out: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, + struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + u32 state; + int cur, loop = 0; + +try: + cur = dpriv->iqtx_current%IRQ_RING_SIZE; + state = dpriv->iqtx[cur]; + if (!state) { +#ifdef DEBUG + if (loop > 1) + printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop); +#endif + if (loop && netif_queue_stopped(dev)) + if ((dpriv->tx_dirty + 8) >= dpriv->tx_current) + netif_wake_queue(dev); + return; + } + loop++; + dpriv->iqtx[cur] = 0; + dpriv->iqtx_current++; + +#ifdef DEBUG_PARANOID + if (SOURCE_ID(state) != dpriv->dev_id) { + printk(KERN_DEBUG "%s (Tx): Source Id=%d, state=%08x\n", + dev->name, SOURCE_ID(state), state ); + return; + } + if (state & 0x0df80c01) { + printk(KERN_DEBUG "%s (Tx): state=%08x (UFO alert)\n", + dev->name, state); + return; + } +#endif + // state &= 0x0fffffff; /* Tracking the analyzed bits */ + if (state & SccEvt) { + if (state & Alls) { + struct TxFD *tx_fd; + struct sk_buff *skb; + + cur = dpriv->tx_dirty%TX_RING_SIZE; + tx_fd = dpriv->tx_fd + cur; + + skb = dpriv->tx_skbuff[cur]; + + /* XXX: hideous kludge - to be removed "later" */ + if (!skb) { + printk(KERN_ERR "%s: NULL skb in tx_irq at index %d\n", dev->name, cur); + goto try; + } + dpriv->tx_dirty++; // MUST be after skb test + + /* Happens sometime. Don't know what triggers it */ + if (!(tx_fd->complete & DataComplete)) { + u32 ioaddr, isr; + + ioaddr = dev->base_addr + + SCC_REG_START(dpriv->dev_id) + ISR; + isr = readl(ioaddr); + printk(KERN_DEBUG + "%s: DataComplete=0 cur=%d isr=%08x state=%08x\n", + dev->name, cur, isr, state); + writel(isr, ioaddr); + dpriv->stats.tx_dropped++; + } else { + tx_fd->complete &= ~DataComplete; + if (tx_fd->state & FrameEnd) { + dpriv->stats.tx_packets++; + dpriv->stats.tx_bytes += skb->len; + } + } + + dpriv->tx_skbuff[cur] = NULL; + pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len, + PCI_DMA_TODEVICE); + tx_fd->data = 0; /* DEBUG */ + dev_kfree_skb_irq(skb); +{ // DEBUG + cur = (dpriv->tx_dirty-1)%TX_RING_SIZE; + tx_fd = dpriv->tx_fd + cur; + tx_fd->state |= Hold; +} + if (!(state &= ~Alls)) + goto try; + } + /* + * Transmit Data Underrun + */ + if (state & Xdu) { + printk(KERN_ERR "dscc4: XDU. Contact maintainer\n"); + dpriv->flags = NeedIDT; + /* Tx reset */ + writel(MTFi | Rdt, + dev->base_addr + 0x0c*dpriv->dev_id + CH0CFG); + writel(0x00000001, dev->base_addr + GCMDR); + return; + } + if (state & Xmr) { + /* Frame needs to be sent again - FIXME */ + //dscc4_start_xmit(dpriv->tx_skbuff[dpriv->tx_dirty], dev); + if (!(state &= ~0x00002000)) /* DEBUG */ + goto try; + } + if (state & Xpr) { + unsigned long ioaddr = dev->base_addr; + unsigned long scc_offset; + u32 scc_addr; + + scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id); + scc_addr = ioaddr + 0x0c*dpriv->dev_id; + if (readl(scc_offset + STAR) & SccBusy) + printk(KERN_DEBUG "%s busy. Fatal\n", + dev->name); + /* + * Keep this order: IDT before IDR + */ + if (dpriv->flags & NeedIDT) { + writel(MTFi | Idt, scc_addr + CH0CFG); + writel(dpriv->tx_fd_dma + + (dpriv->tx_dirty%TX_RING_SIZE)* + sizeof(struct TxFD), scc_addr + CH0BTDA); + if(dscc4_do_action(dev, "IDT")) + goto err_xpr; + dpriv->flags &= ~NeedIDT; + mb(); + } + if (dpriv->flags & NeedIDR) { + writel(MTFi | Idr, scc_addr + CH0CFG); + writel(dpriv->rx_fd_dma + + (dpriv->rx_current%RX_RING_SIZE)* + sizeof(struct RxFD), scc_addr + CH0BRDA); + if(dscc4_do_action(dev, "IDR")) + goto err_xpr; + dpriv->flags &= ~NeedIDR; + mb(); + /* Activate receiver and misc */ + writel(0x08050008, scc_offset + CCR2); + } + err_xpr: + if (!(state &= ~Xpr)) + goto try; + } + } else { /* ! SccEvt */ + if (state & Hi) { +#ifdef EXPERIMENTAL_POLLING + while(!dscc4_tx_poll(dpriv, dev)); +#endif + state &= ~Hi; + } + /* + * FIXME: it may be avoided. Re-re-re-read the manual. + */ + if (state & Err) { + printk(KERN_ERR "%s: Tx ERR\n", dev->name); + dpriv->stats.tx_errors++; + state &= ~Err; + } + } + goto try; +} + +static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + u32 state; + int cur; + +try: + cur = dpriv->iqrx_current%IRQ_RING_SIZE; + state = dpriv->iqrx[cur]; + if (!state) + return; + dpriv->iqrx[cur] = 0; + dpriv->iqrx_current++; + +#ifdef DEBUG_PARANOID + if (SOURCE_ID(state) != dpriv->dev_id) { + printk(KERN_DEBUG "%s (Rx): Source Id=%d, state=%08x\n", + dev->name, SOURCE_ID(state), state); + goto try; + } + if (state & 0x0df80c01) { + printk(KERN_DEBUG "%s (Rx): state=%08x (UFO alert)\n", + dev->name, state); + goto try; + } +#endif + if (!(state & SccEvt)){ + struct RxFD *rx_fd; + + state &= 0x00ffffff; + if (state & Err) { /* Hold or reset */ + printk(KERN_DEBUG "%s (Rx): ERR\n", dev->name); + cur = dpriv->rx_current; + rx_fd = dpriv->rx_fd + cur; + /* + * Presume we're not facing a DMAC receiver reset. + * As We use the rx size-filtering feature of the + * DSCC4, the beginning of a new frame is waiting in + * the rx fifo. I bet a Receive Data Overflow will + * happen most of time but let's try and avoid it. + * Btw (as for RDO) if one experiences ERR whereas + * the system looks rather idle, there may be a + * problem with latency. In this case, increasing + * RX_RING_SIZE may help. + */ + while (dpriv->rx_needs_refill) { + while(!(rx_fd->state1 & Hold)) { + rx_fd++; + cur++; + if (!(cur = cur%RX_RING_SIZE)) + rx_fd = dpriv->rx_fd; + } + dpriv->rx_needs_refill--; + try_get_rx_skb(dpriv, cur, dev); + if (!rx_fd->data) + goto try; + rx_fd->state1 &= ~Hold; + rx_fd->state2 = 0x00000000; + rx_fd->end = 0xbabeface; + } + goto try; + } + if (state & Fi) { + cur = dpriv->rx_current%RX_RING_SIZE; + rx_fd = dpriv->rx_fd + cur; + dscc4_rx_skb(dpriv, cur, rx_fd, dev); + dpriv->rx_current++; + goto try; + } + if (state & Hi ) { /* HI bit */ + state &= ~Hi; + goto try; + } + } else { /* ! SccEvt */ +#ifdef DEBUG_PARANOIA + int i; + static struct { + u32 mask; + const char *irq_name; + } evts[] = { + { 0x00008000, "TIN"}, + { 0x00004000, "CSC"}, + { 0x00000020, "RSC"}, + { 0x00000010, "PCE"}, + { 0x00000008, "PLLA"}, + { 0x00000004, "CDSC"}, + { 0, NULL} + }; +#endif /* DEBUG_PARANOIA */ + state &= 0x00ffffff; +#ifdef DEBUG_PARANOIA + for (i = 0; evts[i].irq_name; i++) { + if (state & evts[i].mask) { + printk(KERN_DEBUG "dscc4(%s): %s\n", + dev->name, evts[i].irq_name); + if (!(state &= ~evts[i].mask)) + goto try; + } + } +#endif /* DEBUG_PARANOIA */ + /* + * Receive Data Overflow (FIXME: untested) + */ + if (state & Rdo) { + u32 ioaddr, scc_offset, scc_addr; + struct RxFD *rx_fd; + int cur; + + //if (debug) + // dscc4_rx_dump(dpriv); + ioaddr = dev->base_addr; + scc_addr = ioaddr + 0x0c*dpriv->dev_id; + scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id); + + writel(readl(scc_offset + CCR2) & ~RxActivate, + scc_offset + CCR2); + /* + * This has no effect. Why ? + * ORed with TxSccRes, one sees the CFG ack (for + * the TX part only). + */ + writel(RxSccRes, scc_offset + CMDR); + dpriv->flags |= RdoSet; + + /* + * Let's try and save something in the received data. + * rx_current must be incremented at least once to + * avoid HOLD in the BRDA-to-be-pointed desc. + */ + do { + cur = dpriv->rx_current++%RX_RING_SIZE; + rx_fd = dpriv->rx_fd + cur; + if (!(rx_fd->state2 & DataComplete)) + break; + if (rx_fd->state2 & FrameAborted) { + dpriv->stats.rx_over_errors++; + rx_fd->state1 |= Hold; + rx_fd->state2 = 0x00000000; + rx_fd->end = 0xbabeface; + } else + dscc4_rx_skb(dpriv, cur, rx_fd, dev); + } while (1); + + if (debug) { + if (dpriv->flags & RdoSet) + printk(KERN_DEBUG + "dscc4: no RDO in Rx data\n"); + } +#ifdef DSCC4_RDO_EXPERIMENTAL_RECOVERY + /* + * FIXME: must the reset be this violent ? + */ + writel(dpriv->rx_fd_dma + + (dpriv->rx_current%RX_RING_SIZE)* + sizeof(struct RxFD), scc_addr + CH0BRDA); + writel(MTFi|Rdr|Idr, scc_addr + CH0CFG); + if(dscc4_do_action(dev, "RDR")) { + printk(KERN_ERR "%s: RDO recovery failed(%s)\n", + dev->name, "RDR"); + goto rdo_end; + } + writel(MTFi|Idr, scc_addr + CH0CFG); + if(dscc4_do_action(dev, "IDR")) { + printk(KERN_ERR "%s: RDO recovery failed(%s)\n", + dev->name, "IDR"); + goto rdo_end; + } + rdo_end: +#endif + writel(readl(scc_offset + CCR2) | RxActivate, + scc_offset + CCR2); + goto try; + } + /* These will be used later */ + if (state & Rfs) { + if (!(state &= ~Rfs)) + goto try; + } + if (state & Rfo) { + if (!(state &= ~Rfo)) + goto try; + } + if (state & Flex) { + if (!(state &= ~Flex)) + goto try; + } + } +} + +static int dscc4_init_ring(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv; + struct TxFD *tx_fd; + struct RxFD *rx_fd; + int i; + + tx_fd = (struct TxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev, + TX_RING_SIZE*sizeof(struct TxFD), &dpriv->tx_fd_dma); + if (!tx_fd) + goto err_out; + rx_fd = (struct RxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev, + RX_RING_SIZE*sizeof(struct RxFD), &dpriv->rx_fd_dma); + if (!rx_fd) + goto err_free_dma_tx; + + dpriv->tx_fd = tx_fd; + dpriv->rx_fd = rx_fd; + dpriv->rx_current = 0; + dpriv->tx_current = 0; + dpriv->tx_dirty = 0; + + /* the dma core of the dscc4 will be locked on the first desc */ + for(i = 0; i < TX_RING_SIZE; ) { + reset_TxFD(tx_fd); + /* FIXME: NULL should be ok - to be tried */ + tx_fd->data = dpriv->tx_fd_dma; + dpriv->tx_skbuff[i] = NULL; + i++; + tx_fd->next = (u32)(dpriv->tx_fd_dma + i*sizeof(struct TxFD)); + tx_fd++; + } + (--tx_fd)->next = (u32)dpriv->tx_fd_dma; +{ + /* + * XXX: I would expect the following to work for the first descriptor + * (tx_fd->state = 0xc0000000) + * - Hold=1 (don't try and branch to the next descripto); + * - No=0 (I want an empty data section, i.e. size=0); + * - Fe=1 (required by No=0 or we got an Err irq and must reset). + * Alas, it fails (and locks solid). Thus the introduction of a dummy + * skb to avoid No=0 (choose one: Ugly [ ] Tasteless [ ] VMS [ ]). + * TODO: fiddle the tx threshold when time permits. + */ + struct sk_buff *skb; + + skb = dev_alloc_skb(32); + if (!skb) + goto err_free_dma_tx; + skb->len = 32; + memset(skb->data, 0xaa, 16); + tx_fd -= (TX_RING_SIZE - 1); + tx_fd->state = 0xc0000000; + tx_fd->state |= ((u32)(skb->len & TxSizeMax)) << 16; + tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + dpriv->tx_skbuff[0] = skb; +} + for (i = 0; i < RX_RING_SIZE;) { + /* size set by the host. Multiple of 4 bytes please */ + rx_fd->state1 = HiDesc; /* Hi, no Hold */ + rx_fd->state2 = 0x00000000; + rx_fd->end = 0xbabeface; + rx_fd->state1 |= ((u32)(dev->mtu & RxSizeMax)) << 16; + try_get_rx_skb(dpriv, i, dev); + i++; + rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD)); + rx_fd++; + } + (--rx_fd)->next = (u32)dpriv->rx_fd_dma; + rx_fd->state1 |= 0x40000000; /* Hold */ + + return 0; + +err_free_dma_tx: + pci_free_consistent(dpriv->pci_priv->pdev, TX_RING_SIZE*sizeof(*tx_fd), + tx_fd, dpriv->tx_fd_dma); +err_out: + return -1; +} + +static struct net_device_stats *dscc4_get_stats(struct net_device *dev) +{ + struct dscc4_dev_priv *priv = (struct dscc4_dev_priv *)dev->priv; + + return &priv->stats; +} + +static void __exit dscc4_remove_one(struct pci_dev *pdev) +{ + struct dscc4_pci_priv *ppriv; + struct net_device *root; + int i; + + ppriv = pci_get_drvdata(pdev); + root = ppriv->root; + + free_irq(pdev->irq, root); + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg, + ppriv->iqcfg_dma); + for (i=0; i < dev_per_card; i++) { + struct dscc4_dev_priv *dpriv; + struct net_device *dev; + + dev = ppriv->root + i; + dscc4_unattach_hdlc_device(dev); + + dpriv = (struct dscc4_dev_priv *)dev->priv; + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), + dpriv->iqrx, dpriv->iqrx_dma); + pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), + dpriv->iqtx, dpriv->iqtx_dma); + unregister_netdev(dev); + } + kfree(root->priv); + + iounmap((void *)root->base_addr); + kfree(root); + + kfree(ppriv); + + release_mem_region(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); +} + +static int dscc4_hdlc_ioctl(struct hdlc_device_struct *hdlc, struct ifreq *ifr, int cmd) +{ + struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr; + int result; + + /* FIXME: locking ? */ + result = dscc4_ioctl(dev, ifr, cmd); + return result; +} + +static int dscc4_hdlc_open(struct hdlc_device_struct *hdlc) +{ + struct net_device *dev = (struct net_device *)(hdlc->netdev.base_addr); + + if (netif_running(dev)) { + printk(KERN_DEBUG "%s: already running\n", dev->name); // DEBUG + return 0; + } + return dscc4_open(dev); +} + +static int dscc4_hdlc_xmit(hdlc_device *hdlc, struct sk_buff *skb) +{ + struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr; + + return dscc4_start_xmit(skb, dev); +} + +static void dscc4_hdlc_close(struct hdlc_device_struct *hdlc) +{ + struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr; + struct dscc4_dev_priv *dpriv; + + dpriv = dev->priv; + --dpriv->usecount; +} + +/* Operated under dev lock */ +static int dscc4_attach_hdlc_device(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + struct hdlc_device_struct *hdlc; + int result; + + hdlc = &dpriv->hdlc; + /* XXX: Don't look at the next line */ + hdlc->netdev.base_addr = (unsigned long)dev; + // FIXME: set hdlc->set_mode ? + hdlc->open = dscc4_hdlc_open; + hdlc->close = dscc4_hdlc_close; + hdlc->ioctl = dscc4_hdlc_ioctl; + hdlc->xmit = dscc4_hdlc_xmit; + + result = register_hdlc_device(hdlc); + if (!result) + dpriv->usecount++; + return result; +} + +/* Operated under dev lock */ +static void dscc4_unattach_hdlc_device(struct net_device *dev) +{ + struct dscc4_dev_priv *dpriv = dev->priv; + + unregister_hdlc_device(&dpriv->hdlc); + dpriv->usecount--; +} + +static struct pci_device_id dscc4_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, dscc4_pci_tbl); + +static struct pci_driver dscc4_driver = { + name: "dscc4", + id_table: dscc4_pci_tbl, + probe: dscc4_init_one, + remove: dscc4_remove_one, +}; + +static int __init dscc4_init_module(void) +{ + return pci_module_init(&dscc4_driver); +} + +static void __exit dscc4_cleanup_module(void) +{ + pci_unregister_driver(&dscc4_driver); +} + +module_init(dscc4_init_module); +module_exit(dscc4_cleanup_module); diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/hd64570.h linux/drivers/net/wan/hd64570.h --- v2.4.2/linux/drivers/net/wan/hd64570.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/hd64570.h Tue Mar 6 19:44:36 2001 @@ -0,0 +1,234 @@ +#ifndef __HD64570_H +#define __HD64570_H + +/* SCA HD64570 register definitions - all addresses for mode 0 (8086 MPU) + and 1 (64180 MPU). For modes 2 and 3, XOR the address with 0x01. + + Source: HD64570 SCA User's Manual +*/ + + + +/* SCA Control Registers */ +#define LPR 0x00 /* Low Power */ + +/* Wait controller registers */ +#define PABR0 0x02 /* Physical Address Boundary 0 */ +#define PABR1 0x03 /* Physical Address Boundary 1 */ +#define WCRL 0x04 /* Wait Control L */ +#define WCRM 0x05 /* Wait Control M */ +#define WCRH 0x06 /* Wait Control H */ + +#define PCR 0x08 /* DMA Priority Control */ +#define DMER 0x09 /* DMA Master Enable */ + + +/* Interrupt registers */ +#define ISR0 0x10 /* Interrupt Status 0 */ +#define ISR1 0x11 /* Interrupt Status 1 */ +#define ISR2 0x12 /* Interrupt Status 2 */ + +#define IER0 0x14 /* Interrupt Enable 0 */ +#define IER1 0x15 /* Interrupt Enable 1 */ +#define IER2 0x16 /* Interrupt Enable 2 */ + +#define ITCR 0x18 /* Interrupt Control */ +#define IVR 0x1A /* Interrupt Vector */ +#define IMVR 0x1C /* Interrupt Modified Vector */ + + + +/* MSCI channel (port) 0 registers - offset 0x20 + MSCI channel (port) 1 registers - offset 0x40 */ + +#define MSCI0_OFFSET 0x20 +#define MSCI1_OFFSET 0x40 + +#define TRBL 0x00 /* TX/RX buffer L */ +#define TRBH 0x01 /* TX/RX buffer H */ +#define ST0 0x02 /* Status 0 */ +#define ST1 0x03 /* Status 1 */ +#define ST2 0x04 /* Status 2 */ +#define ST3 0x05 /* Status 3 */ +#define FST 0x06 /* Frame Status */ +#define IE0 0x08 /* Interrupt Enable 0 */ +#define IE1 0x09 /* Interrupt Enable 1 */ +#define IE2 0x0A /* Interrupt Enable 2 */ +#define FIE 0x0B /* Frame Interrupt Enable */ +#define CMD 0x0C /* Command */ +#define MD0 0x0E /* Mode 0 */ +#define MD1 0x0F /* Mode 1 */ +#define MD2 0x10 /* Mode 2 */ +#define CTL 0x11 /* Control */ +#define SA0 0x12 /* Sync/Address 0 */ +#define SA1 0x13 /* Sync/Address 1 */ +#define IDL 0x14 /* Idle Pattern */ +#define TMC 0x15 /* Time Constant */ +#define RXS 0x16 /* RX Clock Source */ +#define TXS 0x17 /* TX Clock Source */ +#define TRC0 0x18 /* TX Ready Control 0 */ +#define TRC1 0x19 /* TX Ready Control 1 */ +#define RRC 0x1A /* RX Ready Control */ +#define CST0 0x1C /* Current Status 0 */ +#define CST1 0x1D /* Current Status 1 */ + + +/* Timer channel 0 (port 0 RX) registers - offset 0x60 + Timer channel 1 (port 0 TX) registers - offset 0x68 + Timer channel 2 (port 1 RX) registers - offset 0x70 + Timer channel 3 (port 1 TX) registers - offset 0x78 +*/ + +#define TIMER0RX_OFFSET 0x60 +#define TIMER0TX_OFFSET 0x68 +#define TIMER1RX_OFFSET 0x70 +#define TIMER1TX_OFFSET 0x78 + +#define TCNTL 0x00 /* Up-counter L */ +#define TCNTH 0x01 /* Up-counter H */ +#define TCONRL 0x02 /* Constant L */ +#define TCONRH 0x03 /* Constant H */ +#define TCSR 0x04 /* Control/Status */ +#define TEPR 0x05 /* Expand Prescale */ + + + +/* DMA channel 0 (port 0 RX) registers - offset 0x80 + DMA channel 1 (port 0 TX) registers - offset 0xA0 + DMA channel 2 (port 1 RX) registers - offset 0xC0 + DMA channel 3 (port 1 TX) registers - offset 0xE0 +*/ + +#define DMAC0RX_OFFSET 0x80 +#define DMAC0TX_OFFSET 0xA0 +#define DMAC1RX_OFFSET 0xC0 +#define DMAC1TX_OFFSET 0xE0 + +#define BARL 0x00 /* Buffer Address L (chained block) */ +#define BARH 0x01 /* Buffer Address H (chained block) */ +#define BARB 0x02 /* Buffer Address B (chained block) */ + +#define DARL 0x00 /* RX Destination Addr L (single block) */ +#define DARH 0x01 /* RX Destination Addr H (single block) */ +#define DARB 0x02 /* RX Destination Addr B (single block) */ + +#define SARL 0x04 /* TX Source Address L (single block) */ +#define SARH 0x05 /* TX Source Address H (single block) */ +#define SARB 0x06 /* TX Source Address B (single block) */ + +#define CPB 0x06 /* Chain Pointer Base (chained block) */ + +#define CDAL 0x08 /* Current Descriptor Addr L (chained block) */ +#define CDAH 0x09 /* Current Descriptor Addr H (chained block) */ +#define EDAL 0x0A /* Error Descriptor Addr L (chained block) */ +#define EDAH 0x0B /* Error Descriptor Addr H (chained block) */ +#define BFLL 0x0C /* RX Receive Buffer Length L (chained block)*/ +#define BFLH 0x0D /* RX Receive Buffer Length H (chained block)*/ +#define BCRL 0x0E /* Byte Count L */ +#define BCRH 0x0F /* Byte Count H */ +#define DSR 0x10 /* DMA Status */ +#define DSR_RX(node) (DSR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define DSR_TX(node) (DSR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) +#define DMR 0x11 /* DMA Mode */ +#define DMR_RX(node) (DMR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define DMR_TX(node) (DMR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) +#define FCT 0x13 /* Frame End Interrupt Counter */ +#define FCT_RX(node) (FCT + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define FCT_TX(node) (FCT + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) +#define DIR 0x14 /* DMA Interrupt Enable */ +#define DIR_RX(node) (DIR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define DIR_TX(node) (DIR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) +#define DCR 0x15 /* DMA Command */ +#define DCR_RX(node) (DCR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)) +#define DCR_TX(node) (DCR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)) + + + + +/* Descriptor Structure */ + +typedef struct { + u16 cp; /* Chain Pointer */ + u32 bp; /* Buffer Pointer (24 bits) */ + u16 len; /* Data Length */ + u8 stat; /* Status */ + u8 unused2; +}__attribute__ ((packed)) pkt_desc; + + +/* Packet Descriptor Status bits */ + +#define ST_TX_EOM 0x80 /* End of frame */ +#define ST_TX_EOT 0x01 /* End of transmition */ + +#define ST_RX_EOM 0x80 /* End of frame */ +#define ST_RX_SHORT 0x40 /* Short frame */ +#define ST_RX_ABORT 0x20 /* Abort */ +#define ST_RX_RESBIT 0x10 /* Residual bit */ +#define ST_RX_OVERRUN 0x08 /* Overrun */ +#define ST_RX_CRC 0x04 /* CRC */ + +#define ST_ERROR_MASK 0x7C + +#define DIR_EOTE 0x80 /* Transfer completed */ +#define DIR_EOME 0x40 /* Frame Transfer Completed (chained-block) */ +#define DIR_BOFE 0x20 /* Buffer Overflow/Underflow (chained-block)*/ +#define DIR_COFE 0x10 /* Counter Overflow (chained-block) */ + + +#define DSR_EOT 0x80 /* Transfer completed */ +#define DSR_EOM 0x40 /* Frame Transfer Completed (chained-block) */ +#define DSR_BOF 0x20 /* Buffer Overflow/Underflow (chained-block)*/ +#define DSR_COF 0x10 /* Counter Overflow (chained-block) */ +#define DSR_DE 0x02 /* DMA Enable */ +#define DSR_DWE 0x01 /* DMA Write Disable */ + +/* DMA Master Enable Register (DMER) bits */ +#define DMER_DME 0x80 /* DMA Master Enable */ + + +#define CMD_RESET 0x21 /* Reset Channel */ +#define CMD_TX_ENABLE 0x02 /* Start transmitter */ +#define CMD_RX_ENABLE 0x12 /* Start receiver */ + +#define MD0_HDLC 0x80 /* Bit-sync HDLC mode */ +#define MD0_CRC_ENA 0x04 /* Enable CRC code calculation */ +#define MD0_CRC_CCITT 0x02 /* CCITT CRC instead of CRC-16 */ +#define MD0_CRC_PR1 0x01 /* Initial all-ones instead of all-zeros */ + +#define MD0_CRC_NONE 0x00 +#define MD0_CRC_16_0 0x04 +#define MD0_CRC_16 0x05 +#define MD0_CRC_ITU_0 0x06 +#define MD0_CRC_ITU 0x07 + +#define MD2_NRZI 0x20 /* NRZI mode */ +#define MD2_LOOPBACK 0x03 /* Local data Loopback */ + +#define CTL_NORTS 0x01 +#define CTL_IDLE 0x10 /* Transmit an idle pattern */ +#define CTL_UDRNC 0x20 /* Idle after CRC or FCS+flag transmition */ + +#define ST0_TXRDY 0x02 /* TX ready */ +#define ST0_RXRDY 0x01 /* RX ready */ + +#define ST1_UDRN 0x80 /* MSCI TX underrun */ + +#define ST3_CTS 0x08 /* modem input - /CTS */ +#define ST3_DCD 0x04 /* modem input - /DCD */ + +#define IE0_TXINT 0x80 /* TX INT MSCI interrupt enable */ +#define IE1_UDRN 0x80 /* TX underrun MSCI interrupt enable */ + +#define DCR_ABORT 0x01 /* Software abort command */ +#define DCR_CLEAR_EOF 0x02 /* Clear EOF interrupt */ + +/* TX and RX Clock Source - RXS and TXS */ +#define CLK_BRG_MASK 0x0F +#define CLK_LINE_RX 0x00 /* TX/RX clock line input */ +#define CLK_LINE_TX 0x00 /* TX/RX line input */ +#define CLK_BRG_RX 0x40 /* internal baud rate generator */ +#define CLK_BRG_TX 0x40 /* internal baud rate generator */ +#define CLK_RXCLK_TX 0x60 /* TX clock from RX clock */ + +#endif diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/hd6457x.c linux/drivers/net/wan/hd6457x.c --- v2.4.2/linux/drivers/net/wan/hd6457x.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/hd6457x.c Tue Mar 6 19:44:36 2001 @@ -0,0 +1,757 @@ +/* + * Hitachi SCA HD64570 and HD64572 common driver for Linux + * + * Copyright (C) 1998-2000 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Sources of information: + * Hitachi HD64570 SCA User's Manual + * Hitachi HD64572 SCA-II User's Manual + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#if (!defined (__HD64570_H) && !defined (__HD64572_H)) || \ + (defined (__HD64570_H) && defined (__HD64572_H)) +#error Either hd64570.h or hd64572.h must be included +#endif + + +static card_t *first_card; +static card_t **new_card = &first_card; + + +/* Maximum events to handle at each interrupt - should I increase it? */ +#define INTR_WORK 4 + +#define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) +#define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET) +#define get_dmac_tx(port) (phy_node(port) ? DMAC1TX_OFFSET : DMAC0TX_OFFSET) + +#define SCA_INTR_MSCI(node) (node ? 0x10 : 0x01) +#define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02) +#define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04) + +#ifdef __HD64570_H /* HD64570 */ +#define sca_outa(value, reg, card) sca_outw(value, reg, card) +#define sca_ina(reg, card) sca_inw(reg, card) +#define writea(value, ptr) writew(value, ptr) + +static inline int sca_intr_status(card_t *card) +{ + u8 isr0 = sca_in(ISR0, card); + u8 isr1 = sca_in(ISR1, card); + u8 result = 0; + + if (isr1 & 0x03) result |= SCA_INTR_DMAC_RX(0); + if (isr1 & 0x0C) result |= SCA_INTR_DMAC_TX(0); + if (isr1 & 0x30) result |= SCA_INTR_DMAC_RX(1); + if (isr1 & 0xC0) result |= SCA_INTR_DMAC_TX(1); + if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0); + if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1); + + return result; +} + +#else /* HD64572 */ +#define sca_outa(value, reg, card) sca_outl(value, reg, card) +#define sca_ina(reg, card) sca_inl(reg, card) +#define writea(value, ptr) writel(value, ptr) + + +static inline int sca_intr_status(card_t *card) +{ + u32 isr0 = sca_inl(ISR0, card); + u8 result = 0; + + if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0); + if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0); + if (isr0 & 0x00000F00) result |= SCA_INTR_DMAC_RX(1); + if (isr0 & 0x0000F000) result |= SCA_INTR_DMAC_TX(1); + if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0); + if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1); + + return result; +} + +#endif /* HD64570 vs HD64572 */ + + + + +static inline port_t* hdlc_to_port(hdlc_device *hdlc) +{ + return (port_t*)hdlc; +} + + + +static inline port_t* dev_to_port(struct net_device *dev) +{ + return hdlc_to_port(dev_to_hdlc(dev)); +} + + + +static inline u8 next_desc(port_t *port, u8 desc) +{ + return (desc + 1) % port_to_card(port)->ring_buffers; +} + + + +static inline u16 desc_offset(port_t *port, u8 desc, u8 transmit) +{ + /* Descriptor offset always fits in 16 bytes */ + u8 buffs = port_to_card(port)->ring_buffers; + return ((log_node(port) * 2 + transmit) * buffs + (desc % buffs)) * + sizeof(pkt_desc); +} + + + +static inline pkt_desc* desc_address(port_t *port, u8 desc, u8 transmit) +{ +#ifdef PAGE0_ALWAYS_MAPPED + return (pkt_desc*)(win0base(port_to_card(port)) + + desc_offset(port, desc, transmit)); +#else + return (pkt_desc*)(winbase(port_to_card(port)) + + desc_offset(port, desc, transmit)); +#endif +} + + + +static inline u32 buffer_offset(port_t *port, u8 desc, u8 transmit) +{ + u8 buffs = port_to_card(port)->ring_buffers; + return port_to_card(port)->buff_offset + + ((log_node(port) * 2 + transmit) * buffs + (desc % buffs)) * + (u32)HDLC_MAX_MRU; +} + + + +static void sca_init_sync_port(port_t *port) +{ + card_t *card = port_to_card(port); + u8 transmit, i; + u16 dmac, buffs = card->ring_buffers; + + port->rxin = 0; + port->txin = 0; + port->txlast = 0; + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + openwin(card, 0); +#endif + + for (transmit = 0; transmit < 2; transmit++) { + for (i = 0; i < buffs; i++) { + pkt_desc* desc = desc_address(port, i, transmit); + u16 chain_off = desc_offset(port, i + 1, transmit); + u32 buff_off = buffer_offset(port, i, transmit); + + writea(chain_off, &desc->cp); + writel(buff_off, &desc->bp); + writew(0, &desc->len); + writeb(0, &desc->stat); + } + + dmac = transmit ? get_dmac_tx(port) : get_dmac_rx(port); + /* DMA disable - to halt state */ + sca_out(0, transmit ? DSR_TX(phy_node(port)) : + DSR_RX(phy_node(port)), card); + /* software ABORT - to initial state */ + sca_out(DCR_ABORT, transmit ? DCR_TX(phy_node(port)) : + DCR_RX(phy_node(port)), card); + +#ifdef __HD64570_H + sca_out(0, dmac + CPB, card); /* pointer base */ +#endif + /* current desc addr */ + sca_outa(desc_offset(port, 0, transmit), dmac + CDAL, card); + if (!transmit) + sca_outa(desc_offset(port, buffs - 1, transmit), + dmac + EDAL, card); + else + sca_outa(desc_offset(port, 0, transmit), dmac + EDAL, + card); + + /* clear frame end interrupt counter */ + sca_out(DCR_CLEAR_EOF, transmit ? DCR_TX(phy_node(port)) : + DCR_RX(phy_node(port)), card); + + if (!transmit) { /* Receive */ + /* set buffer length */ + sca_outw(HDLC_MAX_MRU, dmac + BFLL, card); + /* Chain mode, Multi-frame */ + sca_out(0x14, DMR_RX(phy_node(port)), card); + sca_out(DIR_EOME | DIR_BOFE, DIR_RX(phy_node(port)), + card); + /* DMA enable */ + sca_out(DSR_DE, DSR_RX(phy_node(port)), card); + } else { /* Transmit */ + /* Chain mode, Multi-frame */ + sca_out(0x14, DMR_TX(phy_node(port)), card); + /* enable underflow interrupts */ + sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card); + } + } +} + + + +/* MSCI interrupt service */ +static inline void sca_msci_intr(port_t *port) +{ + u16 msci = get_msci(port); + card_t* card = port_to_card(port); + u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */ + + /* printk(KERN_DEBUG "MSCI INT: ST1=%02X ILAR=%02X\n", + stat, sca_in(ILAR, card)); */ + + /* Reset MSCI TX underrun status bit */ + sca_out(stat & ST1_UDRN, msci + ST1, card); + + if (stat & ST1_UDRN) { + port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ + port->hdlc.stats.tx_fifo_errors++; + } +} + + + +static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, + u8 rxin) +{ + struct sk_buff *skb; + u16 len; + u32 buff; +#ifndef ALL_PAGES_ALWAYS_MAPPED + u32 maxlen; + u8 page; +#endif + + len = readw(&desc->len); + skb = dev_alloc_skb(len); + if (!skb) { + port->hdlc.stats.rx_dropped++; + return; + } + + buff = buffer_offset(port, rxin, 0); +#ifndef ALL_PAGES_ALWAYS_MAPPED + page = buff / winsize(card); + buff = buff % winsize(card); + maxlen = winsize(card) - buff; + + openwin(card, page); + + if (len > maxlen) { + memcpy_fromio(skb->data, winbase(card) + buff, maxlen); + openwin(card, page + 1); + memcpy_fromio(skb->data + maxlen, winbase(card), len - maxlen); + } else +#endif + memcpy_fromio(skb->data, winbase(card) + buff, len); + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + /* select pkt_desc table page back */ + openwin(card, 0); +#endif + skb_put(skb, len); +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len); + debug_frame(skb); +#endif + port->hdlc.stats.rx_packets++; + port->hdlc.stats.rx_bytes += skb->len; + hdlc_netif_rx(&port->hdlc, skb); +} + + + +/* Receive DMA interrupt service */ +static inline void sca_rx_intr(port_t *port) +{ + u16 dmac = get_dmac_rx(port); + card_t *card = port_to_card(port); + u8 stat = sca_in(DSR_RX(phy_node(port)), card); /* read DMA Status */ + struct net_device_stats *stats = &port->hdlc.stats; + + /* Reset DSR status bits */ + sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, + DSR_RX(phy_node(port)), card); + + if (stat & DSR_BOF) + stats->rx_over_errors++; /* Dropped one or more frames */ + + while (1) { + u32 desc_off = desc_offset(port, port->rxin, 0); + pkt_desc *desc; + u32 cda = sca_ina(dmac + CDAL, card); + + if (cda == desc_off) + break; /* No frame received */ + +#ifdef __HD64572_H + if (cda == desc_off + 8) + break; /* SCA-II updates CDA in 2 steps */ +#endif + + desc = desc_address(port, port->rxin, 0); + stat = readb(&desc->stat); + if (!(stat & ST_RX_EOM)) + port->rxpart = 1; /* partial frame received */ + else if ((stat & ST_ERROR_MASK) || port->rxpart) { + stats->rx_errors++; + if (stat & ST_RX_OVERRUN) stats->rx_fifo_errors++; + else if ((stat & (ST_RX_SHORT | ST_RX_ABORT | + ST_RX_RESBIT)) || port->rxpart) + stats->rx_frame_errors++; + else if (stat & ST_RX_CRC) stats->rx_crc_errors++; + if (stat & ST_RX_EOM) + port->rxpart = 0; /* received last fragment */ + } else + sca_rx(card, port, desc, port->rxin); + + /* Set new error descriptor address */ + sca_outa(desc_off, dmac + EDAL, card); + port->rxin = next_desc(port, port->rxin); + } + + /* make sure RX DMA is enabled */ + sca_out(DSR_DE, DSR_RX(phy_node(port)), card); +} + + + +/* Transmit DMA interrupt service */ +static inline void sca_tx_intr(port_t *port) +{ + u16 dmac = get_dmac_tx(port); + card_t* card = port_to_card(port); + u8 stat; + + spin_lock(&port->lock); + + stat = sca_in(DSR_TX(phy_node(port)), card); /* read DMA Status */ + + /* Reset DSR status bits */ + sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, + DSR_TX(phy_node(port)), card); + + while (1) { + u32 desc_off = desc_offset(port, port->txlast, 1); + pkt_desc *desc; + u16 len; + + if (sca_ina(dmac + CDAL, card) == desc_off) + break; /* Transmitter is/will_be sending this frame */ + + desc = desc_address(port, port->txlast, 1); + len = readw(&desc->len); + + port->hdlc.stats.tx_packets++; + port->hdlc.stats.tx_bytes += len; + writeb(0, &desc->stat); /* Free descriptor */ + + port->txlast = (port->txlast + 1) % + port_to_card(port)->ring_buffers; + } + + netif_wake_queue(hdlc_to_dev(&port->hdlc)); + spin_unlock(&port->lock); +} + + + +static void sca_intr(int irq, void* dev_id, struct pt_regs *regs) +{ + card_t *card = dev_id; + int boguscnt = INTR_WORK; + int i; + u8 stat; + +#ifndef ALL_PAGES_ALWAYS_MAPPED + u8 page = sca_get_page(card); +#endif + + while((stat = sca_intr_status(card)) != 0) { + for (i = 0; i < 2; i++) { + port_t *port = get_port(card, i); + if (port) { + if (stat & SCA_INTR_MSCI(i)) + sca_msci_intr(port); + + if (stat & SCA_INTR_DMAC_RX(i)) + sca_rx_intr(port); + + if (stat & SCA_INTR_DMAC_TX(i)) + sca_tx_intr(port); + } + + if (--boguscnt < 0) { + printk(KERN_ERR "%s: too much work at " + "interrupt\n", + hdlc_to_name(&port->hdlc)); + goto exit; + } + } + } + + exit: +#ifndef ALL_PAGES_ALWAYS_MAPPED + openwin(card, page); /* Restore original page */ +#endif +} + + + +static inline int sca_set_loopback(port_t *port, int line) +{ + card_t* card = port_to_card(port); + u8 msci = get_msci(port); + u8 md2 = sca_in(msci + MD2, card); + + switch(line) { + case LINE_DEFAULT: + md2 &= ~MD2_LOOPBACK; + port->line &= ~LINE_LOOPBACK; + break; + + case LINE_LOOPBACK: + md2 |= MD2_LOOPBACK; + port->line |= LINE_LOOPBACK; + break; + + default: + return -EINVAL; + } + + sca_out(md2, msci + MD2, card); + return 0; +} + + + +static void sca_set_clock(port_t *port) +{ + card_t *card = port_to_card(port); + u8 msci = get_msci(port); + unsigned int tmc, br = 10, brv = 1024; + + if (port->clkrate > 0) { + /* Try lower br for better accuracy*/ + do { + br--; + brv >>= 1; /* brv = 2^9 = 512 max in specs */ + + /* Baud Rate = CLOCK_BASE / TMC / 2^BR */ + tmc = CLOCK_BASE / (brv * port->clkrate); + }while(br > 1 && tmc <= 128); + + if (tmc < 1) { + tmc = 1; + br = 0; /* For baud=CLOCK_BASE we use tmc=1 br=0 */ + brv = 1; + } else if (tmc > 255) + tmc = 256; /* tmc=0 means 256 - low baud rates */ + + port->clkrate = CLOCK_BASE / (brv * tmc); + } else { + br = 9; /* Minimum clock rate */ + tmc = 256; /* 8bit = 0 */ + port->clkrate = CLOCK_BASE / (256 * 512); + } + + port->rxs = (port->rxs & ~CLK_BRG_MASK) | br; + port->txs = (port->txs & ~CLK_BRG_MASK) | br; + port->tmc = tmc; + + /* baud divisor - time constant*/ +#ifdef __HD64570_H + sca_out(port->tmc, msci + TMC, card); +#else + sca_out(port->tmc, msci + TMCR, card); + sca_out(port->tmc, msci + TMCT, card); +#endif + + /* Set BRG bits */ + sca_out(port->rxs, msci + RXS, card); + sca_out(port->txs, msci + TXS, card); +} + + + +static void sca_set_hdlc_mode(port_t *port, u8 idle, u8 crc, u8 nrzi) +{ + card_t* card = port_to_card(port); + u8 msci = get_msci(port); + u8 md2 = (nrzi ? MD2_NRZI : 0) | + ((port->line & LINE_LOOPBACK) ? MD2_LOOPBACK : 0); + u8 ctl = (idle ? CTL_IDLE : 0); +#ifdef __HD64572_H + ctl |= CTL_URCT | CTL_URSKP; /* Skip the rest of underrun frame */ +#endif + + sca_out(CMD_RESET, msci + CMD, card); + sca_out(MD0_HDLC | crc, msci + MD0, card); + sca_out(0x00, msci + MD1, card); /* no address field check */ + sca_out(md2, msci + MD2, card); + sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */ + sca_out(ctl, msci + CTL, card); + +#ifdef __HD64570_H + /* Allow at least 8 bytes before requesting RX DMA operation */ + /* TX with higher priority and possibly with shorter transfers */ + sca_out(0x07, msci + RRC, card); /* +1=RXRDY/DMA activation condition*/ + sca_out(0x10, msci + TRC0, card); /* = TXRDY/DMA activation condition*/ + sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */ +#else + sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */ + /* Setting than to larger value may cause Illegal Access */ + sca_out(0x20, msci + TNR0, card); /* =TX DMA activation condition */ + sca_out(0x30, msci + TNR1, card); /* +1=TX DMA deactivation condition*/ + sca_out(0x04, msci + TCR, card); /* =Critical TX DMA activ condition */ +#endif + + +#ifdef __HD64570_H + /* MSCI TX INT IRQ enable */ + sca_out(IE0_TXINT, msci + IE0, card); + sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun IRQ */ + sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08), + IER0, card); + /* DMA IRQ enable */ + sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F), + IER1, card); +#else + /* MSCI TX INT and underrrun IRQ enable */ + sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card); + /* DMA & MSCI IRQ enable */ + sca_outl(sca_in(IER0, card) | + (phy_node(port) ? 0x02006600 : 0x00020066), IER0, card); +#endif + +#ifdef __HD64570_H + sca_out(port->tmc, msci + TMC, card); /* Restore registers */ +#else + sca_out(port->tmc, msci + TMCR, card); + sca_out(port->tmc, msci + TMCT, card); +#endif + sca_out(port->rxs, msci + RXS, card); + sca_out(port->txs, msci + TXS, card); + sca_out(CMD_TX_ENABLE, msci + CMD, card); + sca_out(CMD_RX_ENABLE, msci + CMD, card); +} + + + +#ifdef DEBUG_RINGS +static void sca_dump_rings(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + card_t *card = port_to_card(port); + u16 cnt; +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + u8 page; +#endif + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + page = sca_get_page(card); + openwin(card, 0); +#endif + + printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u " + "%sactive", + sca_ina(get_dmac_rx(port) + CDAL, card), + sca_ina(get_dmac_rx(port) + EDAL, card), + sca_in(DSR_RX(phy_node(port)), card), + port->rxin, + sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); + for (cnt = 0; cntring_buffers; cnt++) + printk(" %02X", + readb(&(desc_address(port, cnt, 0)->stat))); + + printk("\n" KERN_ERR "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " + "last=%u %sactive", + sca_ina(get_dmac_tx(port) + CDAL, card), + sca_ina(get_dmac_tx(port) + EDAL, card), + sca_in(DSR_TX(phy_node(port)), card), port->txin, + port->txlast, + sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); + + for (cnt = 0; cntring_buffers; cnt++) + printk(" %02X", + readb(&(desc_address(port, cnt, 1)->stat))); + printk("\n"); + + printk(KERN_ERR "MSCI: MD: %02x %02x %02x, " + "ST: %02x %02x %02x %02x" +#ifdef __HD64572_H + " %02x" +#endif + ", FST: %02x CST: %02x %02x\n", + sca_in(get_msci(port) + MD0, card), + sca_in(get_msci(port) + MD1, card), + sca_in(get_msci(port) + MD2, card), + sca_in(get_msci(port) + ST0, card), + sca_in(get_msci(port) + ST1, card), + sca_in(get_msci(port) + ST2, card), + sca_in(get_msci(port) + ST3, card), +#ifdef __HD64572_H + sca_in(get_msci(port) + ST4, card), +#endif + sca_in(get_msci(port) + FST, card), + sca_in(get_msci(port) + CST0, card), + sca_in(get_msci(port) + CST1, card)); + +#ifdef __HD64572_H + printk(KERN_ERR "ILAR: %02x\n", sca_in(ILAR, card)); +#endif + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + openwin(card, page); /* Restore original page */ +#endif +} +#endif /* DEBUG_RINGS */ + + + +static void sca_open(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + + sca_set_hdlc_mode(port, 1, MD0_CRC_ITU, 0); + netif_start_queue(hdlc_to_dev(hdlc)); +} + + +static void sca_close(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + + /* reset channel */ + netif_stop_queue(hdlc_to_dev(hdlc)); + sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); +} + + + +static int sca_xmit(hdlc_device *hdlc, struct sk_buff *skb) +{ + port_t *port = hdlc_to_port(hdlc); + struct net_device *dev = hdlc_to_dev(hdlc); + card_t *card = port_to_card(port); + pkt_desc *desc; + u32 buff, len; +#ifndef ALL_PAGES_ALWAYS_MAPPED + u8 page; + u32 maxlen; +#endif + + spin_lock_irq(&port->lock); + + desc = desc_address(port, port->txin + 1, 1); + if (readb(&desc->stat)) { /* allow 1 packet gap */ + /* should never happen - previous xmit should stop queue */ +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); +#endif + netif_stop_queue(dev); + spin_unlock_irq(&port->lock); + return 1; /* request packet to be queued */ + } + +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len); + debug_frame(skb); +#endif + + desc = desc_address(port, port->txin, 1); + buff = buffer_offset(port, port->txin, 1); + len = skb->len; +#ifndef ALL_PAGES_ALWAYS_MAPPED + page = buff / winsize(card); + buff = buff % winsize(card); + maxlen = winsize(card) - buff; + + openwin(card, page); + if (len > maxlen) { + memcpy_toio(winbase(card) + buff, skb->data, maxlen); + openwin(card, page + 1); + memcpy_toio(winbase(card), skb->data + maxlen, len - maxlen); + } + else +#endif + memcpy_toio(winbase(card) + buff, skb->data, len); + +#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) + openwin(card, 0); /* select pkt_desc table page back */ +#endif + writew(len, &desc->len); + writeb(ST_TX_EOM, &desc->stat); + dev->trans_start = jiffies; + + port->txin = next_desc(port, port->txin); + sca_outa(desc_offset(port, port->txin, 1), + get_dmac_tx(port) + EDAL, card); + + sca_out(DSR_DE, DSR_TX(phy_node(port)), card); /* Enable TX DMA */ + + desc = desc_address(port, port->txin + 1, 1); + if (readb(&desc->stat)) /* allow 1 packet gap */ + netif_stop_queue(hdlc_to_dev(&port->hdlc)); + + spin_unlock_irq(&port->lock); + + dev_kfree_skb(skb); + return 0; +} + + +static void sca_init(card_t *card, int wait_states) +{ + sca_out(wait_states, WCRL, card); /* Wait Control */ + sca_out(wait_states, WCRM, card); + sca_out(wait_states, WCRH, card); + + sca_out(0, DMER, card); /* DMA Master disable */ + sca_out(0x03, PCR, card); /* DMA priority */ + sca_out(0, IER1, card); /* DMA interrupt disable */ + sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ + sca_out(0, DSR_TX(0), card); + sca_out(0, DSR_RX(1), card); + sca_out(0, DSR_TX(1), card); + sca_out(DMER_DME, DMER, card); /* DMA Master enable */ +} diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/hdlc.c linux/drivers/net/wan/hdlc.c --- v2.4.2/linux/drivers/net/wan/hdlc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/hdlc.c Tue Mar 6 19:44:36 2001 @@ -0,0 +1,1454 @@ +/* + * Generic HDLC support routines for Linux + * + * Copyright (C) 1999, 2000 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Current status: + * - this is work in progress + * - not heavily tested on SMP + * - currently supported: + * * raw IP-in-HDLC + * * Cisco HDLC + * * Frame Relay with ANSI or CCITT LMI (both user and network side) + * * PPP (using syncppp.c) + * * X.25 + * + * Use sethdlc utility to set line parameters, protocol and PVCs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define DEBUG_PKT */ +/* #define DEBUG_HARD_HEADER */ +/* #define DEBUG_FECN */ +/* #define DEBUG_BECN */ + +static const char* version = "HDLC support module revision 1.02 for Linux 2.4"; + + +#define CISCO_MULTICAST 0x8F /* Cisco multicast address */ +#define CISCO_UNICAST 0x0F /* Cisco unicast address */ +#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ +#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */ +#define CISCO_ADDR_REQ 0 /* Cisco address request */ +#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ +#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ + +static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + +/******************************************************** + * + * Cisco HDLC support + * + *******************************************************/ + +static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, + u16 type, void *daddr, void *saddr, + unsigned int len) +{ + hdlc_header *data; +#ifdef DEBUG_HARD_HEADER + printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); +#endif + + skb_push(skb, sizeof(hdlc_header)); + data = (hdlc_header*)skb->data; + if (type == CISCO_KEEPALIVE) + data->address = CISCO_MULTICAST; + else + data->address = CISCO_UNICAST; + data->control = 0; + data->protocol = htons(type); + + return sizeof(hdlc_header); +} + + + +static void cisco_keepalive_send(hdlc_device *hdlc, u32 type, + u32 par1, u32 par2) +{ + struct sk_buff *skb; + cisco_packet *data; + + skb = dev_alloc_skb(sizeof(hdlc_header)+sizeof(cisco_packet)); + if (!skb) { + printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n", + hdlc_to_name(hdlc)); + return; + } + skb_reserve(skb, 4); + cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE, + NULL, NULL, 0); + data = (cisco_packet*)skb->tail; + + data->type = htonl(type); + data->par1 = htonl(par1); + data->par2 = htonl(par2); + data->rel = 0xFFFF; + data->time = htonl(jiffies * 1000 / HZ); + + skb_put(skb, sizeof(cisco_packet)); + skb->priority = TC_PRIO_CONTROL; + skb->dev = hdlc_to_dev(hdlc); + + dev_queue_xmit(skb); +} + + + +static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb) +{ + hdlc_header *data = (hdlc_header*)skb->data; + cisco_packet *cisco_data; + struct in_device *in_dev; + u32 addr, mask; + + if (skb->lenaddress != CISCO_MULTICAST && + data->address != CISCO_UNICAST) + goto rx_error; + + skb_pull(skb, sizeof(hdlc_header)); + + switch(ntohs(data->protocol)) { + case ETH_P_IP: + case ETH_P_IPX: + case ETH_P_IPV6: + skb->protocol = data->protocol; + skb->dev = hdlc_to_dev(hdlc); + netif_rx(skb); + return; + + case CISCO_SYS_INFO: + /* Packet is not needed, drop it. */ + dev_kfree_skb_any(skb); + return; + + case CISCO_KEEPALIVE: + if (skb->len != CISCO_PACKET_LEN && + skb->len != CISCO_BIG_PACKET_LEN) { + printk(KERN_INFO "%s: Invalid length of Cisco " + "control packet (%d bytes)\n", + hdlc_to_name(hdlc), skb->len); + goto rx_error; + } + + cisco_data = (cisco_packet*)skb->data; + + switch(ntohl (cisco_data->type)) { + case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ + in_dev = hdlc_to_dev(hdlc)->ip_ptr; + addr = 0; + mask = ~0; /* is the mask correct? */ + + if (in_dev != NULL) { + struct in_ifaddr **ifap = &in_dev->ifa_list; + + while (*ifap != NULL) { + if (strcmp(hdlc_to_name(hdlc), + (*ifap)->ifa_label) == 0) { + addr = (*ifap)->ifa_local; + mask = (*ifap)->ifa_mask; + break; + } + ifap = &(*ifap)->ifa_next; + } + + cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY, + addr, mask); + } + dev_kfree_skb_any(skb); + return; + + case CISCO_ADDR_REPLY: + printk(KERN_INFO "%s: Unexpected Cisco IP address " + "reply\n", hdlc_to_name(hdlc)); + goto rx_error; + + case CISCO_KEEPALIVE_REQ: + hdlc->lmi.rxseq = ntohl(cisco_data->par1); + if (ntohl(cisco_data->par2) == hdlc->lmi.txseq) { + hdlc->lmi.last_poll = jiffies; + if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) { + u32 sec, min, hrs, days; + sec = ntohl(cisco_data->time) / 1000; + min = sec / 60; sec -= min * 60; + hrs = min / 60; min -= hrs * 60; + days = hrs / 24; hrs -= days * 24; + printk(KERN_INFO "%s: Link up (peer " + "uptime %ud%uh%um%us)\n", + hdlc_to_name(hdlc), days, hrs, + min, sec); + } + hdlc->lmi.state |= LINK_STATE_RELIABLE; + } + + dev_kfree_skb_any(skb); + return; + } /* switch(keepalive type) */ + } /* switch(protocol) */ + + printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc), + data->protocol); + dev_kfree_skb_any(skb); + return; + + rx_error: + hdlc->stats.rx_errors++; /* Mark error */ + dev_kfree_skb_any(skb); +} + + + +static void cisco_timer(unsigned long arg) +{ + hdlc_device *hdlc = (hdlc_device*)arg; + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) && + (jiffies - hdlc->lmi.last_poll >= hdlc->lmi.T392 * HZ)) { + hdlc->lmi.state &= ~LINK_STATE_RELIABLE; + printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc)); + } + + cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, ++hdlc->lmi.txseq, + hdlc->lmi.rxseq); + hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ; + + hdlc->timer.function = cisco_timer; + hdlc->timer.data = arg; + add_timer(&hdlc->timer); +} + + + +/****************************************************************** + * + * generic Frame Relay routines + * + *****************************************************************/ + + +static int fr_hard_header(struct sk_buff *skb, struct net_device *dev, + u16 type, void *daddr, void *saddr, unsigned int len) +{ + u16 head_len; + + if (!daddr) + daddr = dev->broadcast; + +#ifdef DEBUG_HARD_HEADER + printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name); +#endif + + switch(type) { + case ETH_P_IP: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = NLPID_IP; + break; + + case ETH_P_IPV6: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = NLPID_IPV6; + break; + + case LMI_PROTO: + head_len = 4; + skb_push(skb, head_len); + skb->data[3] = LMI_PROTO; + break; + + default: + head_len = 10; + skb_push(skb, head_len); + skb->data[3] = FR_PAD; + skb->data[4] = NLPID_SNAP; + skb->data[5] = FR_PAD; + skb->data[6] = FR_PAD; + skb->data[7] = FR_PAD; + skb->data[8] = type>>8; + skb->data[9] = (u8)type; + } + + memcpy(skb->data, daddr, 2); + skb->data[2] = FR_UI; + + return head_len; +} + + + +static inline void fr_log_dlci_active(pvc_device *pvc) +{ + printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc), + pvc->state & PVC_STATE_ACTIVE ? "" : "in", + pvc->state & PVC_STATE_NEW ? " new" : ""); +} + + + +static inline u8 fr_lmi_nextseq(u8 x) +{ + x++; + return x ? x : 1; +} + + + +static void fr_lmi_send(hdlc_device *hdlc, int fullrep) +{ + struct sk_buff *skb; + pvc_device *pvc = hdlc->first_pvc; + int len = mode_is(hdlc, MODE_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH; + int stat_len = 3; + u8 *data; + int i = 0; + + if (mode_is(hdlc, MODE_DCE) && fullrep) { + len += hdlc->pvc_count * (2 + stat_len); + if (len > HDLC_MAX_MTU) { + printk(KERN_WARNING "%s: Too many PVCs while sending " + "LMI full report\n", hdlc_to_name(hdlc)); + return; + } + } + + skb = dev_alloc_skb(len); + if (!skb) { + printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n", + hdlc_to_name(hdlc)); + return; + } + memset(skb->data, 0, len); + skb_reserve(skb, 4); + fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0); + data = skb->tail; + data[i++] = LMI_CALLREF; + data[i++] = mode_is(hdlc, MODE_DCE) ? LMI_STATUS : LMI_STATUS_ENQUIRY; + if (mode_is(hdlc, MODE_FR_ANSI)) + data[i++] = LMI_ANSI_LOCKSHIFT; + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : + LMI_REPTYPE; + data[i++] = LMI_REPT_LEN; + data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; + + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE; + data[i++] = LMI_INTEG_LEN; + data[i++] = hdlc->lmi.txseq = fr_lmi_nextseq(hdlc->lmi.txseq); + data[i++] = hdlc->lmi.rxseq; + + if (mode_is(hdlc, MODE_DCE) && fullrep) { + while (pvc) { + data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? + LMI_CCITT_PVCSTAT:LMI_PVCSTAT; + data[i++] = stat_len; + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) && + (pvc->netdev.flags & IFF_UP) && + !(pvc->state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) { + pvc->state |= PVC_STATE_NEW; + fr_log_dlci_active(pvc); + } + + dlci_to_status(hdlc, netdev_dlci(&pvc->netdev), + data+i, pvc->state); + i += stat_len; + pvc = pvc->next; + } + } + + skb_put(skb, i); + skb->priority = TC_PRIO_CONTROL; + skb->dev = hdlc_to_dev(hdlc); + + dev_queue_xmit(skb); +} + + + +static void fr_timer(unsigned long arg) +{ + hdlc_device *hdlc = (hdlc_device*)arg; + int i, cnt = 0, reliable; + u32 list; + + if (mode_is(hdlc, MODE_DCE)) + reliable = (jiffies - hdlc->lmi.last_poll < hdlc->lmi.T392*HZ); + else { + hdlc->lmi.last_errors <<= 1; /* Shift the list */ + if (hdlc->lmi.state & LINK_STATE_REQUEST) { + printk(KERN_INFO "%s: No LMI status reply received\n", + hdlc_to_name(hdlc)); + hdlc->lmi.last_errors |= 1; + } + + for (i = 0, list = hdlc->lmi.last_errors; i < hdlc->lmi.N393; + i++, list >>= 1) + cnt += (list & 1); /* errors count */ + + reliable = (cnt < hdlc->lmi.N392); + } + + if ((hdlc->lmi.state & LINK_STATE_RELIABLE) != + (reliable ? LINK_STATE_RELIABLE : 0)) { + pvc_device *pvc = hdlc->first_pvc; + + while (pvc) {/* Deactivate all PVCs */ + pvc->state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE); + pvc = pvc->next; + } + + hdlc->lmi.state ^= LINK_STATE_RELIABLE; + printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc), + reliable ? "" : "un"); + + if (reliable) { + hdlc->lmi.N391cnt = 0; /* Request full status */ + hdlc->lmi.state |= LINK_STATE_CHANGED; + } + } + + if (mode_is(hdlc, MODE_DCE)) + hdlc->timer.expires = jiffies + hdlc->lmi.T392*HZ; + else { + if (hdlc->lmi.N391cnt) + hdlc->lmi.N391cnt--; + + fr_lmi_send(hdlc, hdlc->lmi.N391cnt == 0); + + hdlc->lmi.state |= LINK_STATE_REQUEST; + hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ; + } + + hdlc->timer.function = fr_timer; + hdlc->timer.data = arg; + add_timer(&hdlc->timer); +} + + + +static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) +{ + int stat_len; + pvc_device *pvc; + int reptype = -1, error; + u8 rxseq, txseq; + int i; + + if (skb->len < (mode_is(hdlc, MODE_FR_ANSI) ? + LMI_ANSI_LENGTH : LMI_LENGTH)) { + printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc)); + return 1; + } + + if (skb->data[5] != (!mode_is(hdlc, MODE_DCE) ? + LMI_STATUS : LMI_STATUS_ENQUIRY)) { + printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n", + hdlc_to_name(hdlc), skb->data[2], + mode_is(hdlc, MODE_DCE) ? "enquiry" : "reply"); + return 1; + } + + i = mode_is(hdlc, MODE_FR_ANSI) ? 7 : 6; + + if (skb->data[i] != + (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) { + printk(KERN_INFO "%s: Not a report type=%x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + i++; /* Skip length field */ + + reptype = skb->data[i++]; + + if (skb->data[i]!= + (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) { + printk(KERN_INFO "%s: Unsupported status element=%x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + i++; /* Skip length field */ + + hdlc->lmi.rxseq = skb->data[i++]; /* TX sequence from peer */ + rxseq = skb->data[i++]; /* Should confirm our sequence */ + + txseq = hdlc->lmi.txseq; + + if (mode_is(hdlc, MODE_DCE)) { + if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) { + printk(KERN_INFO "%s: Unsupported report type=%x\n", + hdlc_to_name(hdlc), reptype); + return 1; + } + } + + error = 0; + if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) + error = 1; + + if (rxseq == 0 || rxseq != txseq) { + hdlc->lmi.N391cnt = 0; /* Ask for full report next time */ + error = 1; + } + + if (mode_is(hdlc, MODE_DCE)) { + if ((hdlc->lmi.state & LINK_STATE_FULLREP_SENT) && !error) { +/* Stop sending full report - the last one has been confirmed by DTE */ + hdlc->lmi.state &= ~LINK_STATE_FULLREP_SENT; + pvc = hdlc->first_pvc; + while (pvc) { + if (pvc->state & PVC_STATE_NEW) { + pvc->state &= ~PVC_STATE_NEW; + pvc->state |= PVC_STATE_ACTIVE; + fr_log_dlci_active(pvc); + +/* Tell DTE that new PVC is now active */ + hdlc->lmi.state |= LINK_STATE_CHANGED; + } + pvc = pvc->next; + } + } + + if (hdlc->lmi.state & LINK_STATE_CHANGED) { + reptype = LMI_FULLREP; + hdlc->lmi.state |= LINK_STATE_FULLREP_SENT; + hdlc->lmi.state &= ~LINK_STATE_CHANGED; + } + + fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0); + return 0; + } + + /* DTE */ + + if (reptype != LMI_FULLREP || error) + return 0; + + stat_len = 3; + pvc = hdlc->first_pvc; + + while (pvc) { + pvc->newstate = 0; + pvc = pvc->next; + } + + while (skb->len >= i + 2 + stat_len) { + u16 dlci; + u8 state = 0; + + if (skb->data[i] != (mode_is(hdlc, MODE_FR_CCITT) ? + LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) { + printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + if (skb->data[i] != stat_len) { + printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n", + hdlc_to_name(hdlc), skb->data[i]); + return 1; + } + i++; + + dlci = status_to_dlci(hdlc, skb->data+i, &state); + pvc = find_pvc(hdlc, dlci); + + if (pvc) + pvc->newstate = state; + else if (state == PVC_STATE_NEW) + printk(KERN_INFO "%s: new PVC available, DLCI=%u\n", + hdlc_to_name(hdlc), dlci); + + i += stat_len; + } + + pvc = hdlc->first_pvc; + + while (pvc) { + if (pvc->newstate == PVC_STATE_NEW) + pvc->newstate = PVC_STATE_ACTIVE; + + pvc->newstate |= (pvc->state & + ~(PVC_STATE_NEW|PVC_STATE_ACTIVE)); + if (pvc->state != pvc->newstate) { + pvc->state = pvc->newstate; + fr_log_dlci_active(pvc); + } + pvc = pvc->next; + } + + /* Next full report after N391 polls */ + hdlc->lmi.N391cnt = hdlc->lmi.N391; + + return 0; +} + + + +static void fr_netif(hdlc_device *hdlc, struct sk_buff *skb) +{ + fr_hdr *fh = (fr_hdr*)skb->data; + u8 *data = skb->data; + u16 dlci; + pvc_device *pvc; + + if (skb->len<4 || fh->ea1 || data[2] != FR_UI) + goto rx_error; + + dlci = q922_to_dlci(skb->data); + + if (dlci == LMI_DLCI) { + if (data[3] == LMI_PROTO) { + if (fr_lmi_recv(hdlc, skb)) + goto rx_error; + else { + /* No request pending */ + hdlc->lmi.state &= ~LINK_STATE_REQUEST; + hdlc->lmi.last_poll = jiffies; + dev_kfree_skb_any(skb); + return; + } + } + + printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n", + hdlc_to_name(hdlc)); + goto rx_error; + } + + pvc = find_pvc(hdlc, dlci); + if (!pvc) { +#ifdef DEBUG_PKT + printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", + hdlc_to_name(hdlc), dlci); +#endif + goto rx_error; + } + + if ((pvc->netdev.flags & IFF_UP) == 0) { +#ifdef DEBUG_PKT + printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n", + hdlc_to_name(hdlc), dlci); +#endif + goto rx_error; + } + + pvc->stats.rx_packets++; /* PVC traffic */ + pvc->stats.rx_bytes += skb->len; + + if ((pvc->state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) { +#ifdef DEBUG_FECN + printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc), + fh->fecn ? "N" : "FF"); +#endif + pvc->state ^= PVC_STATE_FECN; + } + + if ((pvc->state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) { +#ifdef DEBUG_FECN + printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc), + fh->becn ? "N" : "FF"); +#endif + pvc->state ^= PVC_STATE_BECN; + } + + if (pvc->state & PVC_STATE_BECN) + pvc->stats.rx_compressed++; + + if (data[3] == NLPID_IP) { + skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + skb->protocol = htons(ETH_P_IP); + skb->dev = &pvc->netdev; + netif_rx(skb); + return; + } + + + if (data[3] == NLPID_IPV6) { + skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ + skb->protocol = htons(ETH_P_IPV6); + skb->dev = &pvc->netdev; + netif_rx(skb); + return; + } + + if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD && + data[6] == FR_PAD && data[7] == FR_PAD && + ((data[8]<<8) | data[9]) == ETH_P_ARP) { + skb_pull(skb, 10); + skb->protocol = htons(ETH_P_ARP); + skb->dev = &pvc->netdev; + netif_rx(skb); + return; + } + + printk(KERN_INFO "%s: Unusupported protocol %x\n", + hdlc_to_name(hdlc), data[3]); + dev_kfree_skb_any(skb); + return; + + rx_error: + hdlc->stats.rx_errors++; /* Mark error */ + dev_kfree_skb_any(skb); +} + + + +static void fr_cisco_open(hdlc_device *hdlc) +{ + hdlc->lmi.state = LINK_STATE_CHANGED; + hdlc->lmi.txseq = hdlc->lmi.rxseq = 0; + hdlc->lmi.last_errors = 0xFFFFFFFF; + hdlc->lmi.N391cnt = 0; + + init_timer(&hdlc->timer); + hdlc->timer.expires = jiffies + HZ; /* First poll after 1 second */ + hdlc->timer.function = mode_is(hdlc, MODE_FR) ? fr_timer : cisco_timer; + hdlc->timer.data = (unsigned long)hdlc; + add_timer(&hdlc->timer); +} + + + +static void fr_cisco_close(hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->first_pvc; + + del_timer_sync(&hdlc->timer); + + while(pvc) { /* NULL in Cisco mode */ + dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */ + pvc = pvc->next; + } +} + + + +/****************************************************************** + * + * generic HDLC routines + * + *****************************************************************/ + + + +static int hdlc_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + + + +/******************************************************** + * + * PVC device routines + * + *******************************************************/ + +static int pvc_open(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + int result = 0; + + if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0) + return -EIO; /* Master must be UP in order to activate PVC */ + + memset(&(pvc->stats), 0, sizeof(struct net_device_stats)); + pvc->state = 0; + + if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->open_pvc) + result = pvc->master->open_pvc(pvc); + if (result) + return result; + + pvc->master->lmi.state |= LINK_STATE_CHANGED; + return 0; +} + + + +static int pvc_close(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + pvc->state = 0; + + if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->close_pvc) + pvc->master->close_pvc(pvc); + + pvc->master->lmi.state |= LINK_STATE_CHANGED; + return 0; +} + + + +static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + + if (pvc->state & PVC_STATE_ACTIVE) { + skb->dev = hdlc_to_dev(pvc->master); + pvc->stats.tx_bytes += skb->len; + pvc->stats.tx_packets++; + if (pvc->state & PVC_STATE_FECN) + pvc->stats.tx_compressed++; /* TX Congestion counter */ + dev_queue_xmit(skb); + } else { + pvc->stats.tx_dropped++; + dev_kfree_skb(skb); + } + + return 0; +} + + + +static struct net_device_stats *pvc_get_stats(struct net_device *dev) +{ + pvc_device *pvc = dev_to_pvc(dev); + return &pvc->stats; +} + + + +static int pvc_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + + + +static void destroy_pvc_list(hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->first_pvc; + while(pvc) { + pvc_device *next = pvc->next; + unregister_netdevice(&pvc->netdev); + kfree(pvc); + pvc = next; + } + + hdlc->first_pvc = NULL; /* All PVCs destroyed */ + hdlc->pvc_count = 0; + hdlc->lmi.state |= LINK_STATE_CHANGED; +} + + + +/******************************************************** + * + * X.25 protocol support routines + * + *******************************************************/ + +#ifdef CONFIG_HDLC_X25 +/* These functions are callbacks called by LAPB layer */ + +void x25_connect_disconnect(void *token, int reason, int code) +{ + hdlc_device *hdlc = token; + struct sk_buff *skb; + unsigned char *ptr; + + if ((skb = dev_alloc_skb(1)) == NULL) { + printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc)); + return; + } + + ptr = skb_put(skb, 1); + *ptr = code; + + skb->dev = hdlc_to_dev(hdlc); + skb->protocol = htons(ETH_P_X25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + netif_rx(skb); +} + +void x25_connected(void *token, int reason) +{ + x25_connect_disconnect(token, reason, 1); +} + +void x25_disconnected(void *token, int reason) +{ + x25_connect_disconnect(token, reason, 2); +} + + +int x25_data_indication(void *token, struct sk_buff *skb) +{ + hdlc_device *hdlc = token; + unsigned char *ptr; + + ptr = skb_push(skb, 1); + *ptr = 0; + + skb->dev = hdlc_to_dev(hdlc); + skb->protocol = htons(ETH_P_X25); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_HOST; + + return netif_rx(skb); +} + + +void x25_data_transmit(void *token, struct sk_buff *skb) +{ + hdlc_device *hdlc = token; + hdlc->xmit(hdlc, skb); /* Ignore return value :-( */ +} +#endif /* CONFIG_HDLC_X25 */ + + +/******************************************************** + * + * HDLC device routines + * + *******************************************************/ + +static int hdlc_open(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + int result; + + if (hdlc->mode == MODE_NONE) + return -ENOSYS; + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_open(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_attach(&hdlc->pppdev); + /* sppp_attach nukes them. We don't need syncppp's ioctl */ + dev->do_ioctl = hdlc_ioctl; + hdlc->pppdev.sppp.pp_flags &= ~PP_CISCO; + dev->type = ARPHRD_PPP; + result = sppp_open(dev); + if (result) { + sppp_detach(dev); + return result; + } + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) { + struct lapb_register_struct cb; + + cb.connect_confirmation = x25_connected; + cb.connect_indication = x25_connected; + cb.disconnect_confirmation = x25_disconnected; + cb.disconnect_indication = x25_disconnected; + cb.data_indication = x25_data_indication; + cb.data_transmit = x25_data_transmit; + + result = lapb_register(hdlc, &cb); + if (result != LAPB_OK) + return result; + } +#endif + result = hdlc->open(hdlc); + if (result) { + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_close(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_close(dev); + sppp_detach(dev); + dev->rebuild_header = NULL; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + dev->hard_header_len = 16; + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) + lapb_unregister(hdlc); +#endif + } + + return result; +} + + + +static int hdlc_close(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + hdlc->close(hdlc); + + if (mode_is(hdlc, MODE_FR | MODE_SOFT) || + mode_is(hdlc, MODE_CISCO | MODE_SOFT)) + fr_cisco_close(hdlc); +#ifdef CONFIG_HDLC_PPP + else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) { + sppp_close(dev); + sppp_detach(dev); + dev->rebuild_header = NULL; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + dev->hard_header_len = 16; + } +#endif +#ifdef CONFIG_HDLC_X25 + else if (mode_is(hdlc, MODE_X25)) + lapb_unregister(hdlc); +#endif + return 0; +} + + + +static int hdlc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + +#ifdef CONFIG_HDLC_X25 + if (mode_is(hdlc, MODE_X25 | MODE_SOFT)) { + int result; + + + /* X.25 to LAPB */ + switch (skb->data[0]) { + case 0: /* Data to be transmitted */ + skb_pull(skb, 1); + if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK) + dev_kfree_skb(skb); + return 0; + + case 1: + if ((result = lapb_connect_request(hdlc))!= LAPB_OK) { + if (result == LAPB_CONNECTED) { + /* Send connect confirm. msg to level 3 */ + x25_connected(hdlc, 0); + } else { + printk(KERN_ERR "%s: LAPB connect " + "request failed, error code = " + "%i\n", hdlc_to_name(hdlc), + result); + } + } + break; + + case 2: + if ((result=lapb_disconnect_request(hdlc))!=LAPB_OK) { + if (result == LAPB_NOTCONNECTED) { + /* Send disconnect confirm. msg to level 3 */ + x25_disconnected(hdlc, 0); + } else { + printk(KERN_ERR "%s: LAPB disconnect " + "request failed, error code = " + "%i\n", hdlc_to_name(hdlc), + result); + } + } + break; + + default: /* to be defined */ + } + + dev_kfree_skb(skb); + return 0; + } /* MODE_X25 */ +#endif /* CONFIG_HDLC_X25 */ + + return hdlc->xmit(hdlc, skb); +} + + + +void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb) +{ +/* skb contains raw HDLC frame, in both hard- and software modes */ + skb->mac.raw = skb->data; + + switch(hdlc->mode & MODE_MASK) { + case MODE_HDLC: + skb->protocol = htons(ETH_P_IP); + skb->dev = hdlc_to_dev(hdlc); + netif_rx(skb); + return; + + case MODE_FR: + fr_netif(hdlc, skb); + return; + + case MODE_CISCO: + cisco_netif(hdlc, skb); + return; + +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: +#if 0 + sppp_input(hdlc_to_dev(hdlc), skb); +#else + skb->protocol = htons(ETH_P_WAN_PPP); + skb->dev = hdlc_to_dev(hdlc); + netif_rx(skb); +#endif + return; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: + skb->dev = hdlc_to_dev(hdlc); + if (lapb_data_received(hdlc, skb) == LAPB_OK) + return; + break; +#endif + } + + hdlc->stats.rx_errors++; + dev_kfree_skb_any(skb); +} + + + +static struct net_device_stats *hdlc_get_stats(struct net_device *dev) +{ + return &dev_to_hdlc(dev)->stats; +} + + + +static int hdlc_set_mode(hdlc_device *hdlc, int mode) +{ + int result = -1; /* Default to soft modes */ + struct net_device *dev = hdlc_to_dev(hdlc); + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(dev->flags & IFF_UP) + return -EBUSY; + + dev->addr_len = 0; + dev->hard_header = NULL; + hdlc->mode = MODE_NONE; + + if (!(mode & MODE_SOFT)) + switch(mode & MODE_MASK) { + case MODE_HDLC: + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, MODE_HDLC) : 0; + break; + + case MODE_CISCO: /* By card */ +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: +#endif + case MODE_FR: + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, mode) : -ENOSYS; + break; + + default: + return -EINVAL; + } + + if (result) { + mode |= MODE_SOFT; /* Try "host software" protocol */ + + switch(mode & MODE_MASK) { + case MODE_CISCO: + dev->hard_header = cisco_hard_header; + break; + +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: + break; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: + break; +#endif + + case MODE_FR: + dev->hard_header = fr_hard_header; + dev->addr_len = 2; + *(u16*)dev->dev_addr = htons(LMI_DLCI); + dlci_to_q922(dev->broadcast, LMI_DLCI); + break; + + default: + return -EINVAL; + } + + result = hdlc->set_mode ? + hdlc->set_mode(hdlc, MODE_HDLC) : 0; + } + + if (result) + return result; + + hdlc->mode = mode; + switch(mode & MODE_MASK) { +#ifdef CONFIG_HDLC_PPP + case MODE_PPP: dev->type = ARPHRD_PPP; break; +#endif +#ifdef CONFIG_HDLC_X25 + case MODE_X25: dev->type = ARPHRD_X25; break; +#endif + case MODE_FR: dev->type = ARPHRD_FRAD; break; + case MODE_CISCO: dev->type = ARPHRD_CISCO; break; + default: dev->type = ARPHRD_RAWHDLC; + } + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + destroy_pvc_list(hdlc); + return 0; +} + + + +static int hdlc_fr_pvc(hdlc_device *hdlc, int dlci) +{ + pvc_device **pvc_p = &hdlc->first_pvc; + pvc_device *pvc; + int result, create = 1; /* Create or delete PVC */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + if(dlci<0) { + dlci = -dlci; + create = 0; + } + + if(dlci <= 0 || dlci >= 1024) + return -EINVAL; /* Only 10 bits for DLCI, DLCI=0 is reserved */ + + if(!mode_is(hdlc, MODE_FR)) + return -EINVAL; /* Only meaningfull on FR */ + + while(*pvc_p) { + if (netdev_dlci(&(*pvc_p)->netdev) == dlci) + break; + pvc_p = &(*pvc_p)->next; + } + + if (create) { /* Create PVC */ + if (*pvc_p != NULL) + return -EEXIST; + + pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL); + if (!pvc) { + printk(KERN_WARNING "%s: Memory squeeze on " + "hdlc_fr_pvc()\n", hdlc_to_name(hdlc)); + return -ENOBUFS; + } + memset(pvc, 0, sizeof(pvc_device)); + + pvc->netdev.hard_start_xmit = pvc_xmit; + pvc->netdev.get_stats = pvc_get_stats; + pvc->netdev.open = pvc_open; + pvc->netdev.stop = pvc_close; + pvc->netdev.change_mtu = pvc_change_mtu; + pvc->netdev.mtu = HDLC_MAX_MTU; + + pvc->netdev.type = ARPHRD_DLCI; + pvc->netdev.hard_header_len = 16; + pvc->netdev.hard_header = fr_hard_header; + pvc->netdev.tx_queue_len = 0; + pvc->netdev.flags = IFF_POINTOPOINT; + + dev_init_buffers(&pvc->netdev); + + pvc->master = hdlc; + *(u16*)pvc->netdev.dev_addr = htons(dlci); + dlci_to_q922(pvc->netdev.broadcast, dlci); + pvc->netdev.addr_len = 2; + pvc->netdev.irq = hdlc_to_dev(hdlc)->irq; + + result = dev_alloc_name(&pvc->netdev, "pvc%d"); + if (result < 0) { + kfree(pvc); + *pvc_p = NULL; + return result; + } + + if (register_netdevice(&pvc->netdev) != 0) { + kfree(pvc); + *pvc_p = NULL; + return -EIO; + } + + if (!mode_is(hdlc, MODE_SOFT) && hdlc->create_pvc) { + result = hdlc->create_pvc(pvc); + if (result) { + unregister_netdevice(&pvc->netdev); + kfree(pvc); + *pvc_p = NULL; + return result; + } + } + + hdlc->lmi.state |= LINK_STATE_CHANGED; + hdlc->pvc_count++; + return 0; + } + + if (*pvc_p == NULL) /* Delete PVC */ + return -ENOENT; + + pvc = *pvc_p; + + if (pvc->netdev.flags & IFF_UP) + return -EBUSY; /* PVC in use */ + + if (!mode_is(hdlc, MODE_SOFT) && hdlc->destroy_pvc) + hdlc->destroy_pvc(pvc); + + hdlc->lmi.state |= LINK_STATE_CHANGED; + hdlc->pvc_count--; + *pvc_p = pvc->next; + unregister_netdevice(&pvc->netdev); + kfree(pvc); + return 0; +} + + + +static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + switch(cmd) { + case HDLCGMODE: + ifr->ifr_ifru.ifru_ivalue = hdlc->mode; + return 0; + + case HDLCSMODE: + return hdlc_set_mode(hdlc, ifr->ifr_ifru.ifru_ivalue); + + case HDLCPVC: + return hdlc_fr_pvc(hdlc, ifr->ifr_ifru.ifru_ivalue); + + default: + if (hdlc->ioctl != NULL) + return hdlc->ioctl(hdlc, ifr, cmd); + } + + return -EINVAL; +} + + + +static int hdlc_init(struct net_device *dev) +{ + hdlc_device *hdlc = dev_to_hdlc(dev); + + memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); + + dev->get_stats = hdlc_get_stats; + dev->open = hdlc_open; + dev->stop = hdlc_close; + dev->hard_start_xmit = hdlc_xmit; + dev->do_ioctl = hdlc_ioctl; + dev->change_mtu = hdlc_change_mtu; + dev->mtu = HDLC_MAX_MTU; + + dev->type = ARPHRD_RAWHDLC; + dev->hard_header_len = 16; + + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + + dev_init_buffers(dev); + return 0; +} + + + +int register_hdlc_device(hdlc_device *hdlc) +{ + int result; + struct net_device *dev = hdlc_to_dev(hdlc); + + dev->init = hdlc_init; + dev->priv = &hdlc->syncppp_ptr; + hdlc->syncppp_ptr = &hdlc->pppdev; + hdlc->pppdev.dev = dev; + hdlc->mode = MODE_NONE; + hdlc->lmi.T391 = 10; /* polling verification timer */ + hdlc->lmi.T392 = 15; /* link integrity verification polling timer */ + hdlc->lmi.N391 = 6; /* full status polling counter */ + hdlc->lmi.N392 = 3; /* error threshold */ + hdlc->lmi.N393 = 4; /* monitored events count */ + + result = dev_alloc_name(dev, "hdlc%d"); + if (result<0) + return result; + + result = register_netdev(dev); + if (result != 0) + return -EIO; + + dev_init_buffers(dev); + MOD_INC_USE_COUNT; + return 0; +} + + + +void unregister_hdlc_device(hdlc_device *hdlc) +{ + destroy_pvc_list(hdlc); + unregister_netdev(hdlc_to_dev(hdlc)); + MOD_DEC_USE_COUNT; +} + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("HDLC support module"); + +EXPORT_SYMBOL(hdlc_netif_rx); +EXPORT_SYMBOL(register_hdlc_device); +EXPORT_SYMBOL(unregister_hdlc_device); + +static int __init hdlc_module_init(void) +{ + printk(KERN_INFO "%s\n", version); + return 0; +} + + +module_init(hdlc_module_init); diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/hostess_sv11.c linux/drivers/net/wan/hostess_sv11.c --- v2.4.2/linux/drivers/net/wan/hostess_sv11.c Sun Aug 13 14:57:35 2000 +++ linux/drivers/net/wan/hostess_sv11.c Tue Mar 6 19:44:36 2001 @@ -34,7 +34,7 @@ #include #include #include -#include "syncppp.h" +#include #include "z85230.h" static int dma; @@ -59,7 +59,7 @@ { /* Drop the CRC - its not a good idea to try and negotiate it ;) */ skb_trim(skb, skb->len-2); - skb->protocol=htons(ETH_P_WAN_PPP); + skb->protocol=__constant_htons(ETH_P_WAN_PPP); skb->mac.raw=skb->data; skb->dev=c->netdevice; /* @@ -67,6 +67,7 @@ * it right now. */ netif_rx(skb); + c->netdevice->last_rx = jiffies; } /* diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c --- v2.4.2/linux/drivers/net/wan/lmc/lmc_main.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/wan/lmc/lmc_main.c Tue Mar 6 19:44:36 2001 @@ -67,7 +67,7 @@ #include #include #include -#include "../syncppp.h" +#include #include #if LINUX_VERSION_CODE >= 0x20200 @@ -77,15 +77,7 @@ #define ARPHRD_HDLC 513 #endif -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif #define DRIVER_MAJOR_VERSION 1 #define DRIVER_MINOR_VERSION 34 @@ -166,7 +158,7 @@ /* * Most functions mess with the structure - * Disable interupts while we do the polling + * Disable interrupts while we do the polling */ spin_lock_irqsave(&sc->lmc_lock, flags); @@ -546,7 +538,7 @@ udelay(50); /* - * Clear reset and activate programing lines + * Clear reset and activate programming lines * Reset: Input * DP: Input * Clock: Output @@ -584,7 +576,7 @@ sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */ break; default: - printk(KERN_WARNING "%s Bad data in xilinx programing data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]); + printk(KERN_WARNING "%s Bad data in xilinx programming data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]); sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */ } sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */ @@ -598,13 +590,13 @@ udelay(1); } if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){ - printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name); + printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (corrupted data)\n", dev->name); } else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){ - printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name); + printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (done)\n", dev->name); } else { - printk(KERN_DEBUG "%s: Done reprograming Xilinx, %d bits, good luck!\n", dev->name, pos); + printk(KERN_DEBUG "%s: Done reprogramming Xilinx, %d bits, good luck!\n", dev->name, pos); } lmc_gpio_mkinput(sc, 0xff); @@ -662,12 +654,13 @@ if(sc->check != 0xBEAFCAFE){ printk("LMC: Corrupt net_device stuct, breaking out\n"); + spin_unlock_irqrestore(&sc->lmc_lock, flags); return; } /* Make sure the tx jabber and rx watchdog are off, - * and the transmit and recieve processes are running. + * and the transmit and receive processes are running. */ LMC_CSR_WRITE (sc, csr_15, 0x00000011); @@ -793,7 +786,7 @@ if(sc->failed_recv_alloc == 1){ /* * We failed to alloc mem in the - * interupt halder, go through the rings + * interrupt handler, go through the rings * and rebuild them */ sc->failed_recv_alloc = 0; @@ -1356,7 +1349,7 @@ /* Stop Tx and Rx on the chip */ csr6 = LMC_CSR_READ (sc, csr_command); csr6 &= ~LMC_DEC_ST; /* Turn off the Transmission bit */ - csr6 &= ~LMC_DEC_SR; /* Turn off the Recieve bit */ + csr6 &= ~LMC_DEC_SR; /* Turn off the Receive bit */ LMC_CSR_WRITE (sc, csr_command, csr6); dev->flags &= ~IFF_RUNNING; @@ -1425,7 +1418,7 @@ spin_lock(&sc->lmc_lock); /* - * Read the csr to find what interupts we have (if any) + * Read the csr to find what interrupts we have (if any) */ csr = LMC_CSR_READ (sc, csr_status); @@ -1441,7 +1434,7 @@ /* always go through this loop at least once */ while (csr & sc->lmc_intrmask) { /* - * Clear interupt bits, we handle all case below + * Clear interrupt bits, we handle all case below */ LMC_CSR_WRITE (sc, csr_status, csr); @@ -1464,7 +1457,7 @@ } if (csr & TULIP_STS_RXINTR){ - lmc_trace(dev, "rx interupt"); + lmc_trace(dev, "rx interrupt"); lmc_rx (dev); } @@ -1588,7 +1581,7 @@ /* * Get current csr status to make sure - * we've cleared all interupts + * we've cleared all interrupts */ csr = LMC_CSR_READ (sc, csr_status); } /* end interrupt loop */ @@ -1599,8 +1592,6 @@ spin_unlock(&sc->lmc_lock); lmc_trace(dev, "lmc_interrupt out"); - - return; } static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/ @@ -1879,12 +1870,12 @@ sc->lmc_rxq[i] = nsb; nsb->dev = dev; sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); - /* Transfered to 21140 below */ + /* Transferred to 21140 below */ } else { /* * We've run out of memory, stop trying to allocate - * memory and exit the interupt handler + * memory and exit the interrupt handler * * The chip may run out of receivers and stop * in which care we'll try to allocate the buffer @@ -2129,7 +2120,7 @@ lmc_trace(sc->lmc_device, "lmc_softreset in"); - /* Initialize the recieve rings and buffers. */ + /* Initialize the receive rings and buffers. */ sc->lmc_txfull = 0; sc->lmc_next_rx = 0; sc->lmc_next_tx = 0; @@ -2138,7 +2129,7 @@ /* * Setup each one of the receiver buffers - * allocate an skbuff for each one, setup the the descriptor table + * allocate an skbuff for each one, setup the descriptor table * and point each buffer at the next one */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/lmc/lmc_media.c linux/drivers/net/wan/lmc/lmc_media.c --- v2.4.2/linux/drivers/net/wan/lmc/lmc_media.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/wan/lmc/lmc_media.c Tue Mar 6 19:44:36 2001 @@ -29,7 +29,7 @@ #include #include #include -#include "../syncppp.h" +#include #include #if LINUX_VERSION_CODE >= 0x20200 diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/lmc/lmc_proto.c linux/drivers/net/wan/lmc/lmc_proto.c --- v2.4.2/linux/drivers/net/wan/lmc/lmc_proto.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wan/lmc/lmc_proto.c Tue Mar 6 19:44:36 2001 @@ -43,7 +43,7 @@ #include #include #include -#include "../syncppp.h" +#include #include #include #include @@ -61,7 +61,6 @@ * compiled without referencing any of the sync ppp routines. */ #ifdef SPPPSTUB -#define SYNC_PPP_init() (void)0 #define SPPP_detach(d) (void)0 #define SPPP_open(d) 0 #define SPPP_reopen(d) (void)0 @@ -70,7 +69,6 @@ #define SPPP_do_ioctl(d,i,c) -EOPNOTSUPP #else #if LINUX_VERSION_CODE < 0x20363 -#define SYNC_PPP_init sync_ppp_init #define SPPP_attach(x) sppp_attach((struct ppp_device *)(x)->lmc_device) #define SPPP_detach(x) sppp_detach((x)->lmc_device) #define SPPP_open(x) sppp_open((x)->lmc_device) @@ -78,7 +76,6 @@ #define SPPP_close(x) sppp_close((x)->lmc_device) #define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->lmc_device, (y), (z)) #else -#define SYNC_PPP_init sync_ppp_init #define SPPP_attach(x) sppp_attach((x)->pd) #define SPPP_detach(x) sppp_detach((x)->pd->dev) #define SPPP_open(x) sppp_open((x)->pd->dev) @@ -88,21 +85,19 @@ #endif #endif -static int lmc_first_ppp_load = 0; - // init void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/ { lmc_trace(sc->lmc_device, "lmc_proto_init in"); switch(sc->if_type){ case LMC_PPP: - if(lmc_first_ppp_load == 0) -#ifndef MODULE - SYNC_PPP_init(); -#endif #if LINUX_VERSION_CODE >= 0x20363 sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); + if (!sc->pd) { + printk("lmc_proto_init(): kmalloc failure!\n"); + return; + } sc->pd->dev = sc->lmc_device; #endif sc->if_ptr = sc->pd; diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/lmc/lmc_var.h linux/drivers/net/wan/lmc/lmc_var.h --- v2.4.2/linux/drivers/net/wan/lmc/lmc_var.h Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wan/lmc/lmc_var.h Tue Mar 6 19:44:36 2001 @@ -482,10 +482,10 @@ #define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */ #define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */ -#define TULIP_STS_ERI 0x00004000L /* (RW) Early Receive Interupt */ +#define TULIP_STS_ERI 0x00004000L /* (RW) Early Receive Interrupt */ #define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */ #define TULIP_STS_GTE 0x00000800L /* (RW) General Pupose Timer Exp */ -#define TULIP_STS_ETI 0x00000400L /* (RW) Early Transmit Interupt */ +#define TULIP_STS_ETI 0x00000400L /* (RW) Early Transmit Interrupt */ #define TULIP_STS_RXWT 0x00000200L /* (RW) Receiver Watchdog Timeout */ #define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receiver Process Stopped */ #define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buf Unavail */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/n2.c linux/drivers/net/wan/n2.c --- v2.4.2/linux/drivers/net/wan/n2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/wan/n2.c Tue Mar 6 19:44:37 2001 @@ -0,0 +1,590 @@ +/* + * SDL Inc. RISCom/N2 synchronous serial card driver for Linux + * + * Copyright (C) 1998-2000 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * For information see http://hq.pm.waw.pl/hdlc/ + * + * Note: integrated CSU/DSU/DDS are not supported by this driver + * + * Sources of information: + * Hitachi HD64570 SCA User's Manual + * SDL Inc. PPP/HDLC/CISCO driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hd64570.h" + +#define DEBUG_RINGS +/* #define DEBUG_PKT */ + +static const char* version = "SDL RISCom/N2 driver revision: 1.02 for Linux 2.4"; +static const char* devname = "RISCom/N2"; + +#define USE_WINDOWSIZE 16384 +#define USE_BUS16BITS 1 +#define CLOCK_BASE 9830400 /* 9.8304 MHz */ + +#define N2_IOPORTS 0x10 + +static char *hw = NULL; /* pointer to hw=xxx command line string */ + +/* RISCom/N2 Board Registers */ + +/* PC Control Register */ +#define N2_PCR 0 +#define PCR_RUNSCA 1 /* Run 64570 */ +#define PCR_VPM 2 /* Enable VPM - needed if using RAM above 1 MB */ +#define PCR_ENWIN 4 /* Open window */ +#define PCR_BUS16 8 /* 16-bit bus */ + + +/* Memory Base Address Register */ +#define N2_BAR 2 + + +/* Page Scan Register */ +#define N2_PSR 4 +#define WIN16K 0x00 +#define WIN32K 0x20 +#define WIN64K 0x40 +#define PSR_WINBITS 0x60 +#define PSR_DMAEN 0x80 +#define PSR_PAGEBITS 0x0F + + +/* Modem Control Reg */ +#define N2_MCR 6 +#define CLOCK_OUT_PORT1 0x80 +#define CLOCK_OUT_PORT0 0x40 +#define TX422_PORT1 0x20 +#define TX422_PORT0 0x10 +#define DSR_PORT1 0x08 +#define DSR_PORT0 0x04 +#define DTR_PORT1 0x02 +#define DTR_PORT0 0x01 + + +typedef struct port_s { + hdlc_device hdlc; /* HDLC device struct - must be first */ + struct card_s *card; + spinlock_t lock; /* TX lock */ + int clkmode; /* clock mode */ + int clkrate; /* clock rate */ + int line; /* loopback only */ + u8 rxs, txs, tmc; /* SCA registers */ + u8 valid; /* port enabled */ + u8 phy_node; /* physical port # - 0 or 1 */ + u8 log_node; /* logical port # */ + u8 rxin; /* rx ring buffer 'in' pointer */ + u8 txin; /* tx ring buffer 'in' and 'last' pointers */ + u8 txlast; + u8 rxpart; /* partial frame received, next frame invalid*/ +}port_t; + + + +typedef struct card_s { + u8 *winbase; /* ISA window base address */ + u32 phy_winbase; /* ISA physical base address */ + u32 ram_size; /* number of bytes */ + u16 io; /* IO Base address */ + u16 buff_offset; /* offset of first buffer of first channel */ + u8 irq; /* IRQ (3-15) */ + u8 ring_buffers; /* number of buffers in a ring */ + + port_t ports[2]; + struct card_s *next_card; +}card_t; + + + +#define sca_reg(reg, card) (0x8000 | (card)->io | \ + ((reg) & 0x0F) | (((reg) & 0xF0) << 6)) +#define sca_in(reg, card) inb(sca_reg(reg, card)) +#define sca_out(value, reg, card) outb(value, sca_reg(reg, card)) +#define sca_inw(reg, card) inw(sca_reg(reg, card)) +#define sca_outw(value, reg, card) outw(value, sca_reg(reg, card)) + +#define port_to_card(port) ((port)->card) +#define log_node(port) ((port)->log_node) +#define phy_node(port) ((port)->phy_node) +#define winsize(card) (USE_WINDOWSIZE) +#define winbase(card) ((card)->winbase) +#define get_port(card, port) ((card)->ports[port].valid ? \ + &(card)->ports[port] : NULL) + + + +static __inline__ u8 sca_get_page(card_t *card) +{ + return inb(card->io + N2_PSR) & PSR_PAGEBITS; +} + + +static __inline__ void openwin(card_t *card, u8 page) +{ + u8 psr = inb(card->io + N2_PSR); + outb((psr & ~PSR_PAGEBITS) | page, card->io + N2_PSR); +} + + +static __inline__ void close_windows(card_t *card) +{ + outb(inb(card->io + N2_PCR) & ~PCR_ENWIN, card->io + N2_PCR); +} + + +#include "hd6457x.c" + + + +static int n2_set_clock(port_t *port, int value) +{ + card_t *card = port->card; + int io = card->io; + u8 mcr = inb(io + N2_MCR); + u8 msci = get_msci(port); + u8 rxs = port->rxs & CLK_BRG_MASK; + u8 txs = port->txs & CLK_BRG_MASK; + + switch(value) { + case CLOCK_EXT: + mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0; + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_LINE_TX; /* TXC input */ + break; + + case CLOCK_INT: + mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; + rxs |= CLK_BRG_RX; /* BRG output */ + txs |= CLK_RXCLK_TX; /* RX clock */ + break; + + case CLOCK_TXINT: + mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_BRG_TX; /* BRG output */ + break; + + case CLOCK_TXFROMRX: + mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0; + rxs |= CLK_LINE_RX; /* RXC input */ + txs |= CLK_RXCLK_TX; /* RX clock */ + break; + + default: + return -EINVAL; + } + + outb(mcr, io + N2_MCR); + port->rxs = rxs; + port->txs = txs; + sca_out(rxs, msci + RXS, card); + sca_out(txs, msci + TXS, card); + port->clkmode = value; + return 0; +} + + + +static int n2_open(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + int io = port->card->io; + u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0); + + MOD_INC_USE_COUNT; + mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */ + outb(mcr, io + N2_MCR); + + outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */ + outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */ + sca_open(hdlc); + n2_set_clock(port, port->clkmode); + return 0; +} + + + +static void n2_close(hdlc_device *hdlc) +{ + port_t *port = hdlc_to_port(hdlc); + int io = port->card->io; + u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0); + + sca_close(hdlc); + mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */ + outb(mcr, io + N2_MCR); + MOD_DEC_USE_COUNT; +} + + + +static int n2_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd) +{ + int value = ifr->ifr_ifru.ifru_ivalue; + int result = 0; + port_t *port = hdlc_to_port(hdlc); + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch(cmd) { + case HDLCSCLOCK: + result = n2_set_clock(port, value); + case HDLCGCLOCK: + value = port->clkmode; + break; + + case HDLCSCLOCKRATE: + port->clkrate = value; + sca_set_clock(port); + case HDLCGCLOCKRATE: + value = port->clkrate; + break; + + case HDLCSLINE: + result = sca_set_loopback(port, value); + case HDLCGLINE: + value = port->line; + break; + +#ifdef DEBUG_RINGS + case HDLCRUN: + sca_dump_rings(hdlc); + return 0; +#endif /* DEBUG_RINGS */ + + default: + return -EINVAL; + } + + ifr->ifr_ifru.ifru_ivalue = value; + return result; +} + + + +static u8 n2_count_page(card_t *card) +{ + u8 page; + int i, bcount = USE_WINDOWSIZE, wcount = USE_WINDOWSIZE/2; + u16 *dp = (u16*)card->winbase; + u8 *bp = (u8*)card->winbase; + u8 psr = inb(card->io + N2_PSR) & PSR_WINBITS; + + + for (page = 0; page < 16; page++) { + outb(psr | page, card->io + N2_PSR); /* select a page */ + writeb(page, dp); + if (readb(dp) != page) + break; /* If can't read back, no good memory */ + + outb(psr, card->io + N2_PSR); /* goto page 0 */ + if (readb(dp)) + break; /* If page 0 changed, then wrapped around */ + + outb(psr | page, card->io + N2_PSR); /* select page again */ + + /* first do byte tests */ + for (i = 0; i < bcount; i++) + writeb(i, bp + i); + for (i = 0; i < bcount; i++) + if (readb(bp + i) != (i & 0xff)) + return 0; + + for (i = 0; i < bcount; i++) + writeb(~i, bp + i); + for (i = 0; i < bcount; i++) + if (readb(bp + i) != (~i & 0xff)) + return 0; + + /* next do 16-bit tests */ + for (i = 0; i < wcount; i++) + writew(0x55AA, dp + i); + for (i = 0; i < wcount; i++) + if (readw(dp + i) != 0x55AA) + return 0; + + for (i = 0; i < wcount; i++) + writew(0xAA55, dp + i); + for (i = 0; i < wcount; i++) + if (readw(dp + i) != 0xAA55) + return 0; + + for (i = 0; i < wcount; i++) + writew(page, dp + i); + } + + return page; +} + + + +static void n2_destroy_card(card_t *card) +{ + int cnt; + + for (cnt = 0; cnt < 2; cnt++) + if (card->ports[cnt].card) + unregister_hdlc_device(&card->ports[cnt].hdlc); + + if (card->irq) + free_irq(card->irq, card); + + if (card->winbase) { + iounmap(card->winbase); + release_mem_region(card->phy_winbase, USE_WINDOWSIZE); + } + + if (card->io) + release_region(card->io, N2_IOPORTS); + kfree(card); +} + + + +static int n2_run(unsigned long io, unsigned long irq, unsigned long winbase, + long valid0, long valid1) +{ + card_t *card; + u8 cnt, pcr; + + if (io < 0x200 || io > 0x3FF || (io % N2_IOPORTS) != 0) { + printk(KERN_ERR "n2: invalid I/O port value\n"); + return -ENODEV; + } + + if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ { + printk(KERN_ERR "n2: invalid IRQ value\n"); + return -ENODEV; + } + + if (winbase < 0xA0000 || winbase > 0xFFFFF || (winbase & 0xFFF) != 0) { + printk(KERN_ERR "n2: invalid RAM value\n"); + return -ENODEV; + } + + card = kmalloc(sizeof(card_t), GFP_KERNEL); + if (card == NULL) { + printk(KERN_ERR "n2: unable to allocate memory\n"); + return -ENOBUFS; + } + memset(card, 0, sizeof(card_t)); + + if (!request_region(io, N2_IOPORTS, devname)) { + printk(KERN_ERR "n2: I/O port region in use\n"); + n2_destroy_card(card); + return -EBUSY; + } + card->io = io; + + if (request_irq(irq, &sca_intr, 0, devname, card)) { + printk(KERN_ERR "n2: could not allocate IRQ\n"); + n2_destroy_card(card); + return(-EBUSY); + } + card->irq = irq; + + if (!request_mem_region(winbase, USE_WINDOWSIZE, devname)) { + printk(KERN_ERR "n2: could not request RAM window\n"); + n2_destroy_card(card); + return(-EBUSY); + } + card->phy_winbase = winbase; + card->winbase = ioremap(winbase, USE_WINDOWSIZE); + + outb(0, io + N2_PCR); + outb(winbase >> 12, io + N2_BAR); + + switch (USE_WINDOWSIZE) { + case 16384: + outb(WIN16K, io + N2_PSR); + break; + + case 32768: + outb(WIN32K, io + N2_PSR); + break; + + case 65536: + outb(WIN64K, io + N2_PSR); + break; + + default: + printk(KERN_ERR "n2: invalid window size\n"); + n2_destroy_card(card); + return -ENODEV; + } + + pcr = PCR_ENWIN | PCR_VPM | (USE_BUS16BITS ? PCR_BUS16 : 0); + outb(pcr, io + N2_PCR); + + cnt = n2_count_page(card); + if (!cnt) { + printk(KERN_ERR "n2: memory test failed.\n"); + n2_destroy_card(card); + return -EIO; + } + + card->ram_size = cnt * USE_WINDOWSIZE; + + /* 4 rings required for 2 ports, 2 rings for one port */ + card->ring_buffers = card->ram_size / + ((valid0 + valid1) * 2 * (sizeof(pkt_desc) + HDLC_MAX_MRU)); + + card->buff_offset = (valid0 + valid1) * 2 * (sizeof(pkt_desc)) + * card->ring_buffers; + + printk(KERN_DEBUG "n2: RISCom/N2 %u KB RAM, IRQ%u, " + "using %u packets rings\n", card->ram_size / 1024, card->irq, + card->ring_buffers); + + pcr |= PCR_RUNSCA; /* run SCA */ + outb(pcr, io + N2_PCR); + outb(0, io + N2_MCR); + + sca_init(card, 0); + for (cnt = 0; cnt < 2; cnt++) { + port_t *port = &card->ports[cnt]; + + if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1)) + continue; + + port->phy_node = cnt; + port->valid = 1; + + if ((cnt == 1) && valid0) + port->log_node = 1; + + spin_lock_init(&port->lock); + hdlc_to_dev(&port->hdlc)->irq = irq; + hdlc_to_dev(&port->hdlc)->mem_start = winbase; + hdlc_to_dev(&port->hdlc)->mem_end = winbase + USE_WINDOWSIZE-1; + hdlc_to_dev(&port->hdlc)->tx_queue_len = 50; + port->hdlc.ioctl = n2_ioctl; + port->hdlc.open = n2_open; + port->hdlc.close = n2_close; + port->hdlc.xmit = sca_xmit; + + if (register_hdlc_device(&port->hdlc)) { + printk(KERN_WARNING "n2: unable to register hdlc " + "device\n"); + n2_destroy_card(card); + return -ENOBUFS; + } + port->card = card; + sca_init_sync_port(port); /* Set up SCA memory */ + + printk(KERN_INFO "%s: RISCom/N2 node %d\n", + hdlc_to_name(&port->hdlc), port->phy_node); + } + + *new_card = card; + new_card = &card->next_card; + + return 0; +} + + + +static int __init n2_init(void) +{ + if (hw==NULL) { +#ifdef MODULE + printk(KERN_INFO "n2: no card initialized\n"); +#endif + return -ENOSYS; /* no parameters specified, abort */ + } + + printk(KERN_INFO "%s\n", version); + + do { + unsigned long io, irq, ram; + long valid[2] = { 0, 0 }; /* Default = both ports disabled */ + + io = simple_strtoul(hw, &hw, 0); + + if (*hw++ != ',') + break; + irq = simple_strtoul(hw, &hw, 0); + + if (*hw++ != ',') + break; + ram = simple_strtoul(hw, &hw, 0); + + if (*hw++ != ',') + break; + while(1) { + if (*hw == '0' && !valid[0]) + valid[0] = 1; /* Port 0 enabled */ + else if (*hw == '1' && !valid[1]) + valid[1] = 1; /* Port 1 enabled */ + else + break; + hw++; + } + + if (!valid[0] && !valid[1]) + break; /* at least one port must be used */ + + if (*hw == ':' || *hw == '\x0') + n2_run(io, irq, ram, valid[0], valid[1]); + + if (*hw == '\x0') + return 0; + }while(*hw++ == ':'); + + printk(KERN_ERR "n2: invalid hardware parameters\n"); + return first_card ? 0 : -ENOSYS; +} + + +#ifndef MODULE +static int __init n2_setup(char *str) +{ + hw = str; + return 1; +} + +__setup("n2=", n2_setup); +#endif + + +static void __exit n2_cleanup(void) +{ + card_t *card = first_card; + + while (card) { + card_t *ptr = card; + card = card->next_card; + n2_destroy_card(ptr); + } +} + + +module_init(n2_init); +module_exit(n2_cleanup); + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("RISCom/N2 serial port driver"); +MODULE_PARM(hw, "s"); /* hw=io,irq,ram,ports:io,irq,... */ +EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c --- v2.4.2/linux/drivers/net/wan/sdla_chdlc.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wan/sdla_chdlc.c Tue Mar 6 19:44:36 2001 @@ -932,7 +932,7 @@ if(test_and_set_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical in if_send: %x\n", + printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); ++card->wandev.stats.tx_dropped; #ifdef LINUX_2_1 @@ -1497,7 +1497,7 @@ */ if(card->hw.type != SDLA_S514) { if(test_and_set_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: %x\n", + printk(KERN_INFO "%s: Critical while in ISR: %lx\n", card->devname, card->wandev.critical); card->in_isr = 0; return; diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c --- v2.4.2/linux/drivers/net/wan/sdla_fr.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wan/sdla_fr.c Tue Mar 6 19:44:36 2001 @@ -1654,7 +1654,7 @@ ++card->statistics.isr_intr_test; break; - case FR_INTR_DLC: /* Event interrupt occured */ + case FR_INTR_DLC: /* Event interrupt occurred */ mbox->cmd.command = FR_READ_STATUS; mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; @@ -1691,7 +1691,7 @@ /*============================================================================ * Receive interrupt handler. * When a receive interrupt occurs do the following: - * 1- Find the structure for the dlci that the interrupt occured on + * 1- Find the structure for the dlci that the interrupt occurred on * 2- If it doesn't exist then print appropriate msg and goto step 8. * 3- If it exist then copy data to a skb. * 4- If skb contains Sangoma UDP data then process them diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c --- v2.4.2/linux/drivers/net/wan/sdla_ppp.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wan/sdla_ppp.c Tue Mar 6 19:44:36 2001 @@ -897,7 +897,7 @@ if (test_and_set_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical in if_send: %x\n", + printk(KERN_INFO "%s: Critical in if_send: %lx\n", card->wandev.name,card->wandev.critical); dev_kfree_skb(skb); @@ -1686,8 +1686,6 @@ card->devname); ++card->wandev.stats.rx_dropped; ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; - - dev_kfree_skb(skb); } } else { @@ -2589,8 +2587,6 @@ } ppp_priv_area->udp_pkt_lgth = 0; - - return; } /*============================================================================= @@ -2753,7 +2749,7 @@ card->devname, err); return err; }else - printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n", + printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfully\n", card->devname, in_ntoa(ip_addr)); diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c --- v2.4.2/linux/drivers/net/wan/sdla_x25.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wan/sdla_x25.c Tue Mar 6 19:44:36 2001 @@ -929,7 +929,7 @@ * * Notes: * 1. When allocating a socket buffer, if M-bit is set then more data is - * comming and we have to allocate buffer for the maximum IP packet size + * coming and we have to allocate buffer for the maximum IP packet size * expected on this channel. * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no * socket buffers available) the whole packet sequence must be discarded. @@ -1001,7 +1001,7 @@ memcpy(bufptr, rxmb->data, len); if (qdm & 0x01) - return; /* more data is comming */ + return; /* more data is coming */ dev->last_rx = jiffies; /* timestamp */ chan->rx_skb = NULL; /* dequeue packet */ @@ -1153,7 +1153,7 @@ { wanpipe_set_state(card, WAN_CONNECTED); x25_set_intr_mode(card, 0x83); /* enable Rx interrupts */ - status->imask &= ~0x2; /* mask Tx interupts */ + status->imask &= ~0x2; /* mask Tx interrupts */ } else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT) disconnect(card); diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c --- v2.4.2/linux/drivers/net/wan/sdladrv.c Tue Jun 20 14:14:51 2000 +++ linux/drivers/net/wan/sdladrv.c Tue Mar 6 19:44:37 2001 @@ -195,6 +195,12 @@ * Note: All data must be explicitly initialized!!! */ +static struct pci_device_id sdladrv_pci_tbl[] __initdata = { + { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); + /* private data */ static char modname[] = "sdladrv"; static char fullname[] = "SDLA Support Module"; diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c --- v2.4.2/linux/drivers/net/wan/sdlamain.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wan/sdlamain.c Tue Mar 6 19:44:36 2001 @@ -635,7 +635,7 @@ * o verify user buffer * o copy adapter memory image to user buffer * - * Note: when dumping memory, this routine switches curent dual-port memory + * Note: when dumping memory, this routine switches current dual-port memory * vector, so care must be taken to avoid racing conditions. */ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sealevel.c linux/drivers/net/wan/sealevel.c --- v2.4.2/linux/drivers/net/wan/sealevel.c Sun Aug 13 14:57:35 2000 +++ linux/drivers/net/wan/sealevel.c Tue Mar 6 19:44:37 2001 @@ -26,7 +26,7 @@ #include #include #include -#include "syncppp.h" +#include #include "z85230.h" @@ -67,6 +67,7 @@ * it right now. */ netif_rx(skb); + c->netdevice->last_rx = jiffies; } /* diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c --- v2.4.2/linux/drivers/net/wan/syncppp.c Fri Aug 11 14:31:45 2000 +++ linux/drivers/net/wan/syncppp.c Tue Mar 6 19:44:37 2001 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -51,7 +52,7 @@ #include #include #include -#include "syncppp.h" +#include #define MAXALIVECNT 6 /* max. alive packets */ @@ -147,7 +148,6 @@ static int debug = 0; -MODULE_PARM(debug,"1i"); /* * Interface down stub @@ -208,7 +208,7 @@ skb->dev=dev; skb->mac.raw=skb->data; - + if (dev->flags & IFF_RUNNING) { /* Count received bytes, add FCS and one flag */ @@ -1391,28 +1391,25 @@ }; -void sync_ppp_init(void) + +static int __init sync_ppp_init(void) { + if(debug) + debug=PP_DEBUG; printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); spin_lock_init(&spppq_lock); sppp_packet_type.type=htons(ETH_P_WAN_PPP); dev_add_pack(&sppp_packet_type); -} - -#ifdef MODULE - -int init_module(void) -{ - if(debug) - debug=PP_DEBUG; - sync_ppp_init(); return 0; } -void cleanup_module(void) + +static void __exit sync_ppp_cleanup(void) { dev_remove_pack(&sppp_packet_type); } -#endif +module_init(sync_ppp_init); +module_exit(sync_ppp_cleanup); +MODULE_PARM(debug,"1i"); diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/syncppp.h linux/drivers/net/wan/syncppp.h --- v2.4.2/linux/drivers/net/wan/syncppp.h Mon Mar 13 09:43:37 2000 +++ linux/drivers/net/wan/syncppp.h Wed Dec 31 16:00:00 1969 @@ -1,99 +0,0 @@ -/* - * Defines for synchronous PPP/Cisco link level subroutines. - * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, - * - * This software is distributed with NO WARRANTIES, not even the implied - * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Authors grant any other persons or organizations permission to use - * or modify this software as long as this message is kept with the software, - * all derivative works or modified versions. - * - * Version 1.7, Wed Jun 7 22:12:02 MSD 1995 - * - * - * - */ - -#ifndef _SYNCPPP_H_ -#define _SYNCPPP_H_ 1 - -#ifdef __KERNEL__ -struct slcp { - u16 state; /* state machine */ - u32 magic; /* local magic number */ - u_char echoid; /* id of last keepalive echo request */ - u_char confid; /* id of last configuration request */ -}; - -struct sipcp { - u16 state; /* state machine */ - u_char confid; /* id of last configuration request */ -}; - -struct sppp -{ - struct sppp * pp_next; /* next interface in keepalive list */ - u32 pp_flags; /* use Cisco protocol instead of PPP */ - u16 pp_alivecnt; /* keepalive packets counter */ - u16 pp_loopcnt; /* loopback detection counter */ - u32 pp_seq; /* local sequence number */ - u32 pp_rseq; /* remote sequence number */ - struct slcp lcp; /* LCP params */ - struct sipcp ipcp; /* IPCP params */ - u32 ibytes,obytes; /* Bytes in/out */ - u32 ipkts,opkts; /* Packets in/out */ - struct timer_list pp_timer; - struct net_device *pp_if; - char pp_link_state; /* Link status */ -}; - -struct ppp_device -{ - struct net_device *dev; /* Network device pointer */ - struct sppp sppp; /* Synchronous PPP */ -}; - -#define sppp_of(dev) \ - (&((struct ppp_device *)(*(unsigned long *)((dev)->priv)))->sppp) - -#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ -#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ -#define PP_TIMO 0x04 /* cp_timeout routine active */ -#define PP_DEBUG 0x08 - -#define PPP_MTU 1500 /* max. transmit unit */ - -#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */ -#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */ -#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */ -#define LCP_STATE_OPENED 3 /* LCP state: opened */ - -#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */ -#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */ -#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */ -#define IPCP_STATE_OPENED 3 /* IPCP state: opened */ - -#define SPPP_LINK_DOWN 0 /* link down - no keepalive */ -#define SPPP_LINK_UP 1 /* link is up - keepalive ok */ - -void sppp_attach (struct ppp_device *pd); -void sppp_detach (struct net_device *dev); -void sppp_input (struct net_device *dev, struct sk_buff *m); -int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); -struct sk_buff *sppp_dequeue (struct net_device *dev); -int sppp_isempty (struct net_device *dev); -void sppp_flush (struct net_device *dev); -int sppp_open (struct net_device *dev); -int sppp_reopen (struct net_device *dev); -int sppp_close (struct net_device *dev); -void sync_ppp_init (void); -#endif - -#define SPPPIOCCISCO (SIOCDEVPRIVATE) -#define SPPPIOCPPP (SIOCDEVPRIVATE+1) -#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2) - -#endif /* _SYNCPPP_H_ */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c --- v2.4.2/linux/drivers/net/wan/z85230.c Wed Apr 12 09:47:26 2000 +++ linux/drivers/net/wan/z85230.c Tue Mar 6 19:44:37 2001 @@ -42,14 +42,15 @@ #include #include #include +#include #include #include #define RT_LOCK #define RT_UNLOCK #include +#include #include "z85230.h" -#include "syncppp.h" static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; @@ -70,7 +71,7 @@ * 5uS delay rule. */ -extern __inline__ int z8530_read_port(unsigned long p) +static inline int z8530_read_port(unsigned long p) { u8 r=inb(Z8530_PORT_OF(p)); if(p&Z8530_PORT_SLEEP) /* gcc should figure this out efficiently ! */ @@ -94,7 +95,7 @@ */ -extern __inline__ void z8530_write_port(unsigned long p, u8 d) +static inline void z8530_write_port(unsigned long p, u8 d) { outb(d,Z8530_PORT_OF(p)); if(p&Z8530_PORT_SLEEP) @@ -119,7 +120,7 @@ * operation. */ -extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg) +static inline u8 read_zsreg(struct z8530_channel *c, u8 reg) { u8 r; unsigned long flags; @@ -140,7 +141,7 @@ * have all the 5uS delays to worry about. */ -extern inline u8 read_zsdata(struct z8530_channel *c) +static inline u8 read_zsdata(struct z8530_channel *c) { u8 r; r=z8530_read_port(c->dataio); @@ -158,7 +159,7 @@ * being fast to access. */ -extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) +static inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val) { unsigned long flags; save_flags(flags); @@ -177,7 +178,7 @@ * Write directly to the control register on the Z8530 */ -extern inline void write_zsctrl(struct z8530_channel *c, u8 val) +static inline void write_zsctrl(struct z8530_channel *c, u8 val) { z8530_write_port(c->ctrlio, val); } @@ -191,7 +192,7 @@ */ -extern inline void write_zsdata(struct z8530_channel *c, u8 val) +static inline void write_zsdata(struct z8530_channel *c, u8 val) { z8530_write_port(c->dataio, val); } @@ -441,7 +442,7 @@ * z8530_status - Handle a PIO status exception * @chan: Z8530 channel to process * - * A status event occured in PIO synchronous mode. There are several + * A status event occurred in PIO synchronous mode. There are several * reasons the chip will bother us here. A transmit underrun means we * failed to feed the chip fast enough and just broke a packet. A DCD * change is a line up or down. We communicate that back to the protocol @@ -555,7 +556,7 @@ * z8530_dma_status - Handle a DMA status exception * @chan: Z8530 channel to process * - * A status event occured on the Z8530. We receive these for two reasons + * A status event occurred on the Z8530. We receive these for two reasons * when in DMA mode. Firstly if we finished a packet transfer we get one * and kick the next packet out. Secondly we may see a DCD change and * have to poke the protocol layer. @@ -1654,7 +1655,7 @@ * thing can only DMA within a 64K block not across the edges of it. */ -extern inline int spans_boundary(struct sk_buff *skb) +static inline int spans_boundary(struct sk_buff *skb) { unsigned long a=(unsigned long)skb->data; a^=(a+skb->len); @@ -1735,20 +1736,19 @@ EXPORT_SYMBOL(z8530_get_stats); -#ifdef MODULE - /* * Module support */ - -int init_module(void) +static const char banner[] __initdata = KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"; + +static int __init z85230_init_driver(void) { - printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n"); + printk(banner); return 0; } +module_init(z85230_init_driver); -void cleanup_module(void) +static void __exit z85230_cleanup_driver(void) { } - -#endif +module_exit(z85230_cleanup_driver); diff -u --recursive --new-file v2.4.2/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.4.2/linux/drivers/net/wavelan.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wavelan.c Sat Mar 3 10:55:47 2001 @@ -3686,7 +3686,7 @@ * the spinlock. */ spin_lock(&lp->spinlock); - /* Check modem interupt */ + /* Check modem interrupt */ if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) { u8 dce_status; @@ -3913,8 +3913,6 @@ } wv_splx(lp, &flags); - MOD_INC_USE_COUNT; - #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); #endif @@ -3947,8 +3945,6 @@ free_irq(dev->irq, dev); - MOD_DEC_USE_COUNT; - #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); #endif @@ -4019,8 +4015,10 @@ /* Initialize device structures */ dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); - if (dev->priv == NULL) + if (dev->priv == NULL) { + release_region(ioaddr, sizeof(ha_t)); return -ENOMEM; + } memset(dev->priv, 0x00, sizeof(net_local)); lp = (net_local *) dev->priv; @@ -4045,6 +4043,7 @@ */ ether_setup(dev); + SET_MODULE_OWNER(dev); dev->open = wavelan_open; dev->stop = wavelan_close; dev->hard_start_xmit = wavelan_packet_xmit; @@ -4287,7 +4286,7 @@ /* * This software may only be used and distributed - * according to the terms of the GNU Public License. + * according to the terms of the GNU General Public License. * * This software was developed as a component of the * Linux operating system. diff -u --recursive --new-file v2.4.2/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h --- v2.4.2/linux/drivers/net/wavelan.p.h Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wavelan.p.h Tue Mar 6 19:28:34 2001 @@ -420,7 +420,8 @@ #undef DEBUG_RX_INFO /* header of the received packet */ #undef DEBUG_RX_FAIL /* Normal failure conditions */ #define DEBUG_RX_ERROR /* Unexpected conditions */ -#undef DEBUG_PACKET_DUMP 32 /* Dump packet on the screen. */ + +#undef DEBUG_PACKET_DUMP /* Dump packet on the screen if defined to 32. */ #undef DEBUG_IOCTL_TRACE /* misc. call by Linux */ #undef DEBUG_IOCTL_INFO /* various debugging info */ #define DEBUG_IOCTL_ERROR /* what's going wrong */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c --- v2.4.2/linux/drivers/net/winbond-840.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/winbond-840.c Tue Mar 6 19:28:34 2001 @@ -1,6 +1,6 @@ /* winbond-840.c: A Linux PCI network adapter skeleton device driver. */ /* - Written 1998-2000 by Donald Becker. + Written 1998-2001 by Donald Becker. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. @@ -198,7 +198,8 @@ PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, }; -enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2}; +enum chip_capability_flags { + CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,}; #ifdef USE_IO_OPS #define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER) #else @@ -206,8 +207,9 @@ #endif static struct pci_device_id w840_pci_tbl[] __devinitdata = { - { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { 0x1050, 0x0840, PCI_ANY_ID, 0x8153, 0, 0, 0 }, + { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, { 0, } }; MODULE_DEVICE_TABLE(pci, w840_pci_tbl); @@ -223,6 +225,9 @@ int drv_flags; /* Driver use, intended as capability flags. */ }; static struct pci_id_info pci_id_tbl[] = { + {"Winbond W89c840", /* Sometime a Level-One switch card. */ + { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 }, + W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII}, {"Winbond W89c840", { 0x08401050, 0xffffffff, }, W840_FLAGS, 128, CanHaveMII | HasBrokenTx}, {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,}, @@ -305,21 +310,17 @@ enum desc_status_bits { DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000, DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000, -}; - -/* Bits in w840_tx_desc.length */ -enum desc_length_bits { DescIntr=0x80000000, }; #define PRIV_ALIGN 15 /* Required alignment mask */ +#define MII_CNT 1 /* winbond only supports one MII */ struct netdev_private { struct w840_rx_desc *rx_ring; dma_addr_t rx_addr[RX_RING_SIZE]; struct w840_tx_desc *tx_ring; dma_addr_t tx_addr[RX_RING_SIZE]; dma_addr_t ring_dma_addr; - struct pci_dev *pdev; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for later free(). */ @@ -329,6 +330,7 @@ /* Frequently used values: keep some adjacent for cache effect. */ spinlock_t lock; int chip_id, drv_flags; + struct pci_dev *pci_dev; int csr6; struct w840_rx_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ @@ -344,7 +346,7 @@ /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ + unsigned char phys[MII_CNT]; /* MII device addresses, but only the first is used */ }; static int eeprom_read(long ioaddr, int location); @@ -377,14 +379,17 @@ struct netdev_private *np; static int find_cnt; int chip_idx = ent->driver_data; - int irq = pdev->irq; + int irq; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; long ioaddr; - if (pci_enable_device(pdev)) - return -EIO; + i = pci_enable_device(pdev); + if (i) return i; + pci_set_master(pdev); + irq = pdev->irq; + if(!pci_dma_supported(pdev,0xFFFFffff)) { printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n", pdev->name); @@ -395,17 +400,16 @@ return -ENOMEM; SET_MODULE_OWNER(dev); + if (pci_request_regions(pdev, dev->name)) + goto err_out_netdev; + #ifdef USE_IO_OPS ioaddr = pci_resource_start(pdev, 0); - if (!request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) - goto err_out_netdev; #else ioaddr = pci_resource_start(pdev, 1); - if (!request_mem_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) - goto err_out_netdev; ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); if (!ioaddr) - goto err_out_iomem; + goto err_out_free_res; #endif printk(KERN_INFO "%s: %s at 0x%lx, ", @@ -427,14 +431,14 @@ dev->irq = irq; np = dev->priv; + np->pci_dev = pdev; np->chip_id = chip_idx; np->drv_flags = pci_id_tbl[chip_idx].drv_flags; - np->pdev = pdev; spin_lock_init(&np->lock); - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); - if (dev->mem_start) + if (dev->mem_start && dev->mem_start != ~0) option = dev->mem_start; /* The lower four bits are the media type. */ @@ -463,7 +467,7 @@ if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; - for (phy = 1; phy < 32 && phy_idx < 4; phy++) { + for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { int mii_status = mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phy; @@ -484,9 +488,8 @@ return 0; #ifndef USE_IO_OPS -err_out_iomem: - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[chip_idx].io_size); +err_out_free_res: + pci_release_regions(pdev); #endif err_out_netdev: unregister_netdev (dev); @@ -535,6 +538,7 @@ eeprom_delay(ee_addr); } writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); for (i = 16; i > 0; i--) { writel(EE_ChipSelect | EE_ShiftClk, ee_addr); @@ -612,7 +616,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long mdio_addr = dev->base_addr + MIICtrl; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; int i; @@ -645,7 +649,7 @@ static int netdev_open(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; @@ -680,7 +684,7 @@ static void check_duplex(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int mii_reg5 = mdio_read(dev, np->phys[0], 5); int negotiated = mii_reg5 & np->advertising; int duplex; @@ -702,7 +706,7 @@ static void netdev_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; int old_csr6 = np->csr6; @@ -725,7 +729,7 @@ static void init_rxtx_rings(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; np->rx_head_desc = &np->rx_ring[0]; @@ -747,7 +751,7 @@ if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[i] = pci_map_single(np->pdev,skb->tail, + np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail, skb->len,PCI_DMA_FROMDEVICE); np->rx_ring[i].buffer1 = cpu_to_le32(np->rx_addr[i]); @@ -778,7 +782,7 @@ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].status = 0; if (np->rx_skbuff[i]) { - pci_unmap_single(np->pdev, + pci_unmap_single(np->pci_dev, np->rx_addr[i], np->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE); @@ -788,7 +792,7 @@ } for (i = 0; i < TX_RING_SIZE; i++) { if (np->tx_skbuff[i]) { - pci_unmap_single(np->pdev, + pci_unmap_single(np->pci_dev, np->tx_addr[i], np->tx_skbuff[i]->len, PCI_DMA_TODEVICE); @@ -800,7 +804,7 @@ static void init_registers(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int i; @@ -832,7 +836,7 @@ if (x86 <= 4) printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache " "alignment to %x.\n", dev->name, - (x86 <= 4 ? 0x4810 : 0x8010)); + (x86 <= 4 ? 0x4810 : 0xE010)); #endif #else writel(0xE010, ioaddr + PCIBusCfg); @@ -857,7 +861,7 @@ static void tx_timeout(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," @@ -905,11 +909,11 @@ /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static int alloc_ring(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); - np->rx_ring = pci_alloc_consistent(np->pdev, + np->rx_ring = pci_alloc_consistent(np->pci_dev, sizeof(struct w840_rx_desc)*RX_RING_SIZE + sizeof(struct w840_tx_desc)*TX_RING_SIZE, &np->ring_dma_addr); @@ -922,7 +926,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; unsigned entry; int len1, len2; @@ -933,7 +937,7 @@ entry = np->cur_tx % TX_RING_SIZE; np->tx_skbuff[entry] = skb; - np->tx_addr[entry] = pci_map_single(np->pdev, + np->tx_addr[entry] = pci_map_single(np->pci_dev, skb->data,skb->len, PCI_DMA_TODEVICE); np->tx_ring[entry].buffer1 = cpu_to_le32(np->tx_addr[entry]); len2 = 0; @@ -987,7 +991,7 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = (struct net_device *)dev_instance; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; int work_limit = max_interrupt_work; @@ -1040,7 +1044,7 @@ np->stats.tx_packets++; } /* Free the original skb. */ - pci_unmap_single(np->pdev,np->tx_addr[entry], + pci_unmap_single(np->pci_dev,np->tx_addr[entry], np->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); np->tx_q_bytes -= np->tx_skbuff[entry]->len; @@ -1082,7 +1086,7 @@ for clarity and better register allocation. */ static int netdev_rx(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int entry = np->cur_rx % RX_RING_SIZE; int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx; @@ -1136,7 +1140,7 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pdev,np->rx_addr[entry], + pci_dma_sync_single(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, PCI_DMA_FROMDEVICE); /* Call copy + cksum if available. */ @@ -1148,7 +1152,7 @@ pkt_len); #endif } else { - pci_unmap_single(np->pdev,np->rx_addr[entry], + pci_unmap_single(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, PCI_DMA_FROMDEVICE); skb_put(skb = np->rx_skbuff[entry], pkt_len); @@ -1187,7 +1191,7 @@ if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[entry] = pci_map_single(np->pdev, + np->rx_addr[entry] = pci_map_single(np->pci_dev, skb->tail, skb->len, PCI_DMA_FROMDEVICE); np->rx_ring[entry].buffer1 = cpu_to_le32(np->rx_addr[entry]); @@ -1202,7 +1206,7 @@ static void netdev_error(struct net_device *dev, int intr_status) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; if (debug > 2) printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n", @@ -1243,7 +1247,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; /* The chip only need report frame silently dropped. */ if (netif_running(dev)) @@ -1270,7 +1274,7 @@ static void set_rx_mode(struct net_device *dev) { - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; long ioaddr = dev->base_addr; u32 mc_filter[2]; /* Multicast hash filter */ u32 rx_mode; @@ -1328,7 +1332,7 @@ static int netdev_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_private *np = dev->priv; int i; netif_stop_queue(dev); @@ -1379,23 +1383,19 @@ static void __devexit w840_remove1 (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ if (dev) { - struct netdev_private *np = (void *)(dev->priv); unregister_netdev(dev); -#ifdef USE_IO_OPS - release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size); -#else - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[np->chip_id].io_size); + pci_release_regions(pdev); +#ifndef USE_IO_OPS iounmap((char *)(dev->base_addr)); #endif kfree(dev); } - pdev->driver_data = NULL; + pci_set_drvdata(pdev, NULL); } static struct pci_driver w840_driver = { diff -u --recursive --new-file v2.4.2/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.4.2/linux/drivers/net/yellowfin.c Mon Dec 11 13:38:29 2000 +++ linux/drivers/net/yellowfin.c Tue Mar 6 19:28:35 2001 @@ -1,33 +1,54 @@ /* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */ /* - Written 1997-1999 by Donald Becker. + Written 1997-2001 by Donald Becker. - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter. It also supports the Symbios Logic version of the same chip core. - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 Support and updates available at - http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html + http://www.scyld.com/network/yellowfin.html + + + Linux kernel changelog: + ----------------------- + + LK1.1.1 (jgarzik): Port to 2.4 kernel + + LK1.1.2 (jgarzik): + * Merge in becker version 1.05 + */ -static const char *version = -"yellowfin.c:v1.03a 7/30/99 Written by Donald Becker, becker@cesdis.edu\n" -" http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html\n"; +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"yellowfin.c:v1.05 1/09/2001 Written by Donald Becker \n"; +static const char version2[] = +" http://www.scyld.com/network/yellowfin.html\n"; +static const char version3[] = +" (unofficial 2.4.x port, LK1.1.2, January 11, 2001)\n"; -/* A few user-configurable values. */ +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ -static int debug = 1; +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 20; -static int mtu = 0; +static int mtu; #ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */ /* System-wide count of bogus-rx frames. */ -static int bogus_rx = 0; +static int bogus_rx; static int dma_ctrl = 0x004A0263; /* Constrained by errata */ static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ #elif YF_NEW /* A future perfect board :->. */ @@ -40,7 +61,7 @@ /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1514 effectively disables this feature. */ -static int rx_copybreak = 0; +static int rx_copybreak; /* Used to pass the media type, etc. No media types are currently defined. These exist for driver @@ -51,12 +72,12 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Do ugly workaround for GX server chipset errata. */ -static int gx_fix = 0; +static int gx_fix; /* Operational parameters that are set at compile time. */ /* Keep the ring sizes a power of two for efficiency. - Making the Tx queue too long decreases the effectiveness of channel + Making the Tx ring too long decreases the effectiveness of channel bonding and packet priority. There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 @@ -66,57 +87,61 @@ /* Operational parameters that usually are not changed. */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2*HZ) +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ #define yellowfin_debug debug -#if !defined(__OPTIMIZE__) || !defined(__KERNEL__) +#if !defined(__OPTIMIZE__) #warning You must compile this file with the correct options! #warning See the last lines of the source file. #error You must compile this driver with "-O". #endif -#include #include #include #include #include #include #include -#include +#include #include #include #include +#include +#include +#include #include /* Processor type for cache alignment. */ #include #include #include -#include -#include -#include - -/* Condensed operations for readability. - Compatibility defines are now in drv_compat.h */ - +/* Condensed operations for readability. */ #define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -#ifdef USE_IO_OPS -#define YF_INB inb -#define YF_INW inw -#define YF_INL inl -#define YF_OUTB outb -#define YF_OUTW outw -#define YF_OUTL outl -#else -#define YF_INB readb -#define YF_INW readw -#define YF_INL readl -#define YF_OUTB writeb -#define YF_OUTW writew -#define YF_OUTL writel -#endif +#ifndef USE_IO_OPS +#undef inb +#undef inw +#undef inl +#undef outb +#undef outw +#undef outl +#define inb readb +#define inw readw +#define inl readl +#define outb writeb +#define outw writew +#define outl writel +#endif /* !USE_IO_OPS */ +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(gx_fix, "i"); /* Theory of Operation @@ -193,50 +218,53 @@ IVc. Errata See Packet Engines confidential appendix (prototype chips only). - */ - -/* A few values that may be tweaked. */ -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* The rest of these values should never change. */ + +enum pci_id_flags_bits { + /* Set PCI command register bits before calling probe1(). */ + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + /* Read and map the single following PCI BAR. */ + PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, + PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, + PCI_UNUSED_IRQ=0x800, +}; enum capability_flags { HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16, - HasMACAddrBug=32, /* Really only on early revs. */ + HasMACAddrBug=32, /* Only on early revs. */ }; - - /* The PCI I/O space extent. */ #define YELLOWFIN_SIZE 0x100 +#ifdef USE_IO_OPS +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) +#else +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +#endif -#define YELLOWFIN_MODULE_NAME "yellowfin" -#define PFX YELLOWFIN_MODULE_NAME ": " - - -typedef enum { - YELLOWFIN_GNIC, - SYM83C885, -} chip_t; - - -struct chip_info { - const char *name; - int flags; +struct pci_id_info { + const char *name; + struct match_info { + int pci, pci_mask, subsystem, subsystem_mask; + int revision, revision_mask; /* Only 8 bits. */ + } id; + enum pci_id_flags_bits pci_flags; + int io_size; /* Needed for I/O region check or ioremap(). */ + int drv_flags; /* Driver use, intended as capability flags. */ }; - -/* index by chip_t */ -static struct chip_info chip_info[] = { - {"Yellowfin G-NIC Gigabit Ethernet", +static struct pci_id_info pci_id_tbl[] = { + {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff}, + PCI_IOTYPE, YELLOWFIN_SIZE, FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug}, - {"Symbios SYM83C885", HasMII }, + {"Symbios SYM83C885", { 0x07011000, 0xffffffff}, + PCI_IOTYPE, YELLOWFIN_SIZE, HasMII }, + {0,}, }; - static struct pci_device_id yellowfin_pci_tbl[] __devinitdata = { - { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, YELLOWFIN_GNIC }, - { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SYM83C885 }, + { 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { 0, } }; MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl); @@ -300,21 +328,22 @@ IntrEarlyRx=0x100, IntrWakeup=0x200, }; #define PRIV_ALIGN 31 /* Required alignment mask */ +#define MII_CNT 4 struct yellowfin_private { - /* Descriptor rings first for alignment. Tx requires a second descriptor - for status. */ + /* Descriptor rings first for alignment. + Tx requires a second descriptor for status. */ struct yellowfin_desc rx_ring[RX_RING_SIZE]; struct yellowfin_desc tx_ring[TX_RING_SIZE*2]; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + /* The saved address of a sent-in-place packet/buffer, for later free(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; struct tx_status_words tx_status[TX_RING_SIZE]; struct timer_list timer; /* Media selection timer. */ struct net_device_stats stats; /* Frequently used and paired value: keep adjacent for cache effect. */ + int chip_id, drv_flags; struct pci_dev *pci_dev; - int chip_id, flags; struct yellowfin_desc *rx_head_desc; unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int rx_buf_sz; /* Based on MTU+slack. */ @@ -329,29 +358,14 @@ /* MII transceiver section. */ int mii_cnt; /* MII device addresses. */ u16 advertising; /* NWay media advertisement */ - unsigned char phys[2]; /* MII device addresses. */ - u32 pad[4]; /* Used for 32-byte alignment */ + unsigned char phys[MII_CNT]; /* MII device addresses, only first one used */ spinlock_t lock; }; - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(mtu, "i"); -MODULE_PARM(debug, "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(gx_fix, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); - - static int read_eeprom(long ioaddr, int location); static int mdio_read(long ioaddr, int phy_id, int location); static void mdio_write(long ioaddr, int phy_id, int location, int value); -#ifdef HAVE_PRIVATE_IOCTL static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif static int yellowfin_open(struct net_device *dev); static void yellowfin_timer(unsigned long data); static void yellowfin_tx_timeout(struct net_device *dev); @@ -365,15 +379,141 @@ static void set_rx_mode(struct net_device *dev); +static int __devinit yellowfin_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct yellowfin_private *np; + int irq; + int chip_idx = ent->driver_data; + static int find_cnt = 0; + long ioaddr, real_ioaddr; + int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; + int drv_flags = pci_id_tbl[chip_idx].drv_flags; + + i = pci_enable_device(pdev); + if (i) return i; + + dev = init_etherdev(NULL, sizeof(*np)); + if (!dev) { + printk (KERN_ERR "yellowfin: cannot allocate ethernet device\n"); + return -ENOMEM; + } + SET_MODULE_OWNER(dev); + + np = dev->priv; + + if (pci_request_regions(pdev, dev->name)) + goto err_out_free_netdev; + + pci_set_master (pdev); + +#ifdef USE_IO_OPS + real_ioaddr = ioaddr = pci_resource_start (pdev, 0); +#else + real_ioaddr = ioaddr = pci_resource_start (pdev, 1); + ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE); + if (!ioaddr) + goto err_out_free_res; +#endif + irq = pdev->irq; + + printk(KERN_INFO "%s: %s type %8x at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, inl(ioaddr + ChipRev), ioaddr); + + if (drv_flags & IsGigabit) + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb(ioaddr + StnAddr + i); + else { + int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0); + for (i = 0; i < 6; i++) + dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i); + } + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + /* Reset the chip. */ + outl(0x80000000, ioaddr + DMACtrl); + + dev->base_addr = ioaddr; + dev->irq = irq; + + pci_set_drvdata(pdev, dev); + np->lock = SPIN_LOCK_UNLOCKED; + + np->pci_dev = pdev; + np->chip_id = chip_idx; + np->drv_flags = drv_flags; + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The Yellowfin-specific entries in the device structure. */ + dev->open = &yellowfin_open; + dev->hard_start_xmit = &yellowfin_start_xmit; + dev->stop = &yellowfin_close; + dev->get_stats = &yellowfin_get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = yellowfin_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + if (mtu) + dev->mtu = mtu; + + if (np->drv_flags & HasMII) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { + int mii_status = mdio_read(ioaddr, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + np->advertising = mdio_read(ioaddr, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, np->advertising); + } + } + np->mii_cnt = phy_idx; + } + + find_cnt++; + + return 0; + +#ifndef USE_IO_OPS +err_out_free_res: + pci_release_regions(pdev); +#endif +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; +} + static int __devinit read_eeprom(long ioaddr, int location) { int bogus_cnt = 10000; /* Typical 33Mhz: 1050 ticks */ - YF_OUTB(location, ioaddr + EEAddr); - YF_OUTB(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); - while ((YF_INB(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) + outb(location, ioaddr + EEAddr); + outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); + while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) ; - return YF_INB(ioaddr + EERead); + return inb(ioaddr + EERead); } /* MII Managemen Data I/O accesses. @@ -384,24 +524,24 @@ { int i; - YF_OUTW((phy_id<<8) + location, ioaddr + MII_Addr); - YF_OUTW(1, ioaddr + MII_Cmd); + outw((phy_id<<8) + location, ioaddr + MII_Addr); + outw(1, ioaddr + MII_Cmd); for (i = 10000; i >= 0; i--) - if ((YF_INW(ioaddr + MII_Status) & 1) == 0) + if ((inw(ioaddr + MII_Status) & 1) == 0) break; - return YF_INW(ioaddr + MII_Rd_Data); + return inw(ioaddr + MII_Rd_Data); } static void mdio_write(long ioaddr, int phy_id, int location, int value) { int i; - YF_OUTW((phy_id<<8) + location, ioaddr + MII_Addr); - YF_OUTW(value, ioaddr + MII_Wr_Data); + outw((phy_id<<8) + location, ioaddr + MII_Addr); + outw(value, ioaddr + MII_Wr_Data); /* Wait for the command to finish. */ for (i = 10000; i >= 0; i--) - if ((YF_INW(ioaddr + MII_Status) & 1) == 0) + if ((inw(ioaddr + MII_Status) & 1) == 0) break; return; } @@ -414,10 +554,10 @@ int i; /* Reset the chip. */ - YF_OUTL(0x80000000, ioaddr + DMACtrl); + outl(0x80000000, ioaddr + DMACtrl); - if (request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name, dev)) - return -EAGAIN; + i = request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name, dev); + if (i) return i; if (yellowfin_debug > 1) printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n", @@ -425,58 +565,59 @@ yellowfin_init_ring(dev); - YF_OUTL(virt_to_bus(yp->rx_ring), ioaddr + RxPtr); - YF_OUTL(virt_to_bus(yp->tx_ring), ioaddr + TxPtr); + outl(virt_to_bus(yp->rx_ring), ioaddr + RxPtr); + outl(virt_to_bus(yp->tx_ring), ioaddr + TxPtr); for (i = 0; i < 6; i++) - YF_OUTB(dev->dev_addr[i], ioaddr + StnAddr + i); + outb(dev->dev_addr[i], ioaddr + StnAddr + i); /* Set up various condition 'select' registers. There are no options here. */ - YF_OUTL(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */ - YF_OUTL(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */ - YF_OUTL(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */ - YF_OUTL(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */ - YF_OUTL(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */ - YF_OUTL(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */ + outl(0x00800080, ioaddr + TxIntrSel); /* Interrupt on Tx abort */ + outl(0x00800080, ioaddr + TxBranchSel); /* Branch on Tx abort */ + outl(0x00400040, ioaddr + TxWaitSel); /* Wait on Tx status */ + outl(0x00400040, ioaddr + RxIntrSel); /* Interrupt on Rx done */ + outl(0x00400040, ioaddr + RxBranchSel); /* Branch on Rx error */ + outl(0x00400040, ioaddr + RxWaitSel); /* Wait on Rx done */ /* Initialize other registers: with so many this eventually this will converted to an offset/value list. */ - YF_OUTL(dma_ctrl, ioaddr + DMACtrl); - YF_OUTW(fifo_cfg, ioaddr + FIFOcfg); + outl(dma_ctrl, ioaddr + DMACtrl); + outw(fifo_cfg, ioaddr + FIFOcfg); /* Enable automatic generation of flow control frames, period 0xffff. */ - YF_OUTL(0x0030FFFF, ioaddr + FlowCtrl); + outl(0x0030FFFF, ioaddr + FlowCtrl); yp->tx_threshold = 32; - YF_OUTL(yp->tx_threshold, ioaddr + TxThreshold); + outl(yp->tx_threshold, ioaddr + TxThreshold); if (dev->if_port == 0) dev->if_port = yp->default_port; - netif_start_queue (dev); + netif_start_queue(dev); /* Setting the Rx mode will start the Rx process. */ - if (yp->flags & IsGigabit) { + if (yp->drv_flags & IsGigabit) { /* We are always in full-duplex mode with gigabit! */ yp->full_duplex = 1; - YF_OUTW(0x01CF, ioaddr + Cnfg); + outw(0x01CF, ioaddr + Cnfg); } else { - YF_OUTW(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */ - YF_OUTW(0x1018, ioaddr + FrameGap1); - YF_OUTW(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); + outw(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */ + outw(0x1018, ioaddr + FrameGap1); + outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); } set_rx_mode(dev); /* Enable interrupts by setting the interrupt mask. */ - YF_OUTW(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */ - YF_OUTW(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ - YF_OUTL(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */ - YF_OUTL(0x80008000, ioaddr + TxCtrl); + outw(0x81ff, ioaddr + IntrEnb); /* See enum intr_status_bits */ + outw(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ + outl(0x80008000, ioaddr + RxCtrl); /* Start Rx and Tx channels. */ + outl(0x80008000, ioaddr + TxCtrl); if (yellowfin_debug > 2) { printk(KERN_DEBUG "%s: Done yellowfin_open().\n", dev->name); } + /* Set the timer to check for link beat. */ init_timer(&yp->timer); yp->timer.expires = jiffies + 3*HZ; @@ -496,7 +637,7 @@ if (yellowfin_debug > 3) { printk(KERN_DEBUG "%s: Yellowfin timer tick, status %8.8x.\n", - dev->name, YF_INW(ioaddr + IntrStatus)); + dev->name, inw(ioaddr + IntrStatus)); } if (yp->mii_cnt) { @@ -513,7 +654,7 @@ || (negotiated & 0x00C0) == 0x0040)) { yp->full_duplex = 1; } - YF_OUTW(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); + outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg); if (mii_reg1 & 0x0004) next_tick = 60*HZ; @@ -533,7 +674,7 @@ printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx " "status %4.4x, Rx status %4.4x, resetting...\n", dev->name, yp->cur_tx, yp->dirty_tx, - YF_INL(ioaddr + TxStatus), YF_INL(ioaddr + RxStatus)); + inl(ioaddr + TxStatus), inl(ioaddr + RxStatus)); /* Note: these should be KERN_DEBUG. */ if (yellowfin_debug) { @@ -553,13 +694,12 @@ dev->if_port = 0; /* Wake the potentially-idle transmit channel. */ - YF_OUTL(0x10001000, dev->base_addr + TxCtrl); + outl(0x10001000, dev->base_addr + TxCtrl); if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) netif_wake_queue (dev); /* Typical path */ dev->trans_start = jiffies; yp->stats.tx_errors++; - return; } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ @@ -642,8 +782,8 @@ netif_stop_queue (dev); - /* Caution: the write order is important here, set the base address - with the "ownership" bits last. */ + /* Note: Ordering is important here, set the field with the + "ownership" bit last, and only then increment cur_tx. */ /* Calculate the next Tx descriptor entry. */ entry = yp->cur_tx % TX_RING_SIZE; @@ -691,7 +831,7 @@ /* Non-x86 Todo: explicitly flush cache lines here. */ /* Wake the potentially-idle transmit channel. */ - YF_OUTL(0x10001000, dev->base_addr + TxCtrl); + outl(0x10001000, dev->base_addr + TxCtrl); if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE) netif_start_queue (dev); /* Typical path */ @@ -712,7 +852,8 @@ { struct net_device *dev = (struct net_device *)dev_instance; struct yellowfin_private *yp; - long ioaddr, boguscnt = max_interrupt_work; + long ioaddr; + int boguscnt = max_interrupt_work; #ifndef final_version /* Can never occur. */ if (dev == NULL) { @@ -727,7 +868,7 @@ spin_lock (&yp->lock); do { - u16 intr_status = YF_INW(ioaddr + IntrClear); + u16 intr_status = inw(ioaddr + IntrClear); if (yellowfin_debug > 4) printk(KERN_DEBUG "%s: Yellowfin interrupt, status %4.4x.\n", @@ -738,7 +879,7 @@ if (intr_status & (IntrRxDone | IntrEarlyRx)) { yellowfin_rx(dev); - YF_OUTL(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */ + outl(0x10001000, ioaddr + RxCtrl); /* Wake Rx engine. */ } #ifdef NO_TXSTATS @@ -746,8 +887,8 @@ int entry = yp->dirty_tx % TX_RING_SIZE; if (yp->tx_ring[entry].result_status == 0) break; - yp->stats.tx_bytes += yp->tx_skbuff[entry]->len; yp->stats.tx_packets++; + yp->stats.tx_bytes += yp->tx_skbuff[entry]->len; /* Free the original skb. */ dev_kfree_skb_irq(yp->tx_skbuff[entry]); yp->tx_skbuff[entry] = 0; @@ -756,11 +897,8 @@ && yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) { /* The ring is no longer full, clear tbusy. */ yp->tx_full = 0; - } - if (yp->tx_full) - netif_stop_queue(dev); - else netif_wake_queue(dev); + } #else if (intr_status & IntrTxDone || yp->tx_tail_desc->tx_errs) { @@ -831,11 +969,8 @@ && yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) { /* The ring is no longer full, clear tbusy. */ yp->tx_full = 0; - } - if (yp->tx_full) - netif_stop_queue(dev); - else netif_wake_queue(dev); + } yp->dirty_tx = dirty_tx; yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE]; @@ -847,7 +982,8 @@ yellowfin_error(dev, intr_status); if (--boguscnt < 0) { - printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", dev->name, intr_status); break; } @@ -855,19 +991,10 @@ if (yellowfin_debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, YF_INW(ioaddr + IntrStatus)); - - /* Code that should never be run! Perhaps remove after testing.. */ - { - static int stopit = 10; - if ((!(netif_running(dev))) && --stopit < 0) { - printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", - dev->name); - free_irq(irq, dev); - } - } + dev->name, inw(ioaddr + IntrStatus)); spin_unlock (&yp->lock); + return; } /* This routine is logically part of the interrupt handler, but separated @@ -876,7 +1003,7 @@ { struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; int entry = yp->cur_rx % RX_RING_SIZE; - int boguscnt = 20; + int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx; if (yellowfin_debug > 4) { printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %8.8x.\n", @@ -905,7 +1032,7 @@ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers," " status %4.4x!\n", dev->name, desc_status); yp->stats.rx_length_errors++; - } else if ((yp->flags & IsGigabit) && (frame_status & 0x0038)) { + } else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) { /* There was a error. */ if (yellowfin_debug > 3) printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n", @@ -915,7 +1042,7 @@ if (frame_status & 0x0008) yp->stats.rx_frame_errors++; if (frame_status & 0x0010) yp->stats.rx_crc_errors++; if (frame_status < 0) yp->stats.rx_dropped++; - } else if ( !(yp->flags & IsGigabit) && + } else if ( !(yp->drv_flags & IsGigabit) && ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) { u8 status1 = buf_addr[data_size-2]; u8 status2 = buf_addr[data_size-1]; @@ -952,21 +1079,22 @@ without copying to a properly sized skbuff. */ if (pkt_len > rx_copybreak) { char *temp = skb_put(skb = yp->rx_skbuff[entry], pkt_len); -#ifndef final_verison /* Remove after testing. */ + yp->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ if (le32desc_to_virt(yp->rx_ring[entry].addr) != temp) - printk(KERN_WARNING "%s: Warning -- the skbuff addresses " + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " "do not match in yellowfin_rx: %p vs. %p / %p.\n", - dev->name, le32desc_to_virt(yp->rx_ring[entry].addr), + dev->name, + le32desc_to_virt(yp->rx_ring[entry].addr), skb->head, temp); #endif - yp->rx_skbuff[entry] = NULL; } else { skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) break; skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the data fields */ -#if 1 || USE_IP_CSUM + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if HAS_IP_COPYSUM eth_copy_and_sum(skb, yp->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); #else @@ -989,9 +1117,9 @@ entry = yp->dirty_rx % RX_RING_SIZE; if (yp->rx_skbuff[entry] == NULL) { struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); - if (skb == NULL) - break; /* Better luck next round. */ yp->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ yp->rx_ring[entry].addr = virt_to_le32desc(skb->tail); @@ -1032,29 +1160,30 @@ netif_stop_queue (dev); if (yellowfin_debug > 1) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", - dev->name, YF_INW(ioaddr + TxStatus), - YF_INW(ioaddr + RxStatus), - YF_INW(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x " + "Rx %4.4x Int %2.2x.\n", + dev->name, inw(ioaddr + TxStatus), + inw(ioaddr + RxStatus), inw(ioaddr + IntrStatus)); printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx); } /* Disable interrupts by clearing the interrupt mask. */ - YF_OUTW(0x0000, ioaddr + IntrEnb); + outw(0x0000, ioaddr + IntrEnb); /* Stop the chip's Tx and Rx processes. */ - YF_OUTL(0x80000000, ioaddr + RxCtrl); - YF_OUTL(0x80000000, ioaddr + TxCtrl); + outl(0x80000000, ioaddr + RxCtrl); + outl(0x80000000, ioaddr + TxCtrl); del_timer(&yp->timer); -#if !defined(final_version) && defined(__i386__) +#if defined(__i386__) if (yellowfin_debug > 2) { - printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring)); + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(yp->tx_ring)); for (i = 0; i < TX_RING_SIZE*2; i++) printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n", - YF_INL(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ', + inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ', i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr, yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status); printk(KERN_DEBUG " Tx status %p:\n", yp->tx_status); @@ -1063,10 +1192,11 @@ i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs, yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused); - printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring)); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(yp->rx_ring)); for (i = 0; i < RX_RING_SIZE; i++) { printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n", - YF_INL(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ', + inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ', i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr, yp->rx_ring[i].result_status); if (yellowfin_debug > 6) { @@ -1105,6 +1235,7 @@ dev->name, bogus_rx); } #endif + return 0; } @@ -1143,17 +1274,17 @@ { struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; long ioaddr = dev->base_addr; - u16 cfg_value = YF_INW(ioaddr + Cnfg); + u16 cfg_value = inw(ioaddr + Cnfg); /* Stop the Rx process to change any value. */ - YF_OUTW(cfg_value & ~0x1000, ioaddr + Cnfg); + outw(cfg_value & ~0x1000, ioaddr + Cnfg); if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ /* Unconditionally log net taps. */ printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); - YF_OUTW(0x000F, ioaddr + AddrMode); + outw(0x000F, ioaddr + AddrMode); } else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter well, or accept all multicasts. */ - YF_OUTW(0x000B, ioaddr + AddrMode); + outw(0x000B, ioaddr + AddrMode); } else if (dev->mc_count > 0) { /* Must use the multicast hash table. */ struct dev_mc_list *mclist; u16 hash_table[4]; @@ -1163,7 +1294,7 @@ i++, mclist = mclist->next) { /* Due to a bug in the early chip versions, multiple filter slots must be set for each address. */ - if (yp->flags & HasMulticastBug) { + if (yp->drv_flags & HasMulticastBug) { set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f, hash_table); set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f, @@ -1176,24 +1307,24 @@ } /* Copy the hash table to the chip. */ for (i = 0; i < 4; i++) - YF_OUTW(hash_table[i], ioaddr + HashTbl + i*2); - YF_OUTW(0x0003, ioaddr + AddrMode); + outw(hash_table[i], ioaddr + HashTbl + i*2); + outw(0x0003, ioaddr + AddrMode); } else { /* Normal, unicast/broadcast-only mode. */ - YF_OUTW(0x0001, ioaddr + AddrMode); + outw(0x0001, ioaddr + AddrMode); } /* Restart the Rx process. */ - YF_OUTW(cfg_value | 0x1000, ioaddr + Cnfg); + outw(cfg_value | 0x1000, ioaddr + Cnfg); } -#ifdef HAVE_PRIVATE_IOCTL static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct yellowfin_private *np = (void *)dev->priv; long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - data[0] = ((struct yellowfin_private *)dev->priv)->phys[0] & 0x1f; + data[0] = np->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); @@ -1201,155 +1332,30 @@ case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (data[0] == np->phys[0]) { + u16 value = data[2]; + switch (data[1]) { + case 0: + /* Check for autonegotiation on or reset. */ + np->medialock = (value & 0x9000) ? 0 : 1; + if (np->medialock) + np->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: np->advertising = value; break; + } + /* Perhaps check_duplex(dev), depending on chip semantics. */ + } mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; } } -#endif /* HAVE_PRIVATE_IOCTL */ -static int __devinit yellowfin_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - struct yellowfin_private *yp; - int option, i, irq; - int flags, chip_idx; - static int find_cnt = 0; - long ioaddr, real_ioaddr; - - chip_idx = ent->driver_data; - flags = chip_info[chip_idx].flags; - - dev = init_etherdev(NULL, sizeof(*yp)); - if (!dev) { - printk (KERN_ERR PFX "cannot allocate ethernet device\n"); - return -ENOMEM; - } - SET_MODULE_OWNER(dev); - - yp = dev->priv; - - if (!request_region (pci_resource_start (pdev, 0), - YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) { - printk (KERN_ERR PFX "cannot obtain I/O port region\n"); - goto err_out_free_netdev; - } - if (!request_mem_region (pci_resource_start (pdev, 1), - YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) { - printk (KERN_ERR PFX "cannot obtain MMIO region\n"); - goto err_out_free_pio_region; - } - - if (pci_enable_device (pdev)) - goto err_out_free_mmio_region; - pci_set_master (pdev); - -#ifdef USE_IO_OPS - real_ioaddr = ioaddr = pci_resource_start (pdev, 0); -#else - real_ioaddr = ioaddr = pci_resource_start (pdev, 1); - ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE); - if (!ioaddr) - goto err_out_free_mmio_region; -#endif - irq = pdev->irq; - - printk(KERN_INFO "%s: %s type %8x at 0x%lx, ", - dev->name, chip_info[chip_idx].name, - YF_INL(ioaddr + ChipRev), real_ioaddr); - - if (flags & IsGigabit) - for (i = 0; i < 6; i++) - dev->dev_addr[i] = YF_INB(ioaddr + StnAddr + i); - else { - int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0); - for (i = 0; i < 6; i++) - dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i); - } - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); - - /* Reset the chip. */ - YF_OUTL(0x80000000, ioaddr + DMACtrl); - - dev->base_addr = ioaddr; - dev->irq = irq; - - pdev->driver_data = dev; - yp->chip_id = chip_idx; - yp->flags = flags; - yp->lock = SPIN_LOCK_UNLOCKED; - - option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; - if (dev->mem_start) - option = dev->mem_start; - - /* The lower four bits are the media type. */ - if (option > 0) { - if (option & 0x200) - yp->full_duplex = 1; - yp->default_port = option & 15; - if (yp->default_port) - yp->medialock = 1; - } - if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) - yp->full_duplex = 1; - - if (yp->full_duplex) - yp->duplex_lock = 1; - - /* The Yellowfin-specific entries in the device structure. */ - dev->open = &yellowfin_open; - dev->hard_start_xmit = &yellowfin_start_xmit; - dev->stop = &yellowfin_close; - dev->get_stats = &yellowfin_get_stats; - dev->set_multicast_list = &set_rx_mode; -#ifdef HAVE_PRIVATE_IOCTL - dev->do_ioctl = &mii_ioctl; -#endif - dev->tx_timeout = yellowfin_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - if (mtu) - dev->mtu = mtu; - - if (yp->flags & HasMII) { - int phy, phy_idx = 0; - for (phy = 0; phy < 32 && phy_idx < 4; phy++) { - int mii_status = mdio_read(ioaddr, phy, 1); - if (mii_status != 0xffff && - mii_status != 0x0000) { - yp->phys[phy_idx++] = phy; - yp->advertising = mdio_read(ioaddr, phy, 4); - printk(KERN_INFO "%s: MII PHY found at address %d, status " - "0x%4.4x advertising %4.4x.\n", - dev->name, phy, mii_status, yp->advertising); - } - } - yp->mii_cnt = phy_idx; - } - - find_cnt++; - - return 0; - -err_out_free_mmio_region: - release_mem_region (pci_resource_start (pdev, 1), YELLOWFIN_SIZE); -err_out_free_pio_region: - release_region (pci_resource_start (pdev, 0), YELLOWFIN_SIZE); -err_out_free_netdev: - unregister_netdev (dev); - kfree (dev); - return -ENODEV; -} - static void __devexit yellowfin_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); struct yellowfin_private *np; if (!dev) @@ -1358,19 +1364,19 @@ unregister_netdev (dev); - release_region (dev->base_addr, YELLOWFIN_SIZE); - release_mem_region (dev->base_addr, YELLOWFIN_SIZE); + pci_release_regions (pdev); #ifndef USE_IO_OPS iounmap ((void *) dev->base_addr); #endif kfree (dev); + pci_set_drvdata(pdev, NULL); } static struct pci_driver yellowfin_driver = { - name: YELLOWFIN_MODULE_NAME, + name: "yellowfin", id_table: yellowfin_pci_tbl, probe: yellowfin_init_one, remove: yellowfin_remove_one, @@ -1380,7 +1386,8 @@ static int __init yellowfin_init (void) { if (debug) /* Emit version even if no cards detected. */ - printk(KERN_INFO "%s", version); + printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", + version1, version2, version3); return pci_module_init (&yellowfin_driver); } @@ -1394,12 +1401,12 @@ module_init(yellowfin_init); module_exit(yellowfin_cleanup); - - + /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS` -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" + * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c" + * compile-command-alphaLX: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c yellowfin.c -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" + * simple-compile-command: "gcc -DMODULE -O6 -c yellowfin.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.4.2/linux/drivers/net/zlib.c linux/drivers/net/zlib.c --- v2.4.2/linux/drivers/net/zlib.c Mon Jul 5 20:35:18 1999 +++ linux/drivers/net/zlib.c Sat Mar 3 10:55:47 2001 @@ -433,7 +433,7 @@ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ - /* Didn't use ct_data typedef below to supress compiler warning */ + /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ @@ -689,7 +689,7 @@ /* =========================================================================== * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * IN assertion: all calls to UPDATE_HASH are made with consecutive * input characters, so that a running hash key can be computed from the * previous key instead of complete recalculation each time. */ @@ -700,7 +700,7 @@ * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. - * IN assertion: all calls to to INSERT_STRING are made with consecutive + * IN assertion: all calls to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of str are valid * (except for the last MIN_MATCH-1 bytes of the input file). */ diff -u --recursive --new-file v2.4.2/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c --- v2.4.2/linux/drivers/parport/ieee1284_ops.c Mon May 15 11:16:30 2000 +++ linux/drivers/parport/ieee1284_ops.c Fri Mar 2 18:43:03 2001 @@ -50,9 +50,6 @@ if (port->irq != PARPORT_IRQ_NONE) { parport_enable_irq (port); no_irq = 0; - - /* Clear out previous irqs. */ - while (!down_trylock (&port->physport->ieee1284.irq)); } port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; @@ -192,6 +189,7 @@ DPRINTK (KERN_DEBUG "%s: Nibble timeout at event 9 (%d bytes)\n", port->name, i/2); + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); break; } diff -u --recursive --new-file v2.4.2/linux/drivers/parport/parport_gsc.c linux/drivers/parport/parport_gsc.c --- v2.4.2/linux/drivers/parport/parport_gsc.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/parport/parport_gsc.c Tue Mar 6 19:44:37 2001 @@ -19,6 +19,8 @@ * Andrea Arcangeli */ +#undef DEBUG /* undef for production */ + #include #include #include @@ -42,13 +44,9 @@ #include -#undef DEBUG /* undef for production */ - -#ifdef DEBUG -#define DPRINTK printk -#else -#define DPRINTK(stuff...) -#endif +MODULE_AUTHOR("Helge Deller "); +MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver"); +MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port"); /* @@ -83,25 +81,18 @@ static void parport_gsc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - DPRINTK(__FILE__ ": got IRQ\n"); parport_generic_irq(irq, (struct parport *) dev_id, regs); } void parport_gsc_write_data(struct parport *p, unsigned char d) { - DPRINTK(__FILE__ ": write (0x%02x) %c \n", d, d); parport_writeb (d, DATA (p)); } unsigned char parport_gsc_read_data(struct parport *p) { -#ifdef DEBUG unsigned char c = parport_readb (DATA (p)); - DPRINTK(__FILE__ ": read (0x%02x) %c\n", c,c); return c; -#else - return parport_readb (DATA (p)); -#endif } void parport_gsc_write_control(struct parport *p, unsigned char d) @@ -113,8 +104,8 @@ /* Take this out when drivers have adapted to the newer interface. */ if (d & 0x20) { - printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n", - p->name, p->cad->name); + pr_debug("%s (%s): use data_reverse for this!\n", + p->name, p->cad->name); parport_gsc_data_reverse (p); } @@ -141,7 +132,7 @@ /* Take this out when drivers have adapted to the newer interface. */ if (mask & 0x20) { - printk (KERN_DEBUG "%s (%s): use data_%s for this!\n", + pr_debug("%s (%s): use data_%s for this!\n", p->name, p->cad->name, (val & 0x20) ? "reverse" : "forward"); if (val & 0x20) @@ -199,16 +190,12 @@ void parport_gsc_inc_use_count(void) { -#ifdef MODULE MOD_INC_USE_COUNT; -#endif } void parport_gsc_dec_use_count(void) { -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif } @@ -360,8 +347,12 @@ struct parport tmp; struct parport *p = &tmp; +#if 1 +#warning Take this out when region handling works again, +#else if (check_region(base, 3)) return NULL; +#endif priv = kmalloc (sizeof (struct parport_gsc_private), GFP_KERNEL); if (!priv) { @@ -474,8 +465,7 @@ static int __initdata parport_count; -static int __init -parport_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) +static int __init parport_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) { unsigned long port; int irq; @@ -515,32 +505,22 @@ { 0 } }; -int __init -parport_gsc_init ( void ) +int __init parport_gsc_init(void) { parport_count = 0; register_driver(parport_drivers_for); - return parport_count; + return 0; } -/* Exported symbols. */ -EXPORT_NO_SYMBOLS; - -#ifdef MODULE - -MODULE_AUTHOR("Helge Deller "); -MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver"); -MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port"); - -int init_module(void) +static int __init parport_gsc_init_module(void) { - return !parport_gsc_init (); + return !parport_gsc_init(); } -void cleanup_module(void) +static void __exit parport_gsc_exit_module(void) { struct parport *p = parport_enumerate(), *tmp; while (p) { @@ -569,4 +549,8 @@ p = tmp; } } -#endif + +EXPORT_NO_SYMBOLS; + +module_init(parport_gsc_init_module); +module_exit(parport_gsc_exit_module); diff -u --recursive --new-file v2.4.2/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.4.2/linux/drivers/parport/parport_pc.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/parport/parport_pc.c Fri Mar 2 18:43:08 2001 @@ -89,6 +89,7 @@ } superios[NR_SUPERIOS] __devinitdata = { {0,},}; static int user_specified __devinitdata = 0; +static int registered_parport; /* frob_control, but for ECR */ static void frob_econtrol (struct parport *pb, unsigned char m, @@ -2605,8 +2606,10 @@ count += parport_pc_find_nonpci_ports (autoirq, autodma); r = pci_register_driver (&parport_pc_pci_driver); - if (r > 0) + if (r >= 0) { + registered_parport = 1; count += r; + } return count; } @@ -2667,6 +2670,7 @@ /* Work out how many ports we have, then get parport_share to parse the irq values. */ unsigned int i; + int ret; for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++); if (i) { if (parport_parse_irqs(i, irq, irqval)) return 1; @@ -2691,7 +2695,11 @@ } } - return !parport_pc_init (io, io_hi, irqval, dmaval); + ret = !parport_pc_init (io, io_hi, irqval, dmaval); + if (ret && registered_parport) + pci_unregister_driver (&parport_pc_pci_driver); + + return ret; } void cleanup_module(void) diff -u --recursive --new-file v2.4.2/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.4.2/linux/drivers/pci/pci.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/pci/pci.c Tue Mar 6 22:44:15 2001 @@ -39,10 +39,12 @@ /** * pci_find_slot - locate PCI device from a given PCI slot * @bus: number of PCI bus on which desired PCI device resides - * @devfn: number of PCI slot in which desired PCI device resides + * @devfn: encodes number of PCI slot in which the desired PCI + * device resides and the logical device number within that slot + * in case of multi-function devices. * - * Given a PCI bus and slot number, the desired PCI device is - * located in system global list of PCI devices. If the device + * Given a PCI bus and slot/function number, the desired PCI device + * is located in system global list of PCI devices. If the device * is found, a pointer to its data structure is returned. If no * device is found, %NULL is returned. */ @@ -58,7 +60,20 @@ return NULL; } - +/** + * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices. If a PCI device is + * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its + * device structure is returned. Otherwise, %NULL is returned. + * A new search is initiated by passing %NULL to the @from argument. + * Otherwise if @from is not %NULL, searches continue from next device on the global list. + */ struct pci_dev * pci_find_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, @@ -82,15 +97,14 @@ /** * pci_find_device - begin or continue searching for a PCI device by vendor/device id * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids - * @device: PCI device id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids * @from: Previous PCI device found in search, or %NULL for new search. * * Iterates through the list of known PCI devices. If a PCI device is * found with a matching @vendor and @device, a pointer to its device structure is * returned. Otherwise, %NULL is returned. - * * A new search is initiated by passing %NULL to the @from argument. - * Otherwise if @from is not null, searches continue from that point. + * Otherwise if @from is not %NULL, searches continue from next device on the global list. */ struct pci_dev * pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) @@ -107,9 +121,9 @@ * Iterates through the list of known PCI devices. If a PCI device is * found with a matching @class, a pointer to its device structure is * returned. Otherwise, %NULL is returned. - * * A new search is initiated by passing %NULL to the @from argument. - * Otherwise if @from is not null, searches continue from that point. + * Otherwise if @from is not %NULL, searches continue from next device + * on the global list. */ struct pci_dev * pci_find_class(unsigned int class, const struct pci_dev *from) @@ -125,7 +139,28 @@ return NULL; } - +/** + * pci_find_capability - query for devices' capabilities + * @dev: PCI device to query + * @cap: capability code + * + * Tell if a device supports a given PCI capability. + * Returns the address of the requested capability structure within the + * device's PCI configuration space or 0 in case the device does not + * support it. Possible values for @cap: + * + * %PCI_CAP_ID_PM Power Management + * + * %PCI_CAP_ID_AGP Accelerated Graphics Port + * + * %PCI_CAP_ID_VPD Vital Product Data + * + * %PCI_CAP_ID_SLOTID Slot Identification + * + * %PCI_CAP_ID_MSI Message Signalled Interrupts + * + * %PCI_CAP_ID_CHSWP CompactPCI HotSwap + */ int pci_find_capability(struct pci_dev *dev, int cap) { @@ -274,12 +309,93 @@ return pin; } +/** + * pci_release_regions - Release reserved PCI I/O and memory resources + * @pdev: PCI device whose resources were previously reserved by pci_request_regions + * + * Releases all PCI I/O and memory resources previously reserved by a + * successful call to pci_request_regions. Call this function only + * after all use of the PCI regions has ceased. + */ +void pci_release_regions(struct pci_dev *pdev) +{ + int i; + + for (i = 0; i < 6; i++) { + if (pci_resource_len(pdev, i) == 0) + continue; + + if (pci_resource_flags(pdev, i) & IORESOURCE_IO) + release_region(pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); + + else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) + release_mem_region(pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); + } +} + +/** + * pci_request_regions - Reserved PCI I/O and memory resources + * @pdev: PCI device whose resources are to be reserved + * + * Mark all PCI regions associated with PCI device @pdev as + * being reserved by owner @res_name. Do not access any + * address inside the PCI regions unless this call returns + * successfully. + * + * Returns 0 on success, or %EBUSY on error. A warning + * message is also printed on failure. + */ +int pci_request_regions(struct pci_dev *pdev, char *res_name) +{ + int i; + + for (i = 0; i < 6; i++) { + if (pci_resource_len(pdev, i) == 0) + continue; + + if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { + if (!request_region(pci_resource_start(pdev, i), + pci_resource_len(pdev, i), res_name)) + goto err_out; + } + + else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { + if (!request_mem_region(pci_resource_start(pdev, i), + pci_resource_len(pdev, i), res_name)) + goto err_out; + } + } + + return 0; + +err_out: + printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n", + pci_resource_flags(pdev, i) & IORESOURCE_IO ? "I/O" : "mem", + i + 1, /* PCI BAR # */ + pci_resource_len(pdev, i), pci_resource_start(pdev, i), + pdev->slot_name); + pci_release_regions(pdev); + return -EBUSY; +} + + /* * Registration of PCI drivers and handling of hot-pluggable devices. */ static LIST_HEAD(pci_drivers); +/** + * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure + * @ids: array of PCI device id structures to search in + * @dev: the PCI device structure to match against + * + * Used by a driver to check whether a PCI device present in the + * system is in its list of supported devices.Returns the matching + * pci_device_id structure or %NULL if there is no match. + */ const struct pci_device_id * pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { @@ -320,6 +436,15 @@ return ret; } +/** + * pci_register_driver - register a new pci driver + * @drv: the driver structure to register + * + * Adds the driver structure to the list of registered drivers + * Returns the number of pci devices which were claimed by the driver + * during registration. The driver remains registered even if the + * return value is zero. + */ int pci_register_driver(struct pci_driver *drv) { @@ -334,6 +459,16 @@ return count; } +/** + * pci_unregister_driver - unregister a pci driver + * @drv: the driver structure to unregister + * + * Deletes the driver structure from the list of registered PCI drivers, + * gives it a chance to clean up by calling its remove() function for + * each device it was responsible for, and marks those devices as + * driverless. + */ + void pci_unregister_driver(struct pci_driver *drv) { @@ -395,6 +530,13 @@ call_usermodehelper (argv [0], argv, envp); } +/** + * pci_insert_device - insert a hotplug device + * @dev: the device to insert + * @bus: where to insert it + * + * Add a new device to the device lists and notify userspace (/sbin/hotplug). + */ void pci_insert_device(struct pci_dev *dev, struct pci_bus *bus) { @@ -427,6 +569,13 @@ } } +/** + * pci_remove_device - remove a hotplug device + * @dev: the device to remove + * + * Delete the device structure from the device lists and + * notify userspace (/sbin/hotplug). + */ void pci_remove_device(struct pci_dev *dev) { @@ -452,6 +601,13 @@ name: "compat" }; +/** + * pci_dev_driver - get the pci_driver of a device + * @dev: the device to query + * + * Returns the appropriate pci_driver structure or %NULL if there is no + * registered driver for the device. + */ struct pci_driver * pci_dev_driver(const struct pci_dev *dev) { @@ -503,7 +659,13 @@ PCI_OP(write, word, u16) PCI_OP(write, dword, u32) - +/** + * pci_set_master - enables bus-mastering for device dev + * @dev: the PCI device to enable + * + * Enables bus-mastering on the device and calls pcibios_set_master() + * to do the needed arch specific settings. + */ void pci_set_master(struct pci_dev *dev) { @@ -518,6 +680,18 @@ pcibios_set_master(dev); } +int +pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) +{ + if(! pci_dma_supported(dev, mask)) + return -EIO; + + dev->dma_mask = mask; + + return 0; +} + + /* * Translate the low bits of the PCI base * to the resource type @@ -837,8 +1011,15 @@ dev->irq = irq; } -/* - * Fill in class and map information of a device +/** + * pci_setup_device - fill in class and map information of a device + * @dev: the device structure to fill + * + * Initialize the device structure with information about the device's + * vendor,class,memory and IO-space addresses,IRQ lines etc. + * Called at initialisation of the PCI subsystem and by CardBus services. + * Returns 0 on success and -1 if unknown type of device (not normal, bridge + * or CardBus). */ int pci_setup_device(struct pci_dev * dev) { @@ -1201,11 +1382,14 @@ EXPORT_SYMBOL(pci_root_buses); EXPORT_SYMBOL(pci_enable_device); EXPORT_SYMBOL(pci_find_capability); +EXPORT_SYMBOL(pci_release_regions); +EXPORT_SYMBOL(pci_request_regions); EXPORT_SYMBOL(pci_find_class); EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_slot); EXPORT_SYMBOL(pci_find_subsys); EXPORT_SYMBOL(pci_set_master); +EXPORT_SYMBOL(pci_set_dma_mask); EXPORT_SYMBOL(pci_set_power_state); EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_register_driver); diff -u --recursive --new-file v2.4.2/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.4.2/linux/drivers/pci/pci.ids Tue Jan 2 16:58:45 2001 +++ linux/drivers/pci/pci.ids Tue Mar 6 19:34:25 2001 @@ -85,6 +85,7 @@ 1de1 3904 DC390F Ultra Wide SCSI Controller 0012 53c895a 0020 53c1010 Ultra3 SCSI Adapter + 0021 53c1010 66MHz Ultra3 SCSI Adapter 008f 53c875J 1092 8000 FirePort 40 SCSI Controller 1092 8760 FirePort 40 Dual SCSI Host Adapter @@ -1259,7 +1260,7 @@ 109e Brooktree Corporation 0350 Bt848 TV with DMA push 0351 Bt849A Video capture - 036c Bt879(??) Video Capture + 036c Bt879(?) Video Capture 13e9 0070 Win/TV (Video Section) 036e Bt878 0070 13eb WinTV/GO @@ -3936,7 +3937,7 @@ # 1507 HTEC Ltd # Commented out because there are no known HTEC chips and 1507 is already # used by mistake by Motorola (see vendor ID 1057) -1507 Motorola ?? / HTEC +1507 Motorola ? / HTEC 0001 MPC105 [Eagle] 0002 MPC106 [Grackle] 0003 MPC8240 [Kahlua] @@ -4254,7 +4255,7 @@ 270b Xantel Corporation 270f Chaintech Computer Co. Ltd 2711 AVID Technology Inc. -2a15 3D Vision(???) +2a15 3D Vision(?) 3000 Hansol Electronics Inc. 3142 Post Impression Systems. 3388 Hint Corp diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c --- v2.4.2/linux/drivers/pcmcia/bulkmem.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/pcmcia/bulkmem.c Tue Mar 6 19:28:32 2001 @@ -41,6 +41,7 @@ #include #include #include +#include #define IN_CARD_SERVICES #include diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c --- v2.4.2/linux/drivers/pcmcia/cardbus.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/pcmcia/cardbus.c Sat Mar 3 10:49:17 2001 @@ -288,7 +288,6 @@ if (res->flags) pci_assign_resource(dev, r); } - pci_enable_device(dev); /* XXX check return */ /* Does this function have an interrupt at all? */ pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin); @@ -297,6 +296,7 @@ pci_writeb(dev, PCI_INTERRUPT_LINE, irq); } + pci_enable_device(dev); /* XXX check return */ pci_insert_device(dev, bus); } diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c --- v2.4.2/linux/drivers/pcmcia/i82365.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/pcmcia/i82365.c Sat Mar 3 10:50:29 2001 @@ -210,13 +210,13 @@ PCI_COMMAND_MASTER|PCI_COMMAND_WAIT) /* These definitions must match the pcic table! */ -typedef enum pcic_id { #ifdef CONFIG_ISA +typedef enum pcic_id { IS_I82365A, IS_I82365B, IS_I82365DF, IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469, IS_PD6710, IS_PD672X, IS_VT83C469, -#endif } pcic_id; +#endif /* Flags for classifying groups of controllers */ #define IS_VADEM 0x0001 diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c --- v2.4.2/linux/drivers/pcmcia/rsrc_mgr.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/pcmcia/rsrc_mgr.c Tue Mar 6 19:28:32 2001 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -251,7 +252,7 @@ base, base+num-1); bad = fail = 0; step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); - for (i = base; i < base+num; i = j + step) { + for (i = j = base; i < base+num; i = j + step) { if (!fail) { for (j = i; j < base+num; j += step) if ((check_mem_resource(j, step) == 0) && is_valid(j)) diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c --- v2.4.2/linux/drivers/pcmcia/tcic.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/pcmcia/tcic.c Tue Mar 6 19:28:32 2001 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.2/linux/drivers/s390/char/tape34xx.c linux/drivers/s390/char/tape34xx.c --- v2.4.2/linux/drivers/s390/char/tape34xx.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/s390/char/tape34xx.c Fri Mar 2 11:12:07 2001 @@ -1437,7 +1437,7 @@ debug_text_event (tape_debug_area,6,"xdefhandle"); #endif /* TAPE_DEBUG */ tapestate_set (tape, TS_FAILED); - PRINT_ERR ("TAPE34XX: An unexpected Unit Check occured.\n"); + PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n"); PRINT_ERR ("TAPE34XX: Please read Documentation/s390/TAPE and report it!\n"); PRINT_ERR ("TAPE34XX: Current state is: %s", (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ? @@ -1804,7 +1804,7 @@ tape->wanna_wakeup=1; wake_up (&tape->wq); } else { - PRINT_ERR ("TAPE34XX: An unexpected Unit Check occured.\n"); + PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n"); PRINT_ERR ("TAPE34XX: Please send the following 20 lines of output to cotte@de.ibm.com\n"); PRINT_ERR ("TAPE34XX: Current state is: %s", (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ? diff -u --recursive --new-file v2.4.2/linux/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c --- v2.4.2/linux/drivers/s390/net/ctc.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/s390/net/ctc.c Fri Mar 2 11:12:07 2001 @@ -884,7 +884,7 @@ if (sense & 0x01) printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name); else - printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name); + printk(KERN_DEBUG "%s: System reset occurred (remote side)\n", dev->name); #endif } else if (sense & 0x20) { if (sense & 0x04) diff -u --recursive --new-file v2.4.2/linux/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c --- v2.4.2/linux/drivers/s390/net/netiucv.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/s390/net/netiucv.c Tue Mar 6 19:44:37 2001 @@ -65,9 +65,6 @@ MODULE_PARM_DESC (iucv, "Specify the userids associated with iucv0-iucv9:\n" "iucv=userid1,userid2,...,userid10\n"); -#ifdef MODVERSIONS -#include -#endif #else #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT diff -u --recursive --new-file v2.4.2/linux/drivers/s390/s390mach.c linux/drivers/s390/s390mach.c --- v2.4.2/linux/drivers/s390/s390mach.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/s390/s390mach.c Fri Mar 2 11:12:07 2001 @@ -139,7 +139,7 @@ #endif memcpy( &mcic, - &S390_lowcore.mcck_interuption_code, + &S390_lowcore.mcck_interruption_code, sizeof(__u64)); if ( mcic.mcc.mcd.cp ) // CRW pending ? diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c --- v2.4.2/linux/drivers/sbus/char/aurora.c Mon Dec 11 12:37:03 2000 +++ linux/drivers/sbus/char/aurora.c Tue Mar 6 19:44:37 2001 @@ -1942,7 +1942,7 @@ change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((tmp.close_delay != port->close_delay) || (tmp.closing_wait != port->closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c --- v2.4.2/linux/drivers/sbus/char/flash.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/char/flash.c Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: flash.c,v 1.22 2001/02/13 01:17:00 davem Exp $ +/* $Id: flash.c,v 1.23 2001/03/02 06:32:40 davem Exp $ * flash.c: Allow mmap access to the OBP Flash, for OBP updates. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -106,12 +106,17 @@ size_t count, loff_t *ppos) { unsigned long p = file->f_pos; + int i; if (count > flash.read_size - p) count = flash.read_size - p; - if (copy_to_user(buf, flash.read_base + p, count) < 0) - return -EFAULT; + for (i = 0; i < count; i++) { + u8 data = readb(flash.read_base + p + i); + if (put_user(data, buf)) + return -EFAULT; + buf++; + } file->f_pos += count; return count; diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.4.2/linux/drivers/sbus/char/vfc_dev.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/char/vfc_dev.c Tue Mar 6 22:44:16 2001 @@ -362,7 +362,7 @@ vfc_capture_poll(dev); break; case DIAGMODE: - if(suser()) { + if(capable(CAP_SYS_ADMIN)) { vfc_lock_device(dev); dev->control_reg |= VFC_CONTROL_DIAGMODE; sbus_writel(dev->control_reg, &dev->regs->control); diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c --- v2.4.2/linux/drivers/scsi/3w-xxxx.c Wed Nov 8 17:09:50 2000 +++ linux/drivers/scsi/3w-xxxx.c Fri Mar 2 18:38:38 2001 @@ -5,7 +5,7 @@ Modifications By: Joel Jacobson Arnaldo Carvalho de Melo - Copyright (C) 1999-2000 3ware Inc. + Copyright (C) 1999-2001 3ware Inc. Kernel compatablity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -67,6 +67,15 @@ systems. 08/21/00 - release previously allocated resources on failure at tw_allocate_memory (acme) + 1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when + controller status is non-zero. + Added handling of request_sense opcode. + Fix possible null pointer dereference in + tw_reset_device_extension() + 1.02.00.004 - Add support for device id of 3ware 7000 series controllers. + Make tw_setfeature() call with interrupts disabled. + Register interrupt handler before enabling interrupts. + Clear attention interrupt before draining aen queue. */ #include @@ -112,7 +121,7 @@ }; /* Globals */ -char *tw_driver_version="1.02.00.002"; +char *tw_driver_version="1.02.00.004"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -581,174 +590,179 @@ struct pci_dev *tw_pci_dev = NULL; u32 status_reg_value; unsigned char c = 1; + int i; + u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 }; dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n"); - while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, TW_DEVICE_ID, tw_pci_dev))) { - if (pci_enable_device(tw_pci_dev)) - continue; - /* Prepare temporary device extension */ - tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC); - if (tw_dev == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards); - continue; - } - memset(tw_dev, 0, sizeof(TW_Device_Extension)); - - error = tw_initialize_device_extension(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - /* Calculate the cards register addresses */ - tw_dev->registers.base_addr = pci_resource_start(tw_pci_dev, 0); - tw_dev->registers.control_reg_addr = pci_resource_start(tw_pci_dev, 0); - tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4; - tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8; - tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC; - /* Save pci_dev struct to device extension */ - tw_dev->tw_pci_dev = tw_pci_dev; - - /* Poll status register for 60 secs for 'Controller Ready' flag */ - if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - /* Disable interrupts on the card */ - tw_disable_interrupts(tw_dev); - - while (tries < TW_MAX_RESET_TRIES) { - /* Do soft reset */ - tw_soft_reset(tw_dev); - - error = tw_aen_drain_queue(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards); - tries++; + for (i=0;iregisters.base_addr = pci_resource_start(tw_pci_dev, 0); + tw_dev->registers.control_reg_addr = pci_resource_start(tw_pci_dev, 0); + tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4; + tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8; + tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC; + /* Save pci_dev struct to device extension */ + tw_dev->tw_pci_dev = tw_pci_dev; + + /* Poll status register for 60 secs for 'Controller Ready' flag */ + if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards); + tw_free_device_extension(tw_dev); + kfree(tw_dev); continue; } - /* Now the controller is in a good state */ - break; - } + /* Disable interrupts on the card */ + tw_disable_interrupts(tw_dev); + + while (tries < TW_MAX_RESET_TRIES) { + /* Do soft reset */ + tw_soft_reset(tw_dev); + + error = tw_aen_drain_queue(tw_dev); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards); + tries++; + continue; + } - if (tries >= TW_MAX_RESET_TRIES) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } + /* Check for controller errors */ + if (tw_check_errors(tw_dev)) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards); + tries++; + continue; + } - /* Make sure that io region isn't already taken */ - if (check_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE)) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", - (tw_dev->tw_pci_dev->resource[0].start), - (tw_dev->tw_pci_dev->resource[0].start) + - TW_IO_ADDRESS_RANGE, numcards); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } + /* Empty the response queue */ + error = tw_empty_response_que(tw_dev); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards); + tries++; + continue; + } + + /* Now the controller is in a good state */ + break; + } + + if (tries >= TW_MAX_RESET_TRIES) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } + + /* Make sure that io region isn't already taken */ + if (check_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE)) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", + (tw_dev->tw_pci_dev->resource[0].start), + (tw_dev->tw_pci_dev->resource[0].start) + + TW_IO_ADDRESS_RANGE, numcards); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } - /* Reserve the io address space */ - request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME); - error = tw_initialize_units(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards); - release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } + /* Reserve the io address space */ + request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME); + error = tw_initialize_units(tw_dev); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards); + release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } - error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards); - release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } + error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards); + release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } - /* Calculate max cmds per lun */ - if (tw_dev->num_units > 0) - tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units; + /* Calculate max cmds per lun */ + if (tw_dev->num_units > 0) + tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units; /* Register the card with the kernel SCSI layer */ - host = scsi_register(tw_host, sizeof(TW_Device_Extension)); - if( host == NULL) - { - release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } + host = scsi_register(tw_host, sizeof(TW_Device_Extension)); + if( host == NULL) + { + release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } - status_reg_value = inl(tw_dev->registers.status_reg_addr); + status_reg_value = inl(tw_dev->registers.status_reg_addr); - dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no, + dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no, (u32)(tw_pci_dev->resource[0].start), tw_pci_dev->irq, (status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, (status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24); - if (host->hostdata) { - tw_dev2 = (TW_Device_Extension *)host->hostdata; - memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension)); - tw_device_extension_list[tw_device_extension_count] = tw_dev2; - numcards++; - tw_device_extension_count = numcards; - tw_dev2->host = host; - } else { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1); - scsi_unregister(host); - release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); - tw_free_device_extension(tw_dev); - kfree(tw_dev); - continue; - } - - /* Re-enable interrupts on the card */ - tw_enable_interrupts(tw_dev2); + if (host->hostdata) { + tw_dev2 = (TW_Device_Extension *)host->hostdata; + memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension)); + tw_device_extension_list[tw_device_extension_count] = tw_dev2; + numcards++; + tw_device_extension_count = numcards; + tw_dev2->host = host; + } else { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1); + scsi_unregister(host); + release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + continue; + } - /* Now setup the interrupt handler */ - error = tw_setup_irq(tw_dev2); - if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1); - scsi_unregister(host); - release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); - - tw_free_device_extension(tw_dev); - kfree(tw_dev); - numcards--; - continue; - } + /* Tell the firmware we support shutdown notification*/ + tw_setfeature(tw_dev2, 2, 1, &c); - /* Free the temporary device extension */ - if (tw_dev) - kfree(tw_dev); + /* Now setup the interrupt handler */ + error = tw_setup_irq(tw_dev2); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1); + scsi_unregister(host); + release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); + + tw_free_device_extension(tw_dev); + kfree(tw_dev); + numcards--; + continue; + } - /* Tell the firmware we support shutdown notification*/ - tw_setfeature(tw_dev2, 2, 1, &c); + /* Re-enable interrupts on the card */ + tw_enable_interrupts(tw_dev2); + + /* Free the temporary device extension */ + if (tw_dev) + kfree(tw_dev); + } } if (numcards == 0) @@ -1089,15 +1103,14 @@ /* Handle attention interrupt */ if (do_attention_interrupt) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n"); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n"); + tw_clear_attention_interrupt(tw_dev); tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); if (error) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n"); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); - } else { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n"); - tw_clear_attention_interrupt(tw_dev); } } @@ -1133,13 +1146,15 @@ response_que.value = inl(response_que_addr); request_id = response_que.u.response_id; command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + error = 0; if (command_packet->status != 0) { - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); + printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit); + error = 1; } if (tw_dev->state[request_id] != TW_S_POSTED) { printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode); + error = 1; } - error = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id); /* Check for internal command */ if (tw_dev->srb[request_id] == 0) { @@ -1183,8 +1198,8 @@ } if (error) { /* Tell scsi layer there was an error */ - printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); - tw_dev->srb[request_id]->result = (DID_ERROR << 16); + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); + tw_dev->srb[request_id]->result = (DID_RESET << 16); } else { /* Tell scsi layer command was a success */ tw_dev->srb[request_id]->result = (DID_OK << 16); @@ -1467,8 +1482,11 @@ (tw_dev->state[i] != TW_S_INITIAL) && (tw_dev->state[i] != TW_S_COMPLETED)) { srb = tw_dev->srb[i]; - srb->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); + if (srb != NULL) { + srb = tw_dev->srb[i]; + srb->result = (DID_RESET << 16); + tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); + } } } @@ -1573,6 +1591,8 @@ /* This function will find and initialize any cards */ int tw_scsi_detect(Scsi_Host_Template *tw_host) { + int ret; + dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_detect()\n"); /* Check if the kernel has PCI interface compiled in */ @@ -1581,7 +1601,11 @@ return 0; } - return(tw_findcards(tw_host)); + spin_unlock_irq(&io_request_lock); + ret = tw_findcards(tw_host); + spin_lock_irq(&io_request_lock); + + return ret; } /* End tw_scsi_detect() */ /* This is the new scsi eh abort function */ @@ -1812,6 +1836,10 @@ dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n"); error = tw_scsiop_read_capacity(tw_dev, request_id); break; + case REQUEST_SENSE: + dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n"); + error = tw_scsiop_request_sense(tw_dev, request_id); + break; case TW_IOCTL: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n"); error = tw_ioctl(tw_dev, request_id); @@ -2166,6 +2194,23 @@ return 0; } /* End tw_scsiop_read_write() */ + +/* This function will handle the request sense scsi command */ +int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id) +{ + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n"); + + /* For now we just zero the sense buffer */ + memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + + /* If we got a request_sense, we probably want a reset, return error */ + tw_dev->srb[request_id]->result = (DID_ERROR << 16); + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + + return 0; +} /* End tw_scsiop_request_sense() */ /* This function will handle test unit ready scsi command */ int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id) diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/3w-xxxx.h linux/drivers/scsi/3w-xxxx.h --- v2.4.2/linux/drivers/scsi/3w-xxxx.h Mon Dec 11 13:19:49 2000 +++ linux/drivers/scsi/3w-xxxx.h Fri Mar 2 18:38:38 2001 @@ -3,8 +3,9 @@ Written By: Adam Radford Modifications By: Joel Jacobson + Arnaldo Carvalho de Melo - Copyright (C) 1999 3ware Inc. + Copyright (C) 1999-2001 3ware Inc. Kernel compatablity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -97,6 +98,8 @@ #define TW_DEVICE_NAME "3ware Storage Controller" #define TW_VENDOR_ID (0x13C1) /* 3ware */ #define TW_DEVICE_ID (0x1000) /* Storage Controller */ +#define TW_DEVICE_ID2 (0x1001) /* 7000 series controller */ +#define TW_NUMDEVICES 2 /* Command packet opcodes */ #define TW_OP_NOP 0x0 @@ -289,7 +292,7 @@ unsigned short aen_queue[TW_Q_LENGTH]; unsigned char aen_head; unsigned char aen_tail; - u32 flags; + long flags; /* long req'd for set_bit --RR */ } TW_Device_Extension; /* Function prototypes */ @@ -328,6 +331,7 @@ int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id); +int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id); int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val); diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c --- v2.4.2/linux/drivers/scsi/AM53C974.c Sun Nov 12 20:40:42 2000 +++ linux/drivers/scsi/AM53C974.c Fri Mar 2 18:38:38 2001 @@ -676,6 +676,10 @@ #endif instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata)); + if (!instance) { + printk(KERN_WARNING "AM53C974: Unable to register host, aborting.\n"); + return 0; + } hostdata = (struct AM53C974_hostdata *) instance->hostdata; instance->base = 0; instance->io_port = pci_resource_start(pdev, 0); diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.4.2/linux/drivers/scsi/ChangeLog.ncr53c8xx Mon Jun 19 17:59:41 2000 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Tue Mar 6 19:34:25 2001 @@ -1,3 +1,35 @@ +Mon Feb 12 22:30 2001 Gerard Roudier (groudier@club-internet.fr) + * version ncr53c8xx-3.4.3 + - Call pci_enable_device() as AC wants this to be done. + - Get both the BAR cookies actual and PCI BAR values. + (see Changelog.sym53c8xx rev. 1.7.3 for details) + - Merge changes for linux-2.4 that declare the host template + in the driver object also when the driver is statically + linked with the kernel. + +Sun Sep 24 21:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version ncr53c8xx-3.4.2 + - See Changelog.sym53c8xx, driver version 1.7.2. + +Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version ncr53c8xx-3.4.1 + - Provide OpenFirmare path through the proc FS on PPC. + - Remove trailing argument #2 from a couple of #undefs. + +Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version ncr53c8xx-3.4.0 + - Remove the PROFILE C and SCRIPTS code. + This facility was not this useful and thus was not longer + desirable given the increasing complexity of the driver code. + - Merges from FreeBSD sym-1.6.2 driver: + * Clarify memory barriers needed by the driver for architectures + that implement a weak memory ordering. + - General cleanup: + Move definitions for barriers and IO/MMIO operations to the + sym53c8xx_defs.h header files. They are now shared by the + both drivers. + Use SCSI_NCR_IOMAPPED instead of NCR_IOMAPPED. + Thu May 11 12:30 2000 Pam Delaney (pam.delaney@lsil.com) * revision 3.3b diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx --- v2.4.2/linux/drivers/scsi/ChangeLog.sym53c8xx Mon Jun 19 17:59:41 2000 +++ linux/drivers/scsi/ChangeLog.sym53c8xx Tue Mar 6 19:34:25 2001 @@ -1,3 +1,92 @@ +Sun Mar 4 18:30 2001 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.3a + - Fix an issue in the ncr_int_udc() (unexpected disconnect) + handling. If the DSA didn't match a CCB, a bad write to + memory could happen. + +Mon Feb 12 22:30 2001 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.3 + - Support for hppa. + Tiny patch sent to me by Robert Hirst. + - Tiny patch for ia64 sent to me by Pamela Delaney. + +Tue Feb 6 13:30 2001 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.3-pre1 + - Call pci_enable_device() as AC wants this to be done. + - Get both the BAR cookies used by CPU and actual PCI BAR + values used from SCRIPTS. Recent PCI chips are able to + access themselves using internal cycles, but they compare + BAR values to destination address to make decision. + Earlier chips simply use PCI transactions to access IO + registers from SCRIPTS. + The bus_dvma_to_mem() interface that reverses the actual + PCI BAR value from the BAR cookie is now useless. + This point had been discussed at the list and the solution + got approved by PCI code maintainer (Martin Mares). + - Merge changes for linux-2.4 that declare the host template + in the driver object also when the driver is statically + linked with the kernel. + - Increase SCSI message size up to 12 bytes, given that 8 + bytes was not enough for the PPR message (fix). + - Add field 'maxoffs_st' (max offset for ST data transfers). + The C1010 supports offset 62 in DT mode but only 31 in + ST mode, to 2 different values for the max SCSI offset + are needed. Replace the obviously wrong masking of the + offset against 0x1f for ST mode by a lowering to + maxoffs_st of the SCSI offset in ST mode. + - Refine a work-around for the C1010-66. Revision 1 does + not requires extra cycles in DT DATA OUT phase. + - Add a missing endian-ization (abrt_tbl.addr). + - Minor clean-up in the np structure for fields accessed + from SCRIPTS that requires special alignments. + +Sun Sep 24 21:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.2 + - Remove the hack for PPC added in previous driver version. + - Add FE_DAC feature bit to distinguish between 64 bit PCI + addressing (FE_DAC) and 64 bit PCI interface (FE_64BIT). + - Get rid of the boot command line "ultra:" argument. + This parameter wasn't that clever since we can use "sync:" + for Ultra/Ultra2 settings, and for Ultra3 we may want to + pass PPR options (for now only DT clocking). + - Add FE_VARCLK feature bit that indicates that SCSI clock + frequency may vary depending on board design and thus, + the driver should try to evaluate the SCSI clock. + - Simplify the way the driver determine the SCSI clock: + ULTRA3 -> 160 MHz, ULTRA2 -> 80 MHz otherwise 40 MHz. + Measure the SCSI clock frequency if FE_VARCLK is set. + - Remove FE_CLK80 feature bit that got useless. + - Add support for the SYM53C875A (Pamela Delaney). + +Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.1 + - Provide OpenFirmare path through the proc FS on PPC. + - Download of on-chip SRAM using memcpy_toio() doesn't work + on PPC. Restore previous method (MEMORY MOVE from SCRIPTS). + - Remove trailing argument #2 from a couple of #undefs. + +Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.0 + - Remove the PROFILE C and SCRIPTS code. + This facility was not this useful and thus was not longer + desirable given the increasing complexity of the driver code. + - Merges from FreeBSD sym-1.6.2 driver: + * Clarify memory barriers needed by the driver for architectures + that implement a weak memory ordering. + * Simpler handling of illegal phases and data overrun from + SCRIPTS. These errors are now immediately reported to + the C code by an interrupt. + * Sync the residual handling code with sym-1.6.2 and now + report `resid' to user for linux version >= 2.3.99 + - General cleanup: + Move definitions for barriers and IO/MMIO operations to the + sym53c8xx_defs.h header files. They are now shared by the + both drivers. + Remove unused options that claimed to optimize for the 896. + If fact, they were not this clever. :) + Use SCSI_NCR_IOMAPPED instead of NCR_IOMAPPED. + Remove a couple of unused fields from data structures. + Thu May 11 12:40 2000 Pam Delaney (pam.delaney@lsil.com) * version sym53c8xx-1.6b - Merged version. diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.4.2/linux/drivers/scsi/Config.in Sat Dec 30 18:38:37 2000 +++ linux/drivers/scsi/Config.in Sun Mar 4 14:30:18 2001 @@ -50,12 +50,14 @@ dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI -dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI -if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then - bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT - int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8 - bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS - int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 +source drivers/scsi/aic7xxx/Config.in +if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then + dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI + if [ "$CONFIG_SCSI_AIC7XXX_OLD" != "n" ]; then + bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT + int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE 8 + bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_OLD_PROC_STATS + fi fi dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.4.2/linux/drivers/scsi/Makefile Sat Dec 30 11:23:14 2000 +++ linux/drivers/scsi/Makefile Tue Mar 6 19:44:37 2001 @@ -14,6 +14,8 @@ MOD_IN_SUB_DIRS := ALL_SUB_DIRS := $(SUB_DIRS) pcmcia +subdir-$(CONFIG_SCSI_AIC7XXX) += aic7xxx + ifeq ($(CONFIG_PCMCIA),y) SUB_DIRS += pcmcia MOD_IN_SUB_DIRS += pcmcia @@ -63,7 +65,7 @@ obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o -obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o +obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_IPS) += ips.o obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o @@ -112,14 +114,18 @@ obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o obj-$(CONFIG_SCSI_FCAL) += fcal.o +ifeq ($(CONFIG_ARCH_ACORN),y) +mod-subdirs += ../acorn/scsi +subdir-y += ../acorn/scsi +obj-y += ../acorn/scsi/acorn-scsi.o +endif + obj-$(CONFIG_CHR_DEV_ST) += st.o obj-$(CONFIG_CHR_DEV_OSST) += osst.o obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o - - scsi_mod-objs := scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_proc.o scsi_error.o \ scsi_obsolete.o scsi_queue.o scsi_lib.o \ @@ -147,7 +153,6 @@ a100u2w.o: $(a100u2w-objs) $(LD) -r -o $@ $(a100u2w-objs) - 53c8xx_d.h: 53c7,8xx.scr script_asm.pl ln -sf 53c7,8xx.scr fake8.c diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c --- v2.4.2/linux/drivers/scsi/NCR53C9x.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/scsi/NCR53C9x.c Tue Mar 6 19:44:37 2001 @@ -1820,7 +1820,7 @@ * with ESP_CMD_DMA ... */ - /* figure out how much needs to be transfered */ + /* figure out how much needs to be transferred */ hmuch = SCptr->SCp.this_residual; ESPDATA(("hmuch<%d> pio ", hmuch)); esp->current_transfer_size = hmuch; @@ -1942,18 +1942,18 @@ /* check int. status */ if (esp->ireg & ESP_INTR_DC) { /* disconnect */ - ESPDATA(("disconnect; %d transfered ... ", i)); + ESPDATA(("disconnect; %d transferred ... ", i)); break; } else if (esp->ireg & ESP_INTR_FDONE) { /* function done */ - ESPDATA(("function done; %d transfered ... ", i)); + ESPDATA(("function done; %d transferred ... ", i)); break; } /* XXX fixme: bail out on stall */ if (fifo_stuck > 10) { /* we're stuck */ - ESPDATA(("fifo stall; %d transfered ... ", i)); + ESPDATA(("fifo stall; %d transferred ... ", i)); break; } } @@ -1964,7 +1964,7 @@ if (thisphase == in_dataout) hmuch += fifocnt; /* stuck?? adjust data pointer ...*/ - /* tell do_data_finale how much was transfered */ + /* tell do_data_finale how much was transferred */ esp->current_transfer_size -= hmuch; /* still not completely sure on this one ... */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c --- v2.4.2/linux/drivers/scsi/NCR53c406a.c Mon Sep 18 13:36:24 2000 +++ linux/drivers/scsi/NCR53c406a.c Fri Mar 2 11:12:11 2001 @@ -184,13 +184,13 @@ /* ================================================================= */ #if USE_BIOS -static void *bios_base = (void *)0; +static void *bios_base; #endif #if PORT_BASE static int port_base = PORT_BASE; #else -static int port_base = 0; +static int port_base; #endif #if IRQ_LEV @@ -200,16 +200,16 @@ #endif #if USE_DMA -static int dma_chan = 0; +static int dma_chan; #endif #if USE_PIO static int fast_pio = USE_FAST_PIO; #endif -static Scsi_Cmnd *current_SC = NULL; -static volatile int internal_done_flag = 0; -static volatile int internal_done_errcode = 0; +static Scsi_Cmnd *current_SC; +static volatile int internal_done_flag; +static volatile int internal_done_errcode; static char info_msg[256]; /* ================================================================= */ @@ -484,17 +484,17 @@ #endif USE_BIOS #ifdef PORT_BASE - if (check_region(port_base, 0x10)) /* ports already snatched */ + if (!request_region(port_base, 0x10, "NCR53c406a")) /* ports already snatched */ port_base = 0; #else /* autodetect */ if (port_base) { /* LILO override */ - if (check_region(port_base, 0x10)) + if (!request_region(port_base, 0x10, "NCR53c406a")) port_base = 0; } else { for(i=0; i 0) { if(request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", NULL)){ printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level); - return 0; + goto err_release; } tpnt->can_queue = 1; DEB(printk("NCR53c406a: allocated IRQ %d\n", irq_level)); @@ -548,19 +548,19 @@ DEB(printk("NCR53c406a: No interrupts detected\n")); #if USE_DMA printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n"); - return 0; + goto err_release; #endif USE_DMA } else { DEB(printk("NCR53c406a: Shouldn't get here!\n")); - return 0; + goto err_free_irq; } #if USE_DMA dma_chan = DMA_CHAN; if(request_dma(dma_chan, "NCR53c406a") != 0){ printk("NCR53c406a: unable to allocate DMA channel %d\n", dma_chan); - return 0; + goto err_release; } DEB(printk("Allocated DMA channel %d\n", dma_chan)); @@ -570,6 +570,10 @@ tpnt->proc_name = "NCR53c406a"; shpnt = scsi_register(tpnt, 0); + if (!shpnt) { + printk("NCR53c406a: Unable to register host, giving up.\n"); + goto err_free_dma; + } shpnt->irq = irq_level; shpnt->io_port = port_base; shpnt->n_io_port = 0x10; @@ -586,6 +590,17 @@ #endif return (tpnt->present); + + + err_free_dma: +#if USE_DMA + free_dma(dma_chan); +#endif + err_free_irq: + free_irq(irq_level, do_NCR53c406a_intr); + err_release: + release_region(port_base, 0x10); + return 0; } /* called from init/main.c */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx --- v2.4.2/linux/drivers/scsi/README.aic7xxx Thu Feb 10 19:00:35 2000 +++ linux/drivers/scsi/README.aic7xxx Wed Dec 31 16:00:00 1969 @@ -1,511 +0,0 @@ - AIC7xxx Driver for Linux - -Introduction ----------------------------- -The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com) -SCSI controllers and chipsets. Major portions of the driver and driver -development are shared between both Linux and FreeBSD. Support for the -AIC-7xxx chipsets have been in the default Linux kernel since approximately -linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD -2.1.0 or later. - - Supported cards/chipsets - ---------------------------- - Adaptec Cards - ---------------------------- - AHA-274x - AHA-274xT - AHA-2842 - AHA-2910B - AHA-2920C - AHA-2930 - AHA-2930U - AHA-2930CU - AHA-2930U2 - AHA-2940 - AHA-2940W - AHA-2940U - AHA-2940UW - AHA-2940UW-PRO - AHA-2940AU - AHA-2940U2W - AHA-2940U2 - AHA-2940U2B - AHA-2940U2BOEM - AHA-2944D - AHA-2944WD - AHA-2944UD - AHA-2944UWD - AHA-2950U2 - AHA-2950U2W - AHA-2950U2B - AHA-29160M - AHA-3940 - AHA-3940U - AHA-3940W - AHA-3940UW - AHA-3940AUW - AHA-3940U2W - AHA-3950U2B - AHA-3950U2D - AHA-3960D - AHA-39160M - AHA-3985 - AHA-3985U - AHA-3985W - AHA-3985UW - - Motherboard Chipsets - ---------------------------- - AIC-777x - AIC-785x - AIC-786x - AIC-787x - AIC-788x - AIC-789x - AIC-3860 - - Bus Types - ---------------------------- - W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support - SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s. - U - Ultra SCSI, transfer rates up to 40MB/s. - U2- Ultra 2 SCSI, transfer rates up to 80MB/s. - D - Differential SCSI. - T - Twin Channel SCSI. Up to 14 SCSI devices. - - AHA-274x - EISA SCSI controller - AHA-284x - VLB SCSI controller - AHA-29xx - PCI SCSI controller - AHA-394x - PCI controllers with two separate SCSI controllers on-board. - AHA-398x - PCI RAID controllers with three separate SCSI controllers - on-board. - - Not Supported Devices - ------------------------------ - Adaptec Cards - ---------------------------- - AHA-2920 (Only the cards that use the Future Domain chipset are not - supported, any 2920 cards based on Adaptec AIC chipsets, - such as the 2920C, are supported) - AAA-13x Raid Adapters - AAA-113x Raid Port Card - - Motherboard Chipsets - ---------------------------- - AIC-7810 - - Bus Types - ---------------------------- - R - Raid Port busses are not supported. - - The hardware RAID devices sold by Adaptec are *NOT* supported by this - driver (and will people please stop emailing me about them, they are - a totally separate beast from the bare SCSI controllers and this driver - can not be retrofitted in any sane manner to support the hardware RAID - features on those cards - Doug Ledford). - - - People - ------------------------------ - Justin T Gibbs gibbs@plutotech.com - (BSD Driver Author) - Dan Eischen deischen@iworks.InterWorks.org - (Original Linux Driver Co-maintainer) - Dean Gehnert deang@teleport.com - (Original Linux FTP/patch maintainer) - Jess Johnson jester@frenzy.com - (AIC7xxx FAQ author) - Doug Ledford dledford@redhat.com - (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer) - - Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original - author of the driver. John has since retired from the project. Thanks - again for all his work! - - Mailing list - ------------------------------ - There is a mailing list available for users who want to track development - and converse with other users and developers. This list is for both - FreeBSD and Linux support of the AIC7xxx chipsets. - - To subscribe to the AIC7xxx mailing list send mail to the list server, - with "subscribe AIC7xxx" in the body (no Subject: required): - To: majordomo@FreeBSD.ORG - --- - subscribe AIC7xxx - - To unsubscribe from the list, send mail to the list server with: - To: majordomo@FreeBSD.ORG - --- - unsubscribe AIC7xxx - - Send regular messages and replies to: AIC7xxx@FreeBSD.ORG - - Boot Command line options - ------------------------------ - "aic7xxx=no_reset" - Eliminate the SCSI bus reset during startup. - Some SCSI devices need the initial reset that this option disables - in order to work. If you have problems at bootup, please make sure - you aren't using this option. - - "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at - bootup by scanning from the highest numbered PCI device to the - lowest numbered PCI device, others do just the opposite and scan - from lowest to highest numbered PCI device. There is no reliable - way to autodetect this ordering. So, we default to the most common - order, which is lowest to highest. Then, in case your motherboard - scans from highest to lowest, we have this option. If your BIOS - finds the drives on controller A before controller B but the linux - kernel finds your drives on controller B before A, then you should - use this option. - - "aic7xxx=extended" - Force the driver to detect extended drive translation - on your controller. This helps those people who have cards without - a SEEPROM make sure that linux and all other operating systems think - the same way about your hard drives. - - "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to - give the card more hardware SCB slots. This allows the driver to use - that SCB RAM. Without this option, the driver won't touch the SCB - RAM because it is known to cause problems on a few cards out there - (such as 3985 class cards). - - "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel - to use the correct IRQ type for your card. This only applies to EISA - based controllers. On these controllers, 0 is for Edge triggered - interrupts, and 1 is for Level triggered interrupts. If you aren't - sure or don't know which IRQ trigger type your EISA card uses, then - let the kernel autodetect the trigger type. - - "aic7xxx=verbose" - This option can be used in one of two ways. If you - simply specify aic7xxx=verbose, then the kernel will automatically - pick the default set of verbose messages for you to see. - Alternatively, you can specify the command as - "aic7xxx=verbose:0xXXXX" where the X entries are replaced with - hexadecimal digits. This option is a bit field type option. For - a full listing of the available options, search for the - #define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want - verbose messages, then it is recommended that you simply use the - aic7xxx=verbose variant of this command. - - "aic7xxx=pci_parity:x" - This option controls whether or not the driver - enables PCI parity error checking on the PCI bus. By default, this - checking is disabled. To enable the checks, simply specify pci_parity - with no value afterwords. To reverse the parity from even to odd, - supply any number other than 0 or 255. In short: - pci_parity - Even parity checking (even is the normal PCI parity) - pci_parity:x - Where x > 0, Odd parity checking - pci_parity:0 - No check (default) - NOTE: In order to get Even PCI parity checking, you must use the - version of the option that does not include the : and a number at - the end (unless you want to enter exactly 2^32 - 1 as the number). - - "aic7xxx=no_probe" - This option will disable the probing for any VLB - based 2842 controllers and any EISA based controllers. This is - needed on certain newer motherboards where the normal EISA I/O ranges - have been claimed by other PCI devices. Probing on those machines - will often result in the machine crashing or spontaneously rebooting - during startup. Examples of machines that need this are the - Dell PowerEdge 6300 machines. - - "aic7xxx=seltime:2" - This option controls how long the card waits - during a device selection sequence for the device to respond. - The original SCSI spec says that this "should be" 256ms. This - is generally not required with modern devices. However, some - very old SCSI I devices need the full 256ms. Most modern devices - can run fine with only 64ms. The default for this option is - 64ms. If you need to change this option, then use the following - table to set the proper value in the example above: - 0 - 256ms - 1 - 128ms - 2 - 64ms - 3 - 32ms - - "aic7xxx=panic_on_abort" - This option is for debugging and will cause - the driver to panic the linux kernel and freeze the system the first - time the drivers abort or reset routines are called. This is most - helpful when some problem causes infinite reset loops that scroll too - fast to see. By using this option, you can write down what the errors - actually are and send that information to me so it can be fixed. - - "aic7xxx=dump_card" - This option will print out the *entire* set of - configuration registers on the card during the init sequence. This - is a debugging aid used to see exactly what state the card is in - when we finally finish our initialization routines. If you don't - have documentation on the chipsets, this will do you absolutely - no good unless you are simply trying to write all the information - down in order to send it to me. - - "aic7xxx=dump_sequencer" - This is the same as the above options except - that instead of dumping the register contents on the card, this - option dumps the contents of the sequencer program RAM. This gives - the ability to verify that the instructions downloaded to the - card's sequencer are indeed what they are suppossed to be. Again, - unless you have documentation to tell you how to interpret these - numbers, then it is totally useless. - - "aic7xxx=override_term:0xffffffff" - This option is used to force the - termination on your SCSI controllers to a particular setting. This - is a bit mask variable that applies for up to 8 aic7xxx SCSI channels. - Each channel gets 4 bits, divided as follows: - bit 3 2 1 0 - | | | Enable/Disable Single Ended Low Byte Termination - | | En/Disable Single Ended High Byte Termination - | En/Disable Low Byte LVD Termination - En/Disable High Byte LVD Termination - - The upper 2 bits that deal with LVD termination only apply to Ultra2 - controllers. Futhermore, due to the current Ultra2 controller - designs, these bits are tied together such that setting either bit - enables both low and high byte LVD termination. It is not possible - to only set high or low byte LVD termination in this manner. This is - an artifact of the BIOS definition on Ultra2 controllers. For other - controllers, the only important bits are the two lowest bits. Setting - the higher bits on non-Ultra2 controllers has no effect. A few - examples of how to use this option: - - Enable low and high byte termination on a non-ultra2 controller that - is the first aic7xxx controller (the correct bits are 0011), - aic7xxx=override_term:0x3 - - Enable all termination on the third aic7xxx controller, high byte - termination on the second aic7xxx controller, and low and high byte - SE termination on the first aic7xxx controller - (bits are 1111 0010 0011), - aic7xxx=override_term:0xf23 - - No attempt has been made to make this option non-cryptic. It really - shouldn't be used except in dire circumstances, and if that happens, - I'm probably going to be telling you what to set this to anyway :) - - "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV - bit in the DEVCONFIG PCI register. Currently, this is one of the - very few registers that we have absolutely *no* way of detecting - what the variable should be. It depends entirely on how the chipset - and external terminators were coupled by the card/motherboard maker. - Further, a chip reset (at power up) always sets this bit to 0. If - there is no BIOS to run on the chipset/card (such as with a 2910C - or a motherboard controller with the BIOS totally disabled) then - the variable may not get set properly. Of course, if the proper - setting was 0, then that's what it would be after the reset, but if - the proper setting is actually 1.....you get the picture. Now, since - we can't detect this at all, I've added this option to force the - setting. If you have a BIOS on your controller then you should never - need to use this option. However, if you are having lots of SCSI - reset problems and can't seem to get them knocked out, this may help. - - Here's a test to know for certain if you need this option. Make - a boot floppy that you can use to boot your computer up and that - will detect the aic7xxx controller. Next, power down your computer. - While it's down, unplug all SCSI cables from your Adaptec SCSI - controller. Boot the system back up to the Adaptec EZ-SCSI BIOS - and then make sure that termination is enabled on your adapter (if - you have an Adaptec BIOS of course). Next, boot up the floppy you - made and wait for it to detect the aic7xxx controller. If the kernel - finds the controller fine, says scsi : x hosts and then tries to - detect your devices like normal, up to the point where it fails to - mount your root file system and panics, then you're fine. If, on - the other hand, the system goes into an infinite reset loop, then - you need to use this option and/or the previous option to force the - proper termination settings on your controller. If this happens, - then you next need to figure out what your settings should be. - - To find the correct settings, power your machine back down, connect - back up the SCSI cables, and boot back into your machine like normal. - However, boot with the aic7xxx=verbose:0x39 option. Record the - initial DEVCONFIG values for each of your aic7xxx controllers as - they are listed, and also record what the machine is detecting as - the proper termination on your controllers. NOTE: the order in - which the initial DEVCONFIG values are printed out is not gauranteed - to be the same order as the SCSI controllers are registered. The - above option and this option both work on the order of the SCSI - controllers as they are registered, so make sure you match the right - DEVCONFIG values with the right controllers if you have more than - one aic7xxx controller. - - Once you have the detected termination settings and the initial - DEVCONFIG values for each controller, then figure out what the - termination on each of the controllers *should* be. Hopefully, that - part is correct, but it could possibly be wrong if there is - bogus cable detection logic on your controller or something similar. - If all the controllers have the correct termination settings, then - don't set the aic7xxx=override_term variable at all, leave it alone. - Next, on any controllers that go into an infinite reset loop when - you unplug all the SCSI cables, get the starting DEVCONFIG value. - If the initial DEVCONFIG value is divisible by 2, then the correct - setting for that controller is 0. If it's an odd number, then - the correct setting for that controller is 1. For any other - controllers that didn't have an infinite reset problem, then reverse - the above options. If DEVCONFIG was even, then the correct setting - is 1, if not then the correct setting is 0. - - Now that you know what the correct setting was for each controller, - we need to encode that into the aic7xxx=stpwlev:0x... variable. - This variable is a bit field encoded variable. Bit 0 is for the first - aic7xxx controller, bit 1 for the next, etc. Put all these bits - together and you get a number. For example, if the third aic7xxx - needed a 1, but the second and first both needed a 0, then the bits - would be 100 in binary. This then translates to 0x04. You would - therefore set aic7xxx=stpwlev:0x04. This is fairly standard binary - to hexadecimal conversions here. If you aren't up to speed on the - binary->hex conversion then send an email to the aic7xxx mailing - list and someone can help you out. - - "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable - or enable Tagged Command Queueing (TCQ) on specific devices. As of - driver version 5.1.11, TCQ is now either on or off by default - according to the setting you choose during the make config process. - In order to en/disable TCQ for certian devices at boot time, a user - may use this boot param. The driver will then parse this message out - and en/disable the specific device entries that are present based upon - the value given. The param line is parsed in the following manner: - - { - first instance indicates the start of this parameter values - second instance is the start of entries for a particular - device entry - } - end the entries for a particular host adapter, or end the entire - set of parameter entries - , - move to next entry. Inside of a set of device entries, this - moves us to the next device on the list. Outside of device - entries, this moves us to the next host adapter - . - Same effect as , but is safe to use with insmod. - x - the number to enter into the array at this position. - 0 = Enable tagged queueing on this device and use the default - queue depth - 1-254 = Enable tagged queueing on this device and use this - number as the queue depth - 255 = Disable tagged queueing on this device. - Note: anything above 32 for an actual queue depth is wasteful - and not recommended. - - A few examples of how this can be used: - - tag_info:{{8,12,,0,,255,4}} - This line will only effect the first aic7xxx card registered. It - will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2 - at the default, set id 3 to tagged queueing enabled and use the - default queue depth, id 4 default, id 5 disabled, and id 6 to 4. - Any not specified entries stay at the default value, repeated - commas with no value specified will simply increment to the next id - without changing anything for the missing values. - - tag_info:{,,,{,,,255}} - First, second, and third adapters at default values. Fourth - adapter, id 3 is disabled. Notice that leading commas simply - increment what the first number effects, and there are no need - for trailing commas. When you close out an adapter, or the - entire entry, anything not explicitly set stays at the default - value. - - A final note on this option. The scanner I used for this isn't - perfect or highly robust. If you mess the line up, the worst that - should happen is that the line will get ignored. If you don't - close out the entire entry with the final bracket, then any other - aic7xxx options after this will get ignored. So, in general, be - sure of what you are entering, and after you have it right, just - add it to the lilo.conf file so there won't be any mistakes. As - a means of checking this parser, the entire tag_info array for - each card is now printed out in the /proc/scsi/aic7xxx/x file. You - can use that to verify that your options were parsed correctly. - - Boot command line options may be combined to form the proper set of options - a user might need. For example, the following is valid: - - aic7xxx=verbose,extended,irq_trigger:1 - - The only requirement is that individual options be separated by a comma or - a period on the command line. - - Module Loading command options - ------------------------------ - When loading the aic7xxx driver as a module, the exact same options are - available to the user. However, the syntax to specify the options changes - slightly. For insmod, you need to wrap the aic7xxx= argument in quotes - and replace all ',' with '.'. So, for example, a valid insmod line - would be: - - insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended' - - This line should result in the *exact* same behaviour as if you typed - it in at the lilo prompt and the driver was compiled into the kernel - instead of being a module. The reason for the single quote is so that - the shell won't try to interpret anything in the line, such as {. - Insmod assumes any options starting with a letter instead of a number - is a character string (which is what we want) and by switching all of - the commas to periods, insmod won't interpret this as more than one - string and write junk into our binary image. I consider it a bug in - the insmod program that even if you wrap your string in quotes (quotes - that pass the shell mind you and that insmod sees) it still treates - a comma inside of those quotes as starting a new variable, resulting - in memory scribbles if you don't switch the commas to periods. - - - Kernel Compile options - ------------------------------ - The various kernel compile time options for this driver are now fairly - well documented in the file Documentation/Configure.help. In order to - see this documentation, you need to use one of the advanced configuration - programs (menuconfig and xconfig). If you are using the "make menuconfig" - method of configuring your kernel, then you would simply highlight the - option in question and hit the ? key. If you are using the "make xconfig" - method of configuring your kernel, then simply click on the help button - next to the option you have questions about. The help information from - the Configure.help file will then get automatically displayed. - - /proc support - ------------------------------ - The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/ - directory. That directory contains a file for each SCSI controller in - the system. Each file presents the current configuration and transfer - statistics (enabled with #define in aic7xxx.c) for each controller. - - Thanks to Michael Neuffer for his upper-level SCSI help, and - Matthew Jacob for statistics support. - - Debugging the driver - ------------------------------ - Should you have problems with this driver, and would like some help in - getting them solved, there are a couple debugging items built into - the driver to facilitate getting the needed information from the system. - In general, I need a complete description of the problem, with as many - logs as possible concerning what happens. To help with this, there is - a command option aic7xxx=panic_on_abort. This option, when set, forces - the driver to panic the kernel on the first SCSI abort issued by the - mid level SCSI code. If your system is going to reset loops and you - can't read the screen, then this is what you need. Not only will it - stop the system, but it also prints out a large amount of state - information in the process. Second, if you specify the option - "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much - information as it runs that you won't be able to see anything. - However, this can actually be very usefull if your machine simply - locks up when trying to boot, since it will pin-point what was last - happening (in regards to the aic7xxx driver) immediately prior to - the lockup. This is really only usefull if your machine simply can - not boot up successfully. If you can get your machine to run, then - this will produce far too much information. - - FTP sites - ------------------------------ - ftp://ftp.redhat.com/pub/aic/ - - Out of date. I used to keep stuff here, but too many people - complained about having a hard time getting into Red Hat's ftp - server. So use the web site below instead. - ftp://ftp.pcnet.com/users/eischen/Linux/ - - Dan Eischen's driver distribution area - ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/ - - European Linux mirror of Teleport site - - Web sites - ------------------------------ - http://people.redhat.com/dledford/ - - My web site, also the primary aic7xxx site with several related - pages. - -Dean W. Gehnert -deang@teleport.com - -$Revision: 3.0 $ - -Modified by Doug Ledford 1998-2000 - diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.4.2/linux/drivers/scsi/aha152x.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/scsi/aha152x.c Tue Mar 6 19:44:37 2001 @@ -2755,7 +2755,7 @@ if(TESTLO(DMASTAT, DFIFOEMP)) { int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT(); - DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transfered)\n", + DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n", CMDINFO(CURRENT_SC), data_count, DATA_LEN-CURRENT_SC->resid, diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.4.2/linux/drivers/scsi/aha1542.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/aha1542.c Tue Mar 6 19:44:37 2001 @@ -103,16 +103,17 @@ /* Boards 3,4 slots are reserved for ISAPnP/MCA scans */ -static unsigned int bases[MAXBOARDS] = {0x330, 0x334, 0, 0}; +static unsigned int bases[MAXBOARDS] __initdata = {0x330, 0x334, 0, 0}; -/* set by aha1542_setup according to the command line */ +/* set by aha1542_setup according to the command line; they also may + be marked __initdata, but require zero initializers then */ static int setup_called[MAXBOARDS]; static int setup_buson[MAXBOARDS]; static int setup_busoff[MAXBOARDS]; -static int setup_dmaspeed[MAXBOARDS] = { -1, -1, -1, -1 }; +static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 }; -static char *setup_str[MAXBOARDS]; +static char *setup_str[MAXBOARDS] __initdata; /* * LILO/Module params: aha1542=[,,[,]] @@ -132,12 +133,12 @@ */ #if defined(MODULE) -int isapnp=0; +int isapnp = 0; int aha1542[] = {0x330, 11, 4, -1}; MODULE_PARM(aha1542, "1-4i"); MODULE_PARM(isapnp, "i"); -static struct isapnp_device_id id_table[] __devinitdata = { +static struct isapnp_device_id id_table[] __initdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1542), @@ -149,7 +150,7 @@ MODULE_DEVICE_TABLE(isapnp, id_table); #else -int isapnp=1; +static int isapnp = 1; #endif #define BIOS_TRANSLATION_1632 0 /* Used by some old 1542A boards */ @@ -348,7 +349,7 @@ return scsierr | (hosterr << 16); } -static int aha1542_test_port(int bse, struct Scsi_Host *shpnt) +static int __init aha1542_test_port(int bse, struct Scsi_Host *shpnt) { unchar inquiry_cmd[] = {CMD_INQUIRY}; unchar inquiry_result[4]; @@ -595,7 +596,7 @@ }; } -int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { unchar ahacmd = CMD_START_SCSI; unchar direction; @@ -777,7 +778,7 @@ SCpnt->SCp.Status++; } -int aha1542_command(Scsi_Cmnd * SCpnt) +static int aha1542_command(Scsi_Cmnd * SCpnt) { DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n")); @@ -816,7 +817,7 @@ aha1542_intr_reset(bse); } -static int aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id) +static int __init aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id) { unchar inquiry_cmd[] = {CMD_RETCONF}; unchar inquiry_result[3]; @@ -920,7 +921,7 @@ } /* Query the board to find out if it is a 1542 or a 1740, or whatever. */ -static int aha1542_query(int base_io, int *transl) +static int __init aha1542_query(int base_io, int *transl) { unchar inquiry_cmd[] = {CMD_INQUIRY}; unchar inquiry_result[4]; @@ -1034,7 +1035,7 @@ #endif /* return non-zero on detection */ -int aha1542_detect(Scsi_Host_Template * tpnt) +static int __init aha1542_detect(Scsi_Host_Template * tpnt) { unsigned char dma_chan; unsigned char irq_level; @@ -1052,7 +1053,7 @@ #ifdef MODULE bases[0] = aha1542[0]; - setup_buson[0]=aha1542[1]; + setup_buson[0] = aha1542[1]; setup_busoff[0] = aha1542[2]; { int atbt = -1; @@ -1344,7 +1345,7 @@ return 0; } -int aha1542_abort(Scsi_Cmnd * SCpnt) +static int aha1542_abort(Scsi_Cmnd * SCpnt) { /* @@ -1362,7 +1363,7 @@ * This is a device reset. This is handled by sending a special command * to the device. */ -int aha1542_dev_reset(Scsi_Cmnd * SCpnt) +static int aha1542_dev_reset(Scsi_Cmnd * SCpnt) { unsigned long flags; struct mailbox *mb; @@ -1456,7 +1457,7 @@ #endif /* ERIC_neverdef */ } -int aha1542_bus_reset(Scsi_Cmnd * SCpnt) +static int aha1542_bus_reset(Scsi_Cmnd * SCpnt) { int i; @@ -1520,7 +1521,7 @@ return FAILED; } -int aha1542_host_reset(Scsi_Cmnd * SCpnt) +static int aha1542_host_reset(Scsi_Cmnd * SCpnt) { int i; @@ -1593,7 +1594,7 @@ * These are the old error handling routines. They are only temporarily * here while we play with the new error handling code. */ -int aha1542_old_abort(Scsi_Cmnd * SCpnt) +static int aha1542_old_abort(Scsi_Cmnd * SCpnt) { #if 0 unchar ahacmd = CMD_START_SCSI; @@ -1666,7 +1667,7 @@ For a first go, we assume that the 1542 notifies us with all of the pending commands (it does implement soft reset, after all). */ -int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +static int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) { unchar ahacmd = CMD_START_SCSI; int i; @@ -1779,7 +1780,7 @@ #include "sd.h" -int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip) +static int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip) { int translation_algorithm; int size = disk->capacity; diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aha1542.h linux/drivers/scsi/aha1542.h --- v2.4.2/linux/drivers/scsi/aha1542.h Mon Dec 11 13:19:05 2000 +++ linux/drivers/scsi/aha1542.h Tue Mar 6 19:44:37 2001 @@ -130,16 +130,16 @@ /* REQUEST SENSE */ }; -int aha1542_detect(Scsi_Host_Template *); -int aha1542_command(Scsi_Cmnd *); -int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -int aha1542_abort(Scsi_Cmnd * SCpnt); -int aha1542_bus_reset(Scsi_Cmnd * SCpnt); -int aha1542_dev_reset(Scsi_Cmnd * SCpnt); -int aha1542_host_reset(Scsi_Cmnd * SCpnt); -extern int aha1542_old_abort(Scsi_Cmnd * SCpnt); -int aha1542_old_reset(Scsi_Cmnd *, unsigned int); -int aha1542_biosparam(Disk *, kdev_t, int*); +static int aha1542_detect(Scsi_Host_Template *); +static int aha1542_command(Scsi_Cmnd *); +static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int aha1542_abort(Scsi_Cmnd * SCpnt); +static int aha1542_bus_reset(Scsi_Cmnd * SCpnt); +static int aha1542_dev_reset(Scsi_Cmnd * SCpnt); +static int aha1542_host_reset(Scsi_Cmnd * SCpnt); +static int aha1542_old_abort(Scsi_Cmnd * SCpnt); +static int aha1542_old_reset(Scsi_Cmnd *, unsigned int); +static int aha1542_biosparam(Disk *, kdev_t, int*); #define AHA1542_MAILBOXES 8 #define AHA1542_SCATTER 16 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c --- v2.4.2/linux/drivers/scsi/aha1740.c Sat Nov 11 19:01:11 2000 +++ linux/drivers/scsi/aha1740.c Tue Mar 6 19:44:37 2001 @@ -319,11 +319,16 @@ if(*cmd == REQUEST_SENSE) { +#if 0 + /* scsi_request_sense() provides a buffer of size 256, + so there is no reason to expect equality */ + if (bufflen != sizeof(SCpnt->sense_buffer)) { printk("Wrong buffer length supplied for request sense (%d)\n", bufflen); } +#endif SCpnt->result = 0; done(SCpnt); return 0; @@ -521,10 +526,10 @@ * check/allocate region code, but this may change at some point, * so we go through the motions. */ - if (check_region(slotbase, SLOTSIZE)) /* See if in use */ + if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */ continue; if (!aha1740_test_port(slotbase)) - continue; + goto err_release; aha1740_getconfig(slotbase,&irq_level,&translation); if ((inb(G2STAT(slotbase)) & (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) @@ -538,15 +543,12 @@ DEB(printk("aha1740_detect: enable interrupt channel %d\n",irq_level)); if (request_irq(irq_level,aha1740_intr_handle,0,"aha1740",NULL)) { printk("Unable to allocate IRQ for adaptec controller.\n"); - continue; + goto err_release; } shpnt = scsi_register(tpnt, sizeof(struct aha1740_hostdata)); if(shpnt == NULL) - { - free_irq(irq_level, NULL); - continue; - } - request_region(slotbase, SLOTSIZE, "aha1740"); + goto err_free_irq; + shpnt->base = 0; shpnt->io_port = slotbase; shpnt->n_io_port = SLOTSIZE; @@ -557,6 +559,12 @@ host->translation = translation; aha_host[irq_level - 9] = shpnt; count++; + continue; + + err_free_irq: + free_irq(irq_level, aha1740_intr_handle); + err_release: + release_region(slotbase, SLOTSIZE); } return count; } diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/Config.in linux/drivers/scsi/aic7xxx/Config.in --- v2.4.2/linux/drivers/scsi/aic7xxx/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/Config.in Sun Mar 4 14:30:18 2001 @@ -0,0 +1,7 @@ +if [ "$CONFIG_SCSI_AIC7XXX_OLD" != "y" ]; then + dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI + if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then + int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 253 + int ' Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY 5000 + fi +fi diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/Makefile linux/drivers/scsi/aic7xxx/Makefile --- v2.4.2/linux/drivers/scsi/aic7xxx/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/Makefile Sun Mar 4 14:30:18 2001 @@ -0,0 +1,32 @@ +# +# drivers/scsi/aic7xxx/Makefile +# +# Makefile for the Linux aic7xxx SCSI driver. +# + +O_TARGET = aic7xxx_drv.o + +list-multi := aic7xxx_mod.o + +obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx_mod.o + +# Platform Specific Files +AIC7XXX_OBJS = aic7xxx_linux.o aic7xxx_linux_pci.o +AIC7XXX_OBJS += aic7xxx_proc.o aic7770_linux.o +# Core Files +AIC7XXX_OBJS += aic7xxx.o aic7xxx_pci.o aic7xxx_93cx6.o aic7770.o + +# Override our module desitnation +MOD_DESTDIR = $(shell cd .. && $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh) +MOD_TARGET = aic7xxx.o + +include $(TOPDIR)/Rules.make + +aic7xxx_mod.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS) + +aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm + aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq + +aicasm/aicasm: aicasm/*.[chyl] + $(MAKE) -C aicasm diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7770.c linux/drivers/scsi/aic7xxx/aic7770.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7770.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7770.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,346 @@ +/* + * Product specific probe and attach routines for: + * 27/284X and aic7770 motherboard SCSI controllers + * + * Copyright (c) 1994-1998, 2000, 2001 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aic7770.c#6 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $ + */ + +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" +#include "aic7xxx_93cx6.h" + +#define ID_AIC7770 0x04907770 +#define ID_AHA_274x 0x04907771 +#define ID_AHA_284xB 0x04907756 /* BIOS enabled */ +#define ID_AHA_284x 0x04907757 /* BIOS disabled*/ + +static void aha2840_load_seeprom(struct ahc_softc *ahc); +static ahc_device_setup_t ahc_aic7770_VL_setup; +static ahc_device_setup_t ahc_aic7770_EISA_setup;; +static ahc_device_setup_t ahc_aic7770_setup; + + +struct aic7770_identity aic7770_ident_table [] = +{ + { + ID_AHA_274x, + 0xFFFFFFFF, + "Adaptec 274X SCSI adapter", + ahc_aic7770_EISA_setup + }, + { + ID_AHA_284xB, + 0xFFFFFFFE, + "Adaptec 284X SCSI adapter", + ahc_aic7770_VL_setup + }, + /* Generic chip probes for devices we don't know 'exactly' */ + { + ID_AIC7770, + 0xFFFFFFFF, + "Adaptec aic7770 SCSI adapter", + ahc_aic7770_EISA_setup + } +}; +const int ahc_num_aic7770_devs = NUM_ELEMENTS(aic7770_ident_table); + +struct aic7770_identity * +aic7770_find_device(uint32_t id) +{ + struct aic7770_identity *entry; + int i; + + for (i = 0; i < ahc_num_aic7770_devs; i++) { + entry = &aic7770_ident_table[i]; + if (entry->full_id == (id & entry->id_mask)) + return (entry); + } + return (NULL); +} + +int +aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry) +{ + struct ahc_probe_config probe_config; + int error; + u_int hostconf; + u_int irq; + u_int intdef; + u_int hcntrl; + int shared; + + ahc_init_probe_config(&probe_config); + error = entry->setup(ahc->dev_softc, &probe_config); + if (error != 0) + return (error); + + error = aic7770_map_registers(ahc); + if (error != 0) + return (error); + + /* Pause the card preseving the IRQ type */ + hcntrl = ahc_inb(ahc, HCNTRL) & IRQMS; + ahc_outb(ahc, HCNTRL, hcntrl | PAUSE); + while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0) + ; + + /* Make sure we have a valid interrupt vector */ + intdef = ahc_inb(ahc, INTDEF); + shared = (intdef & EDGE_TRIG) ? 0 : 1; + irq = intdef & VECTOR; + switch (irq) { + case 9: + case 10: + case 11: + case 12: + case 14: + case 15: + break; + default: + printf("aic7770_config: illegal irq setting %d\n", intdef); + return (ENXIO); + } + + probe_config.description = entry->name; + error = ahc_softc_init(ahc, &probe_config); + + error = aic7770_map_int(ahc, irq, shared); + if (error != 0) + return (error); + + error = ahc_reset(ahc); + if (error != 0) + return (error); + + switch (probe_config.chip & (AHC_EISA|AHC_VL)) { + case AHC_EISA: + { + u_int biosctrl; + u_int scsiconf; + u_int scsiconf1; + + biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); + scsiconf = ahc_inb(ahc, SCSICONF); + scsiconf1 = ahc_inb(ahc, SCSICONF + 1); + + /* Get the primary channel information */ + if ((biosctrl & CHANNEL_B_PRIMARY) != 0) + ahc->flags |= AHC_CHANNEL_B_PRIMARY; + + if ((biosctrl & BIOSMODE) == BIOSDISABLED) { + ahc->flags |= AHC_USEDEFAULTS; + } else { + if ((ahc->features & AHC_WIDE) != 0) { + ahc->our_id = scsiconf1 & HWSCSIID; + if (scsiconf & TERM_ENB) + ahc->flags |= AHC_TERM_ENB_A; + } else { + ahc->our_id = scsiconf & HSCSIID; + ahc->our_id_b = scsiconf1 & HSCSIID; + if (scsiconf & TERM_ENB) + ahc->flags |= AHC_TERM_ENB_A; + if (scsiconf1 & TERM_ENB) + ahc->flags |= AHC_TERM_ENB_B; + } + } + /* + * We have no way to tell, so assume extended + * translation is enabled. + */ + ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; + break; + } + case AHC_VL: + { + aha2840_load_seeprom(ahc); + break; + } + default: + break; + } + + /* + * Ensure autoflush is enabled + */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS); + + /* Setup the FIFO threshold and the bus off time */ + hostconf = ahc_inb(ahc, HOSTCONF); + ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); + ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); + + /* + * Generic aic7xxx initialization. + */ + error = ahc_init(ahc); + if (error != 0) + return (error); + + /* + * Link this softc in with all other ahc instances. + */ + ahc_softc_insert(ahc); + + /* + * Enable the board's BUS drivers + */ + ahc_outb(ahc, BCTL, ENABLE); + + return (0); +} + +/* + * Read the 284x SEEPROM. + */ +static void +aha2840_load_seeprom(struct ahc_softc *ahc) +{ + struct seeprom_descriptor sd; + struct seeprom_config sc; + uint16_t checksum = 0; + uint8_t scsi_conf; + int have_seeprom; + + sd.sd_ahc = ahc; + sd.sd_control_offset = SEECTL_2840; + sd.sd_status_offset = STATUS_2840; + sd.sd_dataout_offset = STATUS_2840; + sd.sd_chip = C46; + sd.sd_MS = 0; + sd.sd_RDY = EEPROM_TF; + sd.sd_CS = CS_2840; + sd.sd_CK = CK_2840; + sd.sd_DO = DO_2840; + sd.sd_DI = DI_2840; + + if (bootverbose) + printf("%s: Reading SEEPROM...", ahc_name(ahc)); + have_seeprom = read_seeprom(&sd, + (uint16_t *)&sc, + /*start_addr*/0, + sizeof(sc)/2); + + if (have_seeprom) { + /* Check checksum */ + int i; + int maxaddr = (sizeof(sc)/2) - 1; + uint16_t *scarray = (uint16_t *)≻ + + for (i = 0; i < maxaddr; i++) + checksum = checksum + scarray[i]; + if (checksum != sc.checksum) { + if(bootverbose) + printf ("checksum error\n"); + have_seeprom = 0; + } else if (bootverbose) { + printf("done.\n"); + } + } + + if (!have_seeprom) { + if (bootverbose) + printf("%s: No SEEPROM available\n", ahc_name(ahc)); + ahc->flags |= AHC_USEDEFAULTS; + } else { + /* + * Put the data we've collected down into SRAM + * where ahc_init will find it. + */ + int i; + int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8; + uint16_t discenable; + + discenable = 0; + for (i = 0; i < max_targ; i++){ + uint8_t target_settings; + target_settings = (sc.device_flags[i] & CFXFER) << 4; + if (sc.device_flags[i] & CFSYNCH) + target_settings |= SOFS; + if (sc.device_flags[i] & CFWIDEB) + target_settings |= WIDEXFER; + if (sc.device_flags[i] & CFDISC) + discenable |= (0x01 << i); + ahc_outb(ahc, TARG_SCSIRATE + i, target_settings); + } + ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); + ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); + + ahc->our_id = sc.brtime_id & CFSCSIID; + + scsi_conf = (ahc->our_id & 0x7); + if (sc.adapter_control & CFSPARITY) + scsi_conf |= ENSPCHK; + if (sc.adapter_control & CFRESETB) + scsi_conf |= RESET_SCSI; + + if (sc.bios_control & CF284XEXTEND) + ahc->flags |= AHC_EXTENDED_TRANS_A; + /* Set SCSICONF info */ + ahc_outb(ahc, SCSICONF, scsi_conf); + + if (sc.adapter_control & CF284XSTERM) + ahc->flags |= AHC_TERM_ENB_A; + } +} + +static int +ahc_aic7770_VL_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7770_setup(dev, probe_config); + probe_config->chip |= AHC_VL; + return (error); +} + +static int +ahc_aic7770_EISA_setup(ahc_dev_softc_t dev, + struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7770_setup(dev, probe_config); + probe_config->chip |= AHC_EISA; + return (error); +} + +static int +ahc_aic7770_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config) +{ + probe_config->channel = 'A'; + probe_config->channel_b = 'B'; + probe_config->chip = AHC_AIC7770; + probe_config->features = AHC_AIC7770_FE; + probe_config->bugs |= AHC_TMODE_WIDEODD_BUG; + probe_config->flags |= AHC_PAGESCBS; + return (0); +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7770_linux.c linux/drivers/scsi/aic7xxx/aic7770_linux.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7770_linux.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7770_linux.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,146 @@ +/* + * Linux driver attachment glue for aic7770 based controllers. + * + * Copyright (c) 2000 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#5 $ + */ + +#include "aic7xxx_osm.h" + +#define MINSLOT 1 +#define NUMSLOTS 16 +#define IDOFFSET 0x80 + +int +aic7770_linux_probe(Scsi_Host_Template *template) +{ +#if defined(__i386__) || defined(__alpha__) + struct aic7770_identity *entry; + struct ahc_softc *ahc; + int i, slot; + int eisaBase; + int found; + + if (aic7xxx_no_probe) + return (0); + + eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; + found = 0; + for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { + uint32_t eisa_id; + size_t id_size; + + if (check_region(eisaBase, AHC_EISA_IOSIZE) != 0) + continue; + + eisa_id = 0; + id_size = sizeof(eisa_id); + for (i = 0; i < 4; i++) { + /* VLcards require priming*/ + outb(0x80 + i, eisaBase + IDOFFSET); + eisa_id |= inb(eisaBase + IDOFFSET + i) + << ((id_size-i-1) * 8); + } + if (eisa_id & 0x80000000) + continue; /* no EISA card in slot */ + + entry = aic7770_find_device(eisa_id); + if (entry != NULL) { + char buf[80]; + char *name; + int error; + + /* + * Allocate a softc for this card and + * set it up for attachment by our + * common detect routine. + */ + sprintf(buf, "ahc_eisa:%d", slot); + name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (name == NULL) + break; + strcpy(name, buf); + ahc = ahc_alloc(template, name); + if (ahc == NULL) { + /* + * If we can't allocate this one, + * chances are we won't be able to + * allocate future card structures. + */ + break; + } + ahc->tag = BUS_SPACE_PIO; + ahc->bsh.ioport = eisaBase; + error = aic7770_config(ahc, entry); + if (error != 0) { + ahc_free(ahc); + continue; + } + found++; + } + } + return (found); +#else + return (0); +#endif +} + +int +aic7770_map_registers(struct ahc_softc *ahc) +{ + /* + * Lock out other contenders for our i/o space. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + request_region(ahc->bsh.ioport, AHC_EISA_IOSIZE, "aic7xxx"); +#else + if (request_region(ahc->bsh.ioport, AHC_EISA_IOSIZE, "aic7xxx") == 0) + return (ENOMEM); +#endif + + return (0); +} + +int +aic7770_map_int(struct ahc_softc *ahc, u_int irq, int shared) +{ + int error; + + if (shared) + shared = SA_SHIRQ; + + ahc->platform_data->irq = irq; + error = request_irq(ahc->platform_data->irq, aic7xxx_isr, + SA_INTERRUPT|shared, "aic7xxx", ahc); + if (error < 0) + error = request_irq(ahc->platform_data->irq, aic7xxx_isr, + shared, "aic7xxx", ahc); + + return (-error); +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,6673 @@ +/* + * Core routines and tables shareable across OS platforms. + * + * Copyright (c) 1994-2001 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aic7xxx.c#32 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $ + */ + +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" +#include "aicasm/aicasm_insformat.h" + +/****************************** Softc Data ************************************/ +struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq); + +/***************************** Lookup Tables **********************************/ +char *ahc_chip_names[] = +{ + "NONE", + "aic7770", + "aic7850", + "aic7855", + "aic7859", + "aic7860", + "aic7870", + "aic7880", + "aic7895", + "aic7895C", + "aic7890/91", + "aic7896/97", + "aic7892", + "aic7899" +}; +const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names); + +struct hard_error_entry hard_error[] = { + { ILLHADDR, "Illegal Host Access" }, + { ILLSADDR, "Illegal Sequencer Address referrenced" }, + { ILLOPCODE, "Illegal Opcode in sequencer program" }, + { SQPARERR, "Sequencer Parity Error" }, + { DPARERR, "Data-path Parity Error" }, + { MPARERR, "Scratch or SCB Memory Parity Error" }, + { PCIERRSTAT, "PCI Error detected" }, + { CIOPARERR, "CIOBUS Parity Error" }, +}; +const u_int num_errors = NUM_ELEMENTS(hard_error); + +struct phase_table_entry phase_table[] = +{ + { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, + { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, + { P_DATAOUT_DT, MSG_NOOP, "in DT Data-out phase" }, + { P_DATAIN_DT, MSG_INITIATOR_DET_ERR, "in DT Data-in phase" }, + { P_COMMAND, MSG_NOOP, "in Command phase" }, + { P_MESGOUT, MSG_NOOP, "in Message-out phase" }, + { P_STATUS, MSG_INITIATOR_DET_ERR, "in Status phase" }, + { P_MESGIN, MSG_PARITY_ERROR, "in Message-in phase" }, + { P_BUSFREE, MSG_NOOP, "while idle" }, + { 0, MSG_NOOP, "in unknown phase" } +}; + +/* + * In most cases we only wish to itterate over real phases, so + * exclude the last element from the count. + */ +const u_int num_phases = NUM_ELEMENTS(phase_table) - 1; + +/* + * Valid SCSIRATE values. (p. 3-17) + * Provides a mapping of tranfer periods in ns to the proper value to + * stick in the scsixfer reg. + */ +struct ahc_syncrate ahc_syncrates[] = +{ + /* ultra2 fast/ultra period rate */ + { 0x42, 0x000, 9, "80.0" }, + { 0x03, 0x000, 10, "40.0" }, + { 0x04, 0x000, 11, "33.0" }, + { 0x05, 0x100, 12, "20.0" }, + { 0x06, 0x110, 15, "16.0" }, + { 0x07, 0x120, 18, "13.4" }, + { 0x08, 0x000, 25, "10.0" }, + { 0x19, 0x010, 31, "8.0" }, + { 0x1a, 0x020, 37, "6.67" }, + { 0x1b, 0x030, 43, "5.7" }, + { 0x1c, 0x040, 50, "5.0" }, + { 0x00, 0x050, 56, "4.4" }, + { 0x00, 0x060, 62, "4.0" }, + { 0x00, 0x070, 68, "3.6" }, + { 0x00, 0x000, 0, NULL } +}; + +/* Our Sequencer Program */ +#include "aic7xxx_seq.h" + +/**************************** Function Declarations ***************************/ +static struct tmode_tstate* + ahc_alloc_tstate(struct ahc_softc *ahc, + u_int scsi_id, char channel); +#ifdef AHC_TARGET_MODE +static void ahc_free_tstate(struct ahc_softc *ahc, + u_int scsi_id, char channel, int force); +#endif +static struct ahc_syncrate* + ahc_devlimited_syncrate(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *, + u_int *period, + u_int *ppr_options, + role_t role); +static void ahc_update_pending_syncrates(struct ahc_softc *ahc); +static void ahc_fetch_devinfo(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_scb_devinfo(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct scb *scb); +static void ahc_build_transfer_msg(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_construct_sdtr(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + u_int period, u_int offset); +static void ahc_construct_wdtr(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + u_int bus_width); +static void ahc_construct_ppr(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + u_int period, u_int offset, + u_int bus_width, u_int ppr_options); +static void ahc_clear_msg_state(struct ahc_softc *ahc); +static void ahc_handle_message_phase(struct ahc_softc *ahc); +typedef enum { + AHCMSG_1B, + AHCMSG_2B, + AHCMSG_EXT +} ahc_msgtype; +static int ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, + u_int msgval, int full); +static int ahc_parse_msg(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static int ahc_handle_msg_reject(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_handle_ign_wide_residue(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +static void ahc_handle_devreset(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + cam_status status, char *message, + int verbose_level); + +static bus_dmamap_callback_t ahc_dmamap_cb; +static void ahc_build_free_scb_list(struct ahc_softc *ahc); +static int ahc_init_scbdata(struct ahc_softc *ahc); +static void ahc_fini_scbdata(struct ahc_softc *ahc); +static void ahc_qinfifo_requeue(struct ahc_softc *ahc, + struct scb *prev_scb, + struct scb *scb); +static int ahc_qinfifo_count(struct ahc_softc *ahc); +static u_int ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, + u_int prev, u_int scbptr); +static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc); +static u_int ahc_rem_wscb(struct ahc_softc *ahc, + u_int scbpos, u_int prev); +static int ahc_abort_scbs(struct ahc_softc *ahc, int target, + char channel, int lun, u_int tag, + role_t role, uint32_t status); +static void ahc_reset_current_bus(struct ahc_softc *ahc); +static void ahc_calc_residual(struct scb *scb); +#ifdef AHC_DUMP_SEQ +static void ahc_dumpseq(struct ahc_softc *ahc); +#endif +static void ahc_loadseq(struct ahc_softc *ahc); +static int ahc_check_patch(struct ahc_softc *ahc, + struct patch **start_patch, + u_int start_instr, u_int *skip_addr); +static void ahc_download_instr(struct ahc_softc *ahc, + u_int instrptr, uint8_t *dconsts); +#ifdef AHC_TARGET_MODE +static void ahc_queue_lstate_event(struct ahc_softc *ahc, + struct tmode_lstate *lstate, + u_int initiator_id, + u_int event_type, + u_int event_arg); +static void ahc_update_scsiid(struct ahc_softc *ahc, + u_int targid_mask); +static int ahc_handle_target_cmd(struct ahc_softc *ahc, + struct target_cmd *cmd); +#endif +/************************* Sequencer Execution Control ************************/ +/* + * Restart the sequencer program from address zero + */ +void +restart_sequencer(struct ahc_softc *ahc) +{ + + pause_sequencer(ahc); + + ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ + ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ + ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); + + /* + * Ensure that the sequencer's idea of TQINPOS + * matches our own. The sequencer increments TQINPOS + * only after it sees a DMA complete and a reset could + * occur before the increment leaving the kernel to believe + * the command arrived but the sequencer to not. + */ + ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); + + /* Always allow reselection */ + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Ensure that no DMA operations are in progress */ + ahc_outb(ahc, CCSCBCNT, 0); + ahc_outb(ahc, CCSGCTL, 0); + ahc_outb(ahc, CCSCBCTL, 0); + } + /* + * If we were in the process of DMA'ing SCB data into + * an SCB, replace that SCB on the free list. This prevents + * an SCB leak. + */ + if ((ahc_inb(ahc, SEQ_FLAGS2) & SCB_DMA) != 0) { + ahc_add_curscb_to_free_list(ahc); + ahc_outb(ahc, SEQ_FLAGS2, + ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); + } + ahc_outb(ahc, MWI_RESIDUAL, 0); + ahc_outb(ahc, SEQCTL, FASTMODE); + ahc_outb(ahc, SEQADDR0, 0); + ahc_outb(ahc, SEQADDR1, 0); + unpause_sequencer(ahc); +} + +/************************* Input/Output Queues ********************************/ +void +ahc_run_qoutfifo(struct ahc_softc *ahc) +{ + struct scb *scb; + u_int scb_index; + + while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) { + + scb_index = ahc->qoutfifo[ahc->qoutfifonext]; + if ((ahc->qoutfifonext & 0x03) == 0x03) { + u_int modnext; + + /* + * Clear 32bits of QOUTFIFO at a time + * so that we don't clobber an incomming + * byte DMA to the array on architectures + * that only support 32bit load and store + * operations. + */ + modnext = ahc->qoutfifonext & ~0x3; + *((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL; + } + ahc->qoutfifonext++; + + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s: WARNING no command for scb %d " + "(cmdcmplt)\nQOUTPOS = %d\n", + ahc_name(ahc), scb_index, + ahc->qoutfifonext - 1); + continue; + } + + /* + * Save off the residual + * if there is one. + */ + if (ahc_check_residual(scb) != 0) + ahc_calc_residual(scb); + else + ahc_set_residual(scb, 0); + ahc_done(ahc, scb); + } +} + +void +ahc_run_untagged_queues(struct ahc_softc *ahc) +{ + int i; + + for (i = 0; i < 16; i++) + ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]); +} + +void +ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue) +{ + struct scb *scb; + + if (ahc->untagged_queue_lock != 0) + return; + + if ((scb = TAILQ_FIRST(queue)) != NULL + && (scb->flags & SCB_ACTIVE) == 0) { + scb->flags |= SCB_ACTIVE; + ahc_queue_scb(ahc, scb); + } +} + +/************************* Interrupt Handling *********************************/ +void +ahc_handle_brkadrint(struct ahc_softc *ahc) +{ + /* + * We upset the sequencer :-( + * Lookup the error message + */ + int i, error, num_errors; + + error = ahc_inb(ahc, ERROR); + num_errors = sizeof(hard_error)/sizeof(hard_error[0]); + for (i = 0; error != 1 && i < num_errors; i++) + error >>= 1; + printf("%s: brkadrint, %s at seqaddr = 0x%x\n", + ahc_name(ahc), hard_error[i].errmesg, + ahc_inb(ahc, SEQADDR0) | + (ahc_inb(ahc, SEQADDR1) << 8)); + + ahc_dump_card_state(ahc); + + /* Tell everyone that this HBA is no longer availible */ + ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, + CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, + CAM_NO_HBA); + + /* Disable all interrupt sources by resetting the controller */ + ahc_shutdown(ahc); +} + +void +ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) +{ + struct scb *scb; + struct ahc_devinfo devinfo; + + ahc_fetch_devinfo(ahc, &devinfo); + + /* + * Clear the upper byte that holds SEQINT status + * codes and clear the SEQINT bit. We will unpause + * the sequencer, if appropriate, after servicing + * the request. + */ + ahc_outb(ahc, CLRINT, CLRSEQINT); + switch (intstat & SEQINT_MASK) { + case BAD_STATUS: + { + u_int scb_index; + struct hardware_scb *hscb; + + /* + * Set the default return value to 0 (don't + * send sense). The sense code will change + * this if needed. + */ + ahc_outb(ahc, RETURN_1, 0); + + /* + * The sequencer will notify us when a command + * has an error that would be of interest to + * the kernel. This allows us to leave the sequencer + * running in the common case of command completes + * without error. The sequencer will already have + * dma'd the SCB back up to us, so we can reference + * the in kernel copy directly. + */ + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s:%c:%d: ahc_intr - referenced scb " + "not valid during seqint 0x%x scb(%d)\n", + ahc_name(ahc), devinfo.channel, + devinfo.target, intstat, scb_index); + ahc_dump_card_state(ahc); + panic("for safety"); + goto unpause; + } + + hscb = scb->hscb; + + /* Don't want to clobber the original sense code */ + if ((scb->flags & SCB_SENSE) != 0) { + /* + * Clear the SCB_SENSE Flag and have + * the sequencer do a normal command + * complete. + */ + scb->flags &= ~SCB_SENSE; + ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + break; + } + ahc_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); + /* Freeze the queue until the client sees the error. */ + ahc_freeze_devq(ahc, scb); + ahc_freeze_scb(scb); + ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status); + switch (hscb->shared_data.status.scsi_status) { + case SCSI_STATUS_OK: + printf("%s: Interrupted for staus of 0???\n", + ahc_name(ahc)); + break; + case SCSI_STATUS_CMD_TERMINATED: + case SCSI_STATUS_CHECK_COND: +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWSENSE) { + ahc_print_path(ahc, scb); + printf("SCB %d: requests Check Status\n", + scb->hscb->tag); + } +#endif + + if (ahc_perform_autosense(scb)) { + struct ahc_dma_seg *sg; + struct scsi_sense *sc; + struct ahc_initiator_tinfo *targ_info; + struct tmode_tstate *tstate; + struct ahc_transinfo *tinfo; + + targ_info = + ahc_fetch_transinfo(ahc, + devinfo.channel, + devinfo.our_scsiid, + devinfo.target, + &tstate); + tinfo = &targ_info->current; + sg = scb->sg_list; + sc = (struct scsi_sense *) + (&hscb->shared_data.cdb); + /* + * Save off the residual if there is one. + */ + if (ahc_check_residual(scb)) + ahc_calc_residual(scb); + else + ahc_set_residual(scb, 0); +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWSENSE) { + ahc_print_path(ahc, scb); + printf("Sending Sense\n"); + } +#endif + sg->addr = ahc_get_sense_bufaddr(ahc, scb); + sg->len = ahc_get_sense_bufsize(ahc, scb); + sg->len |= AHC_DMA_LAST_SEG; + + /* Fixup byte order */ + sg->addr = ahc_htole32(sg->addr); + sg->len = ahc_htole32(sg->len); + + sc->opcode = REQUEST_SENSE; + sc->byte2 = 0; + if (tinfo->protocol_version <= SCSI_REV_2 + && SCB_GET_LUN(scb) < 8) + sc->byte2 = SCB_GET_LUN(scb) << 5; + sc->unused[0] = 0; + sc->unused[1] = 0; + sc->length = sg->len; + sc->control = 0; + + /* + * XXX Still true??? + * Would be nice to preserve DISCENB here, + * but due to the way we manage busy targets, + * we can't. + */ + hscb->control = 0; + + /* + * This request sense could be because the + * the device lost power or in some other + * way has lost our transfer negotiations. + * Renegotiate if appropriate. Unit attention + * errors will be reported before any data + * phases occur. + */ + if (ahc_get_residual(scb) + == ahc_get_transfer_length(scb)) { + ahc_update_target_msg_request(ahc, + &devinfo, + targ_info, + /*force*/TRUE, + /*paused*/TRUE); + } + hscb->cdb_len = sizeof(*sc); + hscb->dataptr = sg->addr; + hscb->datacnt = sg->len; + hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; + hscb->sgptr = ahc_htole32(hscb->sgptr); + scb->sg_count = 1; + scb->flags |= SCB_SENSE; + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, RETURN_1, SEND_SENSE); +#ifdef __FreeBSD__ + /* + * Ensure we have enough time to actually + * retrieve the sense. + */ + untimeout(ahc_timeout, (caddr_t)scb, + scb->io_ctx->ccb_h.timeout_ch); + scb->io_ctx->ccb_h.timeout_ch = + timeout(ahc_timeout, (caddr_t)scb, 5 * hz); +#endif + } + break; + default: + break; + } + break; + } + case NO_MATCH: + { + /* Ensure we don't leave the selection hardware on */ + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); + + printf("%s:%c:%d: no active SCB for reconnecting " + "target - issuing BUS DEVICE RESET\n", + ahc_name(ahc), devinfo.channel, devinfo.target); + printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " + "ARG_1 == 0x%x ACCUM = 0x%x\n", + ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), + ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); + printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + "SINDEX == 0x%x\n", + ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), + ahc_index_busy_tcl(ahc, + BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), + ahc_inb(ahc, SAVED_LUN))), + ahc_inb(ahc, SINDEX)); + printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", + ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), + ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), + ahc_inb(ahc, SCB_CONTROL)); + printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", + ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); + printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0)); + printf("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL)); + ahc_dump_card_state(ahc); + ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; + ahc->msgout_len = 1; + ahc->msgout_index = 0; + ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO); + break; + } + case SEND_REJECT: + { + u_int rejbyte = ahc_inb(ahc, ACCUM); + printf("%s:%c:%d: Warning - unknown message received from " + "target (0x%x). Rejecting\n", + ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte); + break; + } + case NO_IDENT: + { + /* + * The reconnecting target either did not send an identify + * message, or did, but we didn't find an SCB to match and + * before it could respond to our ATN/abort, it hit a dataphase. + * The only safe thing to do is to blow it away with a bus + * reset. + */ + int found; + + printf("%s:%c:%d: Target did not send an IDENTIFY message. " + "LASTPHASE = 0x%x, SAVED_SCSIID == 0x%x\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_SCSIID)); + found = ahc_reset_channel(ahc, devinfo.channel, + /*initiate reset*/TRUE); + printf("%s: Issued Channel %c Bus Reset. " + "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel, + found); + return; + } + case IGN_WIDE_RES: + ahc_handle_ign_wide_residue(ahc, &devinfo); + break; + case BAD_PHASE: + { + u_int lastphase; + + lastphase = ahc_inb(ahc, LASTPHASE); + printf("%s:%c:%d: unknown scsi bus phase %x, " + "lastphase = 0x%x. Attempting to continue\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + lastphase, ahc_inb(ahc, SCSISIGI)); + break; + } + case MISSED_BUSFREE: + { + u_int lastphase; + + lastphase = ahc_inb(ahc, LASTPHASE); + printf("%s:%c:%d: Missed busfree. " + "Lastphase = 0x%x, Curphase = 0x%x\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + lastphase, ahc_inb(ahc, SCSISIGI)); + restart_sequencer(ahc); + return; + } + case HOST_MSG_LOOP: + { + /* + * The sequencer has encountered a message phase + * that requires host assistance for completion. + * While handling the message phase(s), we will be + * notified by the sequencer after each byte is + * transfered so we can track bus phase changes. + * + * If this is the first time we've seen a HOST_MSG_LOOP + * interrupt, initialize the state of the host message + * loop. + */ + if (ahc->msg_type == MSG_TYPE_NONE) { + u_int bus_phase; + + bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + if (bus_phase != P_MESGIN + && bus_phase != P_MESGOUT) { + printf("ahc_intr: HOST_MSG_LOOP bad " + "phase 0x%x\n", + bus_phase); + /* + * Probably transitioned to bus free before + * we got here. Just punt the message. + */ + ahc_clear_intstat(ahc); + restart_sequencer(ahc); + return; + } + + if (devinfo.role == ROLE_INITIATOR) { + struct scb *scb; + u_int scb_index; + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + + if (scb == NULL) + panic("HOST_MSG_LOOP with " + "invalid SCB %x\n", scb_index); + + if (bus_phase == P_MESGOUT) + ahc_setup_initiator_msgout(ahc, + &devinfo, + scb); + else { + ahc->msg_type = + MSG_TYPE_INITIATOR_MSGIN; + ahc->msgin_index = 0; + } + } else { + if (bus_phase == P_MESGOUT) { + ahc->msg_type = + MSG_TYPE_TARGET_MSGOUT; + ahc->msgin_index = 0; + } +#if AHC_TARGET_MODE + else + ahc_setup_target_msgin(ahc, &devinfo); +#endif + } + } + + ahc_handle_message_phase(ahc); + break; + } + case PERR_DETECTED: + { + /* + * If we've cleared the parity error interrupt + * but the sequencer still believes that SCSIPERR + * is true, it must be that the parity error is + * for the currently presented byte on the bus, + * and we are not in a phase (data-in) where we will + * eventually ack this byte. Ack the byte and + * throw it away in the hope that the target will + * take us to message out to deliver the appropriate + * error message. + */ + if ((intstat & SCSIINT) == 0 + && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { + u_int curphase; + + /* + * The hardware will only let you ack bytes + * if the expected phase in SCSISIGO matches + * the current phase. Make sure this is + * currently the case. + */ + curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + ahc_outb(ahc, LASTPHASE, curphase); + ahc_outb(ahc, SCSISIGO, curphase); + ahc_inb(ahc, SCSIDATL); + } + break; + } + case DATA_OVERRUN: + { + /* + * When the sequencer detects an overrun, it + * places the controller in "BITBUCKET" mode + * and allows the target to complete its transfer. + * Unfortunately, none of the counters get updated + * when the controller is in this mode, so we have + * no way of knowing how large the overrun was. + */ + u_int scbindex = ahc_inb(ahc, SCB_TAG); + u_int lastphase = ahc_inb(ahc, LASTPHASE); + u_int i; + + scb = ahc_lookup_scb(ahc, scbindex); + for (i = 0; i < num_phases; i++) { + if (lastphase == phase_table[i].phase) + break; + } + ahc_print_path(ahc, scb); + printf("data overrun detected %s." + " Tag == 0x%x.\n", + phase_table[i].phasemsg, + scb->hscb->tag); + ahc_print_path(ahc, scb); + printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", + ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", + ahc_get_transfer_length(scb), scb->sg_count); + if (scb->sg_count > 0) { + for (i = 0; i < scb->sg_count; i++) { + printf("sg[%d] - Addr 0x%x : Length %d\n", + i, + ahc_le32toh(scb->sg_list[i].addr), + ahc_le32toh(scb->sg_list[i].len) + & AHC_SG_LEN_MASK); + } + } + /* + * Set this and it will take effect when the + * target does a command complete. + */ + ahc_freeze_devq(ahc, scb); + ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + ahc_freeze_scb(scb); + break; + } + case MKMSG_FAILED: + { + u_int scbindex; + + printf("%s:%c:%d:%d: Attempt to issue message failed\n", + ahc_name(ahc), devinfo.channel, devinfo.target, + devinfo.lun); + scbindex = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scbindex); + if (scb != NULL + && (scb->flags & SCB_RECOVERY_SCB) != 0) + /* + * Ensure that we didn't put a second instance of this + * SCB into the QINFIFO. + */ + ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), scb->hscb->tag, + ROLE_INITIATOR, /*status*/0, + SEARCH_REMOVE); + break; + } + case NO_FREE_SCB: + { + printf("%s: No free or disconnected SCBs\n", ahc_name(ahc)); + ahc_dump_card_state(ahc); + panic("for safety"); + break; + } + case SCB_MISMATCH: + { + u_int scbptr; + + scbptr = ahc_inb(ahc, SCBPTR); + printf("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n", + scbptr, ahc_inb(ahc, ARG_1), + ahc->scb_data->hscbs[scbptr].tag); + ahc_dump_card_state(ahc); + panic("for saftey"); + break; + } + case OUT_OF_RANGE: + { + printf("%s: BTT calculation out of range\n", ahc_name(ahc)); + printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " + "ARG_1 == 0x%x ACCUM = 0x%x\n", + ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), + ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); + printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + "SINDEX == 0x%x\n, A == 0x%x\n", + ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), + ahc_index_busy_tcl(ahc, + BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), + ahc_inb(ahc, SAVED_LUN))), + ahc_inb(ahc, SINDEX), + ahc_inb(ahc, ACCUM)); + printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", + ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), + ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), + ahc_inb(ahc, SCB_CONTROL)); + printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", + ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); + ahc_dump_card_state(ahc); + panic("for safety"); + break; + } + default: + printf("ahc_intr: seqint, " + "intstat == 0x%x, scsisigi = 0x%x\n", + intstat, ahc_inb(ahc, SCSISIGI)); + break; + } +unpause: + /* + * The sequencer is paused immediately on + * a SEQINT, so we should restart it when + * we're done. + */ + unpause_sequencer(ahc); +} + +void +ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) +{ + u_int scb_index; + u_int status0; + u_int status; + struct scb *scb; + char cur_channel; + char intr_channel; + + /* Make sure the sequencer is in a safe location. */ + ahc_clear_critical_section(ahc); + + if ((ahc->features & AHC_TWIN) != 0 + && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0)) + cur_channel = 'B'; + else + cur_channel = 'A'; + intr_channel = cur_channel; + + if ((ahc->features & AHC_ULTRA2) != 0) + status0 = ahc_inb(ahc, SSTAT0) & IOERR; + else + status0 = 0; + status = ahc_inb(ahc, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); + if (status == 0 && status0 == 0) { + if ((ahc->features & AHC_TWIN) != 0) { + /* Try the other channel */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); + status = ahc_inb(ahc, SSTAT1) + & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); + intr_channel = (cur_channel == 'A') ? 'B' : 'A'; + } + if (status == 0) { + printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + unpause_sequencer(ahc); + return; + } + } + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + if (scb != NULL + && (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) == 0) + scb = NULL; + + if ((ahc->features & AHC_ULTRA2) != 0 + && (status0 & IOERR) != 0) { + int now_lvd; + + now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40; + printf("%s: Transceiver State Has Changed to %s mode\n", + ahc_name(ahc), now_lvd ? "LVD" : "SE"); + ahc_outb(ahc, CLRSINT0, CLRIOERR); + /* + * When transitioning to SE mode, the reset line + * glitches, triggering an arbitration bug in some + * Ultra2 controllers. This bug is cleared when we + * assert the reset line. Since a reset glitch has + * already occurred with this transition and a + * transceiver state change is handled just like + * a bus reset anyway, asserting the reset line + * ourselves is safe. + */ + ahc_reset_channel(ahc, intr_channel, + /*Initiate Reset*/now_lvd == 0); + } else if ((status & SCSIRSTI) != 0) { + printf("%s: Someone reset channel %c\n", + ahc_name(ahc), intr_channel); + if (intr_channel != cur_channel) + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); + ahc_reset_channel(ahc, intr_channel, /*Initiate Reset*/FALSE); + } else if ((status & SCSIPERR) != 0) { + /* + * Determine the bus phase and queue an appropriate message. + * SCSIPERR is latched true as soon as a parity error + * occurs. If the sequencer acked the transfer that + * caused the parity error and the currently presented + * transfer on the bus has correct parity, SCSIPERR will + * be cleared by CLRSCSIPERR. Use this to determine if + * we should look at the last phase the sequencer recorded, + * or the current phase presented on the bus. + */ + u_int mesg_out; + u_int curphase; + u_int errorphase; + u_int lastphase; + u_int scsirate; + u_int i; + u_int sstat2; + + lastphase = ahc_inb(ahc, LASTPHASE); + curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + sstat2 = ahc_inb(ahc, SSTAT2); + ahc_outb(ahc, CLRSINT1, CLRSCSIPERR); + /* + * For all phases save DATA, the sequencer won't + * automatically ack a byte that has a parity error + * in it. So the only way that the current phase + * could be 'data-in' is if the parity error is for + * an already acked byte in the data phase. During + * synchronous data-in transfers, we may actually + * ack bytes before latching the current phase in + * LASTPHASE, leading to the discrepancy between + * curphase and lastphase. + */ + if ((ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0 + || curphase == P_DATAIN || curphase == P_DATAIN_DT) + errorphase = curphase; + else + errorphase = lastphase; + + for (i = 0; i < num_phases; i++) { + if (errorphase == phase_table[i].phase) + break; + } + mesg_out = phase_table[i].mesg_out; + if (scb != NULL) + ahc_print_path(ahc, scb); + else + printf("%s:%c:%d: ", ahc_name(ahc), intr_channel, + SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID))); + scsirate = ahc_inb(ahc, SCSIRATE); + printf("parity error detected %s. " + "SEQADDR(0x%x) SCSIRATE(0x%x)\n", + phase_table[i].phasemsg, + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), + scsirate); + + if ((ahc->features & AHC_DT) != 0) { + + if ((sstat2 & CRCVALERR) != 0) + printf("\tCRC Value Mismatch\n"); + if ((sstat2 & CRCENDERR) != 0) + printf("\tNo terminal CRC packet recevied\n"); + if ((sstat2 & CRCREQERR) != 0) + printf("\tIllegal CRC packet request\n"); + if ((sstat2 & DUAL_EDGE_ERR) != 0) + printf("\tUnexpected %sDT Data Phase\n", + (scsirate & SINGLE_EDGE) ? "" : "non-"); + } + + /* + * We've set the hardware to assert ATN if we + * get a parity error on "in" phases, so all we + * need to do is stuff the message buffer with + * the appropriate message. "In" phases have set + * mesg_out to something other than MSG_NOP. + */ + if (mesg_out != MSG_NOOP) { + if (ahc->msg_type != MSG_TYPE_NONE) + ahc->send_msg_perror = TRUE; + else + ahc_outb(ahc, MSG_OUT, mesg_out); + } + ahc_outb(ahc, CLRINT, CLRSCSIINT); + unpause_sequencer(ahc); + } else if ((status & BUSFREE) != 0 + && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { + u_int lastphase; + u_int saved_scsiid; + u_int saved_lun; + u_int target; + u_int initiator_role_id; + char channel; + int printerror; + + /* + * Clear our selection hardware as soon as possible. + * We may have an entry in the waiting Q for this target, + * that is affected by this busfree and we don't want to + * go about selecting the target while we handle the event. + */ + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); + + /* + * Disable busfree interrupts and clear the busfree + * interrupt status. We do this here so that several + * bus transactions occur prior to clearing the SCSIINT + * latch. It can take a bit for the clearing to take effect. + */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR); + + /* + * Look at what phase we were last in. + * If its message out, chances are pretty good + * that the busfree was in response to one of + * our abort requests. + */ + lastphase = ahc_inb(ahc, LASTPHASE); + saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); + saved_lun = ahc_inb(ahc, SAVED_LUN); + target = SCSIID_TARGET(ahc, saved_scsiid); + initiator_role_id = SCSIID_OUR_ID(saved_scsiid); + channel = SCSIID_CHANNEL(ahc, saved_scsiid); + printerror = 1; + + if (lastphase == P_MESGOUT) { + struct ahc_devinfo devinfo; + u_int tag; + + ahc_fetch_devinfo(ahc, &devinfo); + tag = SCB_LIST_NULL; + if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE) + || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) { + if (ahc->msgout_buf[ahc->msgout_index - 1] + == MSG_ABORT_TAG) + tag = scb->hscb->tag; + ahc_print_path(ahc, scb); + printf("SCB %d - Abort%s Completed.\n", + scb->hscb->tag, tag == SCB_LIST_NULL ? + "" : " Tag"); + ahc_abort_scbs(ahc, target, channel, + saved_lun, tag, + ROLE_INITIATOR, + CAM_REQ_ABORTED); + printerror = 0; + } else if (ahc_sent_msg(ahc, AHCMSG_1B, + MSG_BUS_DEV_RESET, TRUE)) { + struct ahc_devinfo devinfo; +#ifdef __FreeBSD__ + /* + * Don't mark the user's request for this BDR + * as completing with CAM_BDR_SENT. CAM3 + * specifies CAM_REQ_CMP. + */ + if (scb != NULL + && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV + && ahc_match_scb(ahc, scb, target, channel, + CAM_LUN_WILDCARD, + SCB_LIST_NULL, + ROLE_INITIATOR)) { + ahc_set_transaction_status(scb, CAM_REQ_CMP); + } +#endif + ahc_compile_devinfo(&devinfo, + initiator_role_id, + target, + CAM_LUN_WILDCARD, + channel, + ROLE_INITIATOR); + ahc_handle_devreset(ahc, &devinfo, + CAM_BDR_SENT, + "Bus Device Reset", + /*verbose_level*/0); + printerror = 0; + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, + MSG_EXT_PPR, FALSE)) { + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + + /* + * PPR Rejected. Try non-ppr negotiation + * and retry command. + */ + tinfo = ahc_fetch_transinfo(ahc, + devinfo.channel, + devinfo.our_scsiid, + devinfo.target, + &tstate); + tinfo->current.transport_version = 2; + tinfo->goal.transport_version = 2; + tinfo->goal.ppr_options = 0; + ahc_qinfifo_requeue_tail(ahc, scb); + printerror = 0; + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, + MSG_EXT_WDTR, FALSE) + || ahc_sent_msg(ahc, AHCMSG_EXT, + MSG_EXT_SDTR, FALSE)) { + /* + * Negotiation Rejected. Go-async and + * retry command. + */ + ahc_set_width(ahc, &devinfo, + MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_CUR|AHC_TRANS_GOAL, + /*paused*/TRUE); + ahc_set_syncrate(ahc, &devinfo, + /*syncrate*/NULL, + /*period*/0, /*offset*/0, + /*ppr_options*/0, + AHC_TRANS_CUR|AHC_TRANS_GOAL, + /*paused*/TRUE); + ahc_qinfifo_requeue_tail(ahc, scb); + printerror = 0; + } + } + if (printerror != 0) { + u_int i; + + if (scb != NULL) { + u_int tag; + + if ((scb->hscb->control & TAG_ENB) != 0) + tag = scb->hscb->tag; + else + tag = SCB_LIST_NULL; + ahc_print_path(ahc, scb); + ahc_abort_scbs(ahc, target, channel, + SCB_GET_LUN(scb), tag, + ROLE_INITIATOR, + CAM_UNEXP_BUSFREE); + } else { + /* + * We had not fully identified this connection, + * so we cannot abort anything. + */ + printf("%s: ", ahc_name(ahc)); + } + for (i = 0; i < num_phases; i++) { + if (lastphase == phase_table[i].phase) + break; + } + printf("Unexpected busfree %s\n" + "SEQADDR == 0x%x\n", + phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) + | (ahc_inb(ahc, SEQADDR1) << 8)); + } + ahc_clear_msg_state(ahc); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + restart_sequencer(ahc); + } else if ((status & SELTO) != 0) { + u_int scbptr; + + /* Stop the selection */ + ahc_outb(ahc, SCSISEQ, 0); + + /* No more pending messages */ + ahc_clear_msg_state(ahc); + + /* Clear interrupt state */ + ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); + + /* + * Although the driver does not care about the + * 'Selection in Progress' status bit, the busy + * LED does. SELINGO is only cleared by a sucessful + * selection, so we must manually clear it to insure + * the LED turns off just incase no future successful + * selections occur (e.g. no devices on the bus). + */ + ahc_outb(ahc, CLRSINT0, CLRSELINGO); + + scbptr = ahc_inb(ahc, WAITING_SCBH); + ahc_outb(ahc, SCBPTR, scbptr); + scb_index = ahc_inb(ahc, SCB_TAG); + + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s: ahc_intr - referenced scb not " + "valid during SELTO scb(%d, %d)\n", + ahc_name(ahc), scbptr, scb_index); + } else { + ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); + ahc_freeze_devq(ahc, scb); + } + ahc_outb(ahc, CLRINT, CLRSCSIINT); + restart_sequencer(ahc); + } else { + printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", + ahc_name(ahc), status); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + } +} + +#define AHC_MAX_STEPS 2000 +void +ahc_clear_critical_section(struct ahc_softc *ahc) +{ + int stepping; + int steps; + u_int simode0; + u_int simode1; + + if (ahc->num_critical_sections == 0) + return; + + stepping = FALSE; + steps = 0; + simode0 = 0; + simode1 = 0; + for (;;) { + struct cs *cs; + u_int seqaddr; + u_int i; + + seqaddr = ahc_inb(ahc, SEQADDR0) + | (ahc_inb(ahc, SEQADDR1) << 8); + + cs = ahc->critical_sections; + for (i = 0; i < ahc->num_critical_sections; i++, cs++) { + + if (cs->begin < seqaddr && cs->end >= seqaddr) + break; + } + + if (i == ahc->num_critical_sections) + break; + + if (steps > AHC_MAX_STEPS) { + printf("%s: Infinite loop in critical section\n", + ahc_name(ahc)); + ahc_dump_card_state(ahc); + panic("critical section loop"); + } + + steps++; + if (stepping == FALSE) { + + /* + * Disable all interrupt sources so that the + * sequencer will not be stuck by a pausing + * interrupt condition while we attempt to + * leave a critical section. + */ + simode0 = ahc_inb(ahc, SIMODE0); + ahc_outb(ahc, SIMODE0, 0); + simode1 = ahc_inb(ahc, SIMODE1); + ahc_outb(ahc, SIMODE1, 0); + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP); + stepping = TRUE; + } + ahc_outb(ahc, HCNTRL, ahc->unpause); + do { + ahc_delay(200); + } while (!sequencer_paused(ahc)); + } + if (stepping) { + ahc_outb(ahc, SIMODE0, simode0); + ahc_outb(ahc, SIMODE1, simode1); + ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) & ~STEP); + } +} + +/* + * Clear any pending interrupt status. + */ +void +ahc_clear_intstat(struct ahc_softc *ahc) +{ + /* Clear any interrupt conditions this may have caused */ + ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI + |CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG| + CLRREQINIT); + ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO); + ahc_outb(ahc, CLRINT, CLRSCSIINT); +} + +/**************************** Debugging Routines ******************************/ +void +ahc_print_scb(struct scb *scb) +{ + int i; + + struct hardware_scb *hscb = scb->hscb; + + printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", + scb, + hscb->control, + hscb->scsiid, + hscb->lun, + hscb->cdb_len); + i = 0; + printf("Shared Data: %#02x %#02x %#02x %#02x\n", + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++]); + printf(" %#02x %#02x %#02x %#02x\n", + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++]); + printf(" %#02x %#02x %#02x %#02x\n", + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++], + hscb->shared_data.cdb[i++]); + printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", + ahc_le32toh(hscb->dataptr), + ahc_le32toh(hscb->datacnt), + ahc_le32toh(hscb->sgptr), + hscb->tag); + if (scb->sg_count > 0) { + for (i = 0; i < scb->sg_count; i++) { + printf("sg[%d] - Addr 0x%x : Length %d\n", + i, + ahc_le32toh(scb->sg_list[i].addr), + ahc_le32toh(scb->sg_list[i].len)); + } + } +} + +/************************* Transfer Negotiation *******************************/ +/* + * Allocate per target mode instance (ID we respond to as a target) + * transfer negotiation data structures. + */ +static struct tmode_tstate * +ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) +{ + struct tmode_tstate *master_tstate; + struct tmode_tstate *tstate; + int i; + + master_tstate = ahc->enabled_targets[ahc->our_id]; + if (channel == 'B') { + scsi_id += 8; + master_tstate = ahc->enabled_targets[ahc->our_id_b + 8]; + } + if (ahc->enabled_targets[scsi_id] != NULL + && ahc->enabled_targets[scsi_id] != master_tstate) + panic("%s: ahc_alloc_tstate - Target already allocated", + ahc_name(ahc)); + tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); + if (tstate == NULL) + return (NULL); + + /* + * If we have allocated a master tstate, copy user settings from + * the master tstate (taken from SRAM or the EEPROM) for this + * channel, but reset our current and goal settings to async/narrow + * until an initiator talks to us. + */ + if (master_tstate != NULL) { + memcpy(tstate, master_tstate, sizeof(*tstate)); + memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); + tstate->ultraenb = 0; + for (i = 0; i < 16; i++) { + memset(&tstate->transinfo[i].current, 0, + sizeof(tstate->transinfo[i].current)); + memset(&tstate->transinfo[i].goal, 0, + sizeof(tstate->transinfo[i].goal)); + } + } else + memset(tstate, 0, sizeof(*tstate)); + ahc->enabled_targets[scsi_id] = tstate; + return (tstate); +} + +#ifdef AHC_TARGET_MODE +/* + * Free per target mode instance (ID we respond to as a target) + * transfer negotiation data structures. + */ +static void +ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) +{ + struct tmode_tstate *tstate; + + /* Don't clean up the entry for our initiator role */ + if ((ahc->flags & AHC_INITIATORROLE) != 0 + && ((channel == 'B' && scsi_id == ahc->our_id_b) + || (channel == 'A' && scsi_id == ahc->our_id)) + && force == FALSE) + return; + + if (channel == 'B') + scsi_id += 8; + tstate = ahc->enabled_targets[scsi_id]; + if (tstate != NULL) + free(tstate, M_DEVBUF); + ahc->enabled_targets[scsi_id] = NULL; +} +#endif + +/* + * Called when we have an active connection to a target on the bus, + * this function finds the nearest syncrate to the input period limited + * by the capabilities of the bus connectivity of and sync settings for + * the target. + */ +struct ahc_syncrate * +ahc_devlimited_syncrate(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, + u_int *period, u_int *ppr_options, role_t role) { + struct ahc_transinfo *transinfo; + u_int maxsync; + + if ((ahc->features & AHC_ULTRA2) != 0) { + if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 + && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { + maxsync = AHC_SYNCRATE_DT; + } else { + maxsync = AHC_SYNCRATE_ULTRA; + /* Can't do DT on an SE bus */ + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + } + } else if ((ahc->features & AHC_ULTRA) != 0 + && (ahc->flags & AHC_ULTRA_DISABLED) == 0) { + maxsync = AHC_SYNCRATE_ULTRA; + } else { + maxsync = AHC_SYNCRATE_FAST; + } + /* + * Never allow a value higher than our current goal + * period otherwise we may allow a target initiated + * negotiation to go above the limit as set by the + * user. In the case of an initiator initiated + * sync negotiation, we limit based on the user + * setting. This allows the system to still accept + * incoming negotiations even if target initiated + * negotiation is not performed. + */ + if (role == ROLE_TARGET) + transinfo = &tinfo->user; + else + transinfo = &tinfo->goal; + *ppr_options &= transinfo->ppr_options; + if (transinfo->period == 0) { + *period = 0; + *ppr_options = 0; + return (NULL); + } + *period = MAX(*period, transinfo->period); + return (ahc_find_syncrate(ahc, period, ppr_options, maxsync)); +} + +/* + * Look up the valid period to SCSIRATE conversion in our table. + * Return the period and offset that should be sent to the target + * if this was the beginning of an SDTR. + */ +struct ahc_syncrate * +ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, + u_int *ppr_options, u_int maxsync) +{ + struct ahc_syncrate *syncrate; + + if ((ahc->features & AHC_DT) == 0) + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + + for (syncrate = &ahc_syncrates[maxsync]; + syncrate->rate != NULL; + syncrate++) { + + /* + * The Ultra2 table doesn't go as low + * as for the Fast/Ultra cards. + */ + if ((ahc->features & AHC_ULTRA2) != 0 + && (syncrate->sxfr_u2 == 0)) + break; + + /* Skip any DT entries if DT is not available */ + if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && (syncrate->sxfr_u2 & DT_SXFR) != 0) + continue; + + if (*period <= syncrate->period) { + /* + * When responding to a target that requests + * sync, the requested rate may fall between + * two rates that we can output, but still be + * a rate that we can receive. Because of this, + * we want to respond to the target with + * the same rate that it sent to us even + * if the period we use to send data to it + * is lower. Only lower the response period + * if we must. + */ + if (syncrate == &ahc_syncrates[maxsync]) + *period = syncrate->period; + + /* + * At some speeds, we only support + * ST transfers. + */ + if ((syncrate->sxfr_u2 & ST_SXFR) != 0) + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + break; + } + } + + if ((*period == 0) + || (syncrate->rate == NULL) + || ((ahc->features & AHC_ULTRA2) != 0 + && (syncrate->sxfr_u2 == 0))) { + /* Use asynchronous transfers. */ + *period = 0; + syncrate = NULL; + *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + } + return (syncrate); +} + +/* + * Convert from an entry in our syncrate table to the SCSI equivalent + * sync "period" factor. + */ +u_int +ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync) +{ + struct ahc_syncrate *syncrate; + + if ((ahc->features & AHC_ULTRA2) != 0) + scsirate &= SXFR_ULTRA2; + else + scsirate &= SXFR; + + syncrate = &ahc_syncrates[maxsync]; + while (syncrate->rate != NULL) { + + if ((ahc->features & AHC_ULTRA2) != 0) { + if (syncrate->sxfr_u2 == 0) + break; + else if (scsirate == (syncrate->sxfr_u2 & SXFR_ULTRA2)) + return (syncrate->period); + } else if (scsirate == (syncrate->sxfr & SXFR)) { + return (syncrate->period); + } + syncrate++; + } + return (0); /* async */ +} + +/* + * Truncate the given synchronous offset to a value the + * current adapter type and syncrate are capable of. + */ +void +ahc_validate_offset(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, + struct ahc_syncrate *syncrate, + u_int *offset, int wide, role_t role) +{ + u_int maxoffset; + + /* Limit offset to what we can do */ + if (syncrate == NULL) { + maxoffset = 0; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + maxoffset = MAX_OFFSET_ULTRA2; + } else { + if (wide) + maxoffset = MAX_OFFSET_16BIT; + else + maxoffset = MAX_OFFSET_8BIT; + } + *offset = MIN(*offset, maxoffset); + if (tinfo != NULL) { + if (role == ROLE_TARGET) + *offset = MIN(*offset, tinfo->user.offset); + else + *offset = MIN(*offset, tinfo->goal.offset); + } +} + +/* + * Truncate the given transfer width parameter to a value the + * current adapter type is capable of. + */ +void +ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo, + u_int *bus_width, role_t role) +{ + switch (*bus_width) { + default: + if (ahc->features & AHC_WIDE) { + /* Respond Wide */ + *bus_width = MSG_EXT_WDTR_BUS_16_BIT; + break; + } + /* FALLTHROUGH */ + case MSG_EXT_WDTR_BUS_8_BIT: + *bus_width = MSG_EXT_WDTR_BUS_8_BIT; + break; + } + if (tinfo != NULL) { + if (role == ROLE_TARGET) + *bus_width = MIN(tinfo->user.width, *bus_width); + else + *bus_width = MIN(tinfo->goal.width, *bus_width); + } +} + +/* + * Update the bitmask of targets for which the controller should + * negotiate with at the next convenient oportunity. This currently + * means the next time we send the initial identify messages for + * a new transaction. + */ +void +ahc_update_target_msg_request(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct ahc_initiator_tinfo *tinfo, + int force, int paused) +{ + u_int targ_msg_req_orig; + + targ_msg_req_orig = ahc->targ_msg_req; + if (tinfo->current.period != tinfo->goal.period + || tinfo->current.width != tinfo->goal.width + || tinfo->current.offset != tinfo->goal.offset + || tinfo->current.ppr_options != tinfo->goal.ppr_options + || (force + && (tinfo->goal.period != 0 + || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT + || tinfo->goal.ppr_options != 0))) + ahc->targ_msg_req |= devinfo->target_mask; + else + ahc->targ_msg_req &= ~devinfo->target_mask; + + if (ahc->targ_msg_req != targ_msg_req_orig) { + /* Update the message request bit for this target */ + if (!paused) + pause_sequencer(ahc); + + ahc_outb(ahc, TARGET_MSG_REQUEST, + ahc->targ_msg_req & 0xFF); + ahc_outb(ahc, TARGET_MSG_REQUEST + 1, + (ahc->targ_msg_req >> 8) & 0xFF); + + if (!paused) + unpause_sequencer(ahc); + } +} + +/* + * Update the user/goal/current tables of synchronous negotiation + * parameters as well as, in the case of a current or active update, + * any data structures on the host controller. In the case of an + * active update, the specified target is currently talking to us on + * the bus, so the transfer parameter update must take effect + * immediately. + */ +void +ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct ahc_syncrate *syncrate, u_int period, + u_int offset, u_int ppr_options, u_int type, int paused) +{ + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int old_period; + u_int old_offset; + u_int old_ppr; + int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + + if (syncrate == NULL) { + period = 0; + offset = 0; + } + + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + + if ((type & AHC_TRANS_USER) != 0) { + tinfo->user.period = period; + tinfo->user.offset = offset; + tinfo->user.ppr_options = ppr_options; + } + + if ((type & AHC_TRANS_GOAL) != 0) { + tinfo->goal.period = period; + tinfo->goal.offset = offset; + tinfo->goal.ppr_options = ppr_options; + } + + old_period = tinfo->current.period; + old_offset = tinfo->current.offset; + old_ppr = tinfo->current.ppr_options; + + if ((type & AHC_TRANS_CUR) != 0 + && (old_period != period + || old_offset != offset + || old_ppr != ppr_options)) { + u_int scsirate; + + scsirate = tinfo->scsirate; + if ((ahc->features & AHC_ULTRA2) != 0) { + + scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC); + if (syncrate != NULL) { + scsirate |= syncrate->sxfr_u2; + if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) + scsirate |= ENABLE_CRC; + else + scsirate |= SINGLE_EDGE; + } + } else { + + scsirate &= ~(SXFR|SOFS); + /* + * Ensure Ultra mode is set properly for + * this target. + */ + tstate->ultraenb &= ~devinfo->target_mask; + if (syncrate != NULL) { + if (syncrate->sxfr & ULTRA_SXFR) { + tstate->ultraenb |= + devinfo->target_mask; + } + scsirate |= syncrate->sxfr & SXFR; + scsirate |= offset & SOFS; + } + if (active) { + u_int sxfrctl0; + + sxfrctl0 = ahc_inb(ahc, SXFRCTL0); + sxfrctl0 &= ~FAST20; + if (tstate->ultraenb & devinfo->target_mask) + sxfrctl0 |= FAST20; + ahc_outb(ahc, SXFRCTL0, sxfrctl0); + } + } + if (active) { + ahc_outb(ahc, SCSIRATE, scsirate); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIOFFSET, offset); + } + + tinfo->scsirate = scsirate; + tinfo->current.period = period; + tinfo->current.offset = offset; + tinfo->current.ppr_options = ppr_options; + + /* Update the syncrates in any pending scbs */ + ahc_update_pending_syncrates(ahc); + + ahc_send_async(ahc, devinfo->channel, devinfo->target, + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + if (bootverbose) { + if (offset != 0) { + printf("%s: target %d synchronous at %sMHz%s, " + "offset = 0x%x\n", ahc_name(ahc), + devinfo->target, syncrate->rate, + (ppr_options & MSG_EXT_PPR_DT_REQ) + ? " DT" : "", offset); + } else { + printf("%s: target %d using " + "asynchronous transfers\n", + ahc_name(ahc), devinfo->target); + } + } + } + + ahc_update_target_msg_request(ahc, devinfo, tinfo, + /*force*/FALSE, + paused); +} + +/* + * Update the user/goal/current tables of wide negotiation + * parameters as well as, in the case of a current or active update, + * any data structures on the host controller. In the case of an + * active update, the specified target is currently talking to us on + * the bus, so the transfer parameter update must take effect + * immediately. + */ +void +ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + u_int width, u_int type, int paused) +{ + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int oldwidth; + int active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; + + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + + if ((type & AHC_TRANS_USER) != 0) + tinfo->user.width = width; + + if ((type & AHC_TRANS_GOAL) != 0) + tinfo->goal.width = width; + + oldwidth = tinfo->current.width; + if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { + u_int scsirate; + + scsirate = tinfo->scsirate; + scsirate &= ~WIDEXFER; + if (width == MSG_EXT_WDTR_BUS_16_BIT) + scsirate |= WIDEXFER; + + tinfo->scsirate = scsirate; + + if (active) + ahc_outb(ahc, SCSIRATE, scsirate); + + tinfo->current.width = width; + + ahc_send_async(ahc, devinfo->channel, devinfo->target, + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + if (bootverbose) { + printf("%s: target %d using %dbit transfers\n", + ahc_name(ahc), devinfo->target, + 8 * (0x01 << width)); + } + } + + ahc_update_target_msg_request(ahc, devinfo, tinfo, + /*force*/FALSE, paused); +} + +/* + * Update the current state of tagged queuing for a given target. + */ +void +ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable) +{ + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + uint16_t orig_tagenable; + + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + + orig_tagenable = tstate->tagenable; + if (enable) + tstate->tagenable |= devinfo->target_mask; + else + tstate->tagenable &= ~devinfo->target_mask; + + if (orig_tagenable != tstate->tagenable) { + ahc_platform_set_tags(ahc, devinfo, enable); + ahc_send_async(ahc, devinfo->channel, devinfo->target, + devinfo->lun, AC_TRANSFER_NEG); + } + +} + +/* + * When the transfer settings for a connection change, update any + * in-transit SCBs to contain the new data so the hardware will + * be set correctly during future (re)selections. + */ +static void +ahc_update_pending_syncrates(struct ahc_softc *ahc) +{ + struct scb *pending_scb; + int pending_scb_count; + int i; + u_int saved_scbptr; + + /* + * Traverse the pending SCB list and ensure that all of the + * SCBs there have the proper settings. + */ + pending_scb_count = 0; + LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { + struct ahc_devinfo devinfo; + struct hardware_scb *pending_hscb; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + + ahc_scb_devinfo(ahc, &devinfo, pending_scb); + tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, + devinfo.our_scsiid, + devinfo.target, &tstate); + pending_hscb = pending_scb->hscb; + pending_hscb->control &= ~ULTRAENB; + if ((tstate->ultraenb & devinfo.target_mask) != 0) + pending_hscb->control |= ULTRAENB; + pending_hscb->scsirate = tinfo->scsirate; + pending_hscb->scsioffset = tinfo->current.offset; + pending_scb_count++; + } + + if (pending_scb_count == 0) + return; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + /* Ensure that the hscbs down on the card match the new information */ + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + struct hardware_scb *pending_hscb; + u_int control; + u_int scb_tag; + + ahc_outb(ahc, SCBPTR, i); + scb_tag = ahc_inb(ahc, SCB_TAG); + pending_scb = ahc_lookup_scb(ahc, scb_tag); + if (pending_scb == NULL) + continue; + + pending_hscb = pending_scb->hscb; + control = ahc_inb(ahc, SCB_CONTROL); + control &= ~ULTRAENB; + if ((pending_hscb->control & ULTRAENB) != 0) + control |= ULTRAENB; + ahc_outb(ahc, SCB_CONTROL, control); + ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate); + ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset); + } + ahc_outb(ahc, SCBPTR, saved_scbptr); +} + +/**************************** Pathing Information *****************************/ +static void +ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + u_int saved_scsiid; + role_t role; + int our_id; + + if (ahc_inb(ahc, SSTAT0) & TARGET) + role = ROLE_TARGET; + else + role = ROLE_INITIATOR; + + if (role == ROLE_TARGET + && (ahc->features & AHC_MULTI_TID) != 0 + && (ahc_inb(ahc, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) { + /* We were selected, so pull our id from TARGIDIN */ + our_id = ahc_inb(ahc, TARGIDIN) & OID; + } else if ((ahc->features & AHC_ULTRA2) != 0) + our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; + else + our_id = ahc_inb(ahc, SCSIID) & OID; + + saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); + ahc_compile_devinfo(devinfo, + our_id, + SCSIID_TARGET(ahc, saved_scsiid), + ahc_inb(ahc, SAVED_LUN), + SCSIID_CHANNEL(ahc, saved_scsiid), + role); +} + +void +ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, + u_int lun, char channel, role_t role) +{ + devinfo->our_scsiid = our_id; + devinfo->target = target; + devinfo->lun = lun; + devinfo->target_offset = target; + devinfo->channel = channel; + devinfo->role = role; + if (channel == 'B') + devinfo->target_offset += 8; + devinfo->target_mask = (0x01 << devinfo->target_offset); +} + +static void +ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) +{ + role_t role; + int our_id; + + our_id = SCSIID_OUR_ID(scb->hscb->scsiid); + role = ROLE_INITIATOR; + if ((scb->hscb->control & TARGET_SCB) != 0) + role = ROLE_TARGET; + ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb), + SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role); +} + + +/************************ Message Phase Processing ****************************/ +/* + * When an initiator transaction with the MK_MESSAGE flag either reconnects + * or enters the initial message out phase, we are interrupted. Fill our + * outgoing message buffer with the appropriate message and beging handing + * the message phase(s) manually. + */ +static void +ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + struct scb *scb) +{ + /* + * To facilitate adding multiple messages together, + * each routine should increment the index and len + * variables instead of setting them explicitly. + */ + ahc->msgout_index = 0; + ahc->msgout_len = 0; + + if ((scb->flags & SCB_DEVICE_RESET) == 0 + && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) { + u_int identify_msg; + + identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb); + if ((scb->hscb->control & DISCENB) != 0) + identify_msg |= MSG_IDENTIFY_DISCFLAG; + ahc->msgout_buf[ahc->msgout_index++] = identify_msg; + ahc->msgout_len++; + + if ((scb->hscb->control & TAG_ENB) != 0) { + ahc->msgout_buf[ahc->msgout_index++] = + scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE); + ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag; + ahc->msgout_len += 2; + } + } + + if (scb->flags & SCB_DEVICE_RESET) { + ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET; + ahc->msgout_len++; + ahc_print_path(ahc, scb); + printf("Bus Device Reset Message Sent\n"); + /* + * Clear our selection hardware in advance of + * the busfree. We may have an entry in the waiting + * Q for this target, and we don't want to go about + * selecting while we handle the busfree and blow it + * away. + */ + ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); + } else if ((scb->flags & SCB_ABORT) != 0) { + if ((scb->hscb->control & TAG_ENB) != 0) + ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG; + else + ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT; + ahc->msgout_len++; + ahc_print_path(ahc, scb); + printf("Abort%s Message Sent\n", + (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); + /* + * Clear our selection hardware in advance of + * the busfree. We may have an entry in the waiting + * Q for this target, and we don't want to go about + * selecting while we handle the busfree and blow it + * away. + */ + ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); + } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0 + || (scb->flags & SCB_NEGOTIATE) != 0) { + ahc_build_transfer_msg(ahc, devinfo); + } else { + printf("ahc_intr: AWAITING_MSG for an SCB that " + "does not have a waiting message\n"); + printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, + devinfo->target_mask); + panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " + "SCB flags = %x", scb->hscb->tag, scb->hscb->control, + ahc_inb(ahc, MSG_OUT), scb->flags); + } + + /* + * Clear the MK_MESSAGE flag from the SCB so we aren't + * asked to send this message again. + */ + ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); + ahc->msgout_index = 0; + ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; +} + +/* + * Build an appropriate transfer negotiation message for the + * currently active target. + */ +static void +ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + /* + * We need to initiate transfer negotiations. + * If our current and goal settings are identical, + * we want to renegotiate due to a check condition. + */ + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + struct ahc_syncrate *rate; + int dowide; + int dosync; + int doppr; + int use_ppr; + u_int period; + u_int ppr_options; + u_int offset; + + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + dowide = tinfo->current.width != tinfo->goal.width; + dosync = tinfo->current.period != tinfo->goal.period; + doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options; + + if (!dowide && !dosync && !doppr) { + dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; + dosync = tinfo->goal.period != 0; + doppr = tinfo->goal.ppr_options != 0; + } + + if (!dowide && !dosync && !doppr) { + panic("ahc_intr: AWAITING_MSG for negotiation, " + "but no negotiation needed\n"); + } + + use_ppr = (tinfo->current.transport_version >= 3) || doppr; + /* Target initiated PPR is not allowed in the SCSI spec */ + if (devinfo->role == ROLE_TARGET) + use_ppr = 0; + + /* + * Both the PPR message and SDTR message require the + * goal syncrate to be limited to what the target device + * is capable of handling (based on whether an LVD->SE + * expander is on the bus), so combine these two cases. + * Regardless, guarantee that if we are using WDTR and SDTR + * messages that WDTR comes first. + */ + if (use_ppr || (dosync && !dowide)) { + + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + if (use_ppr == 0) + ppr_options = 0; + rate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, devinfo->role); + offset = tinfo->goal.offset; + ahc_validate_offset(ahc, tinfo, rate, &offset, + use_ppr ? tinfo->goal.width + : tinfo->current.width, + devinfo->role); + if (use_ppr) { + ahc_construct_ppr(ahc, devinfo, period, offset, + tinfo->goal.width, ppr_options); + } else { + ahc_construct_sdtr(ahc, devinfo, period, offset); + } + } else { + ahc_construct_wdtr(ahc, devinfo, tinfo->goal.width); + } +} + +/* + * Build a synchronous negotiation message in our message + * buffer based on the input parameters. + */ +static void +ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + u_int period, u_int offset) +{ + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR; + ahc->msgout_buf[ahc->msgout_index++] = period; + ahc->msgout_buf[ahc->msgout_index++] = offset; + ahc->msgout_len += 5; + if (bootverbose) { + printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, period, offset); + } +} + +/* + * Build a wide negotiateion message in our message + * buffer based on the input parameters. + */ +static void +ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + u_int bus_width) +{ + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR; + ahc->msgout_buf[ahc->msgout_index++] = bus_width; + ahc->msgout_len += 4; + if (bootverbose) { + printf("(%s:%c:%d:%d): Sending WDTR %x\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, bus_width); + } +} + +/* + * Build a parallel protocol request message in our message + * buffer based on the input parameters. + */ +static void +ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + u_int period, u_int offset, u_int bus_width, + u_int ppr_options) +{ + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN; + ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR; + ahc->msgout_buf[ahc->msgout_index++] = period; + ahc->msgout_buf[ahc->msgout_index++] = 0; + ahc->msgout_buf[ahc->msgout_index++] = offset; + ahc->msgout_buf[ahc->msgout_index++] = bus_width; + ahc->msgout_buf[ahc->msgout_index++] = ppr_options; + ahc->msgout_len += 8; + if (bootverbose) { + printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " + "offset %x, ppr_options %x\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun, + bus_width, period, offset, ppr_options); + } +} + +/* + * Clear any active message state. + */ +static void +ahc_clear_msg_state(struct ahc_softc *ahc) +{ + ahc->msgout_len = 0; + ahc->msgin_index = 0; + ahc->msg_type = MSG_TYPE_NONE; + if ((ahc_inb(ahc, SCSISIGI) & ATNI) == 0) { + /* + * The target didn't care to respond to our + * message request, so clear ATN. + */ + ahc_outb(ahc, CLRSINT1, CLRATNO); + } + ahc_outb(ahc, MSG_OUT, MSG_NOOP); +} + +/* + * Manual message loop handler. + */ +static void +ahc_handle_message_phase(struct ahc_softc *ahc) +{ + struct ahc_devinfo devinfo; + u_int bus_phase; + int end_session; + + ahc_fetch_devinfo(ahc, &devinfo); + end_session = FALSE; + bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + +reswitch: + switch (ahc->msg_type) { + case MSG_TYPE_INITIATOR_MSGOUT: + { + int lastbyte; + int phasemis; + int msgdone; + + if (ahc->msgout_len == 0) + panic("HOST_MSG_LOOP interrupt with no active message"); + + phasemis = bus_phase != P_MESGOUT; + if (phasemis) { + if (bus_phase == P_MESGIN) { + /* + * Change gears and see if + * this messages is of interest to + * us or should be passed back to + * the sequencer. + */ + ahc_outb(ahc, CLRSINT1, CLRATNO); + ahc->send_msg_perror = FALSE; + ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN; + ahc->msgin_index = 0; + goto reswitch; + } + end_session = TRUE; + break; + } + + if (ahc->send_msg_perror) { + ahc_outb(ahc, CLRSINT1, CLRATNO); + ahc_outb(ahc, CLRSINT1, CLRREQINIT); + ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR); + break; + } + + msgdone = ahc->msgout_index == ahc->msgout_len; + if (msgdone) { + /* + * The target has requested a retry. + * Re-assert ATN, reset our message index to + * 0, and try again. + */ + ahc->msgout_index = 0; + ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + } + + lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); + if (lastbyte) { + /* Last byte is signified by dropping ATN */ + ahc_outb(ahc, CLRSINT1, CLRATNO); + } + + /* + * Clear our interrupt status and present + * the next byte on the bus. + */ + ahc_outb(ahc, CLRSINT1, CLRREQINIT); + ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); + break; + } + case MSG_TYPE_INITIATOR_MSGIN: + { + int phasemis; + int message_done; + + phasemis = bus_phase != P_MESGIN; + + if (phasemis) { + ahc->msgin_index = 0; + if (bus_phase == P_MESGOUT + && (ahc->send_msg_perror == TRUE + || (ahc->msgout_len != 0 + && ahc->msgout_index == 0))) { + ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; + goto reswitch; + } + end_session = TRUE; + break; + } + + /* Pull the byte in without acking it */ + ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL); + + message_done = ahc_parse_msg(ahc, &devinfo); + + if (message_done) { + /* + * Clear our incoming message buffer in case there + * is another message following this one. + */ + ahc->msgin_index = 0; + + /* + * If this message illicited a response, + * assert ATN so the target takes us to the + * message out phase. + */ + if (ahc->msgout_len != 0) + ahc_outb(ahc, SCSISIGO, + ahc_inb(ahc, SCSISIGO) | ATNO); + } else + ahc->msgin_index++; + + /* Ack the byte */ + ahc_outb(ahc, CLRSINT1, CLRREQINIT); + ahc_inb(ahc, SCSIDATL); + break; + } + case MSG_TYPE_TARGET_MSGIN: + { + int msgdone; + int msgout_request; + + if (ahc->msgout_len == 0) + panic("Target MSGIN with no active message"); + + /* + * If we interrupted a mesgout session, the initiator + * will not know this until our first REQ. So, we + * only honor mesgout requests after we've sent our + * first byte. + */ + if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0 + && ahc->msgout_index > 0) + msgout_request = TRUE; + else + msgout_request = FALSE; + + if (msgout_request) { + + /* + * Change gears and see if + * this messages is of interest to + * us or should be passed back to + * the sequencer. + */ + ahc->msg_type = MSG_TYPE_TARGET_MSGOUT; + ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO); + ahc->msgin_index = 0; + /* Dummy read to REQ for first byte */ + ahc_inb(ahc, SCSIDATL); + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | SPIOEN); + break; + } + + msgdone = ahc->msgout_index == ahc->msgout_len; + if (msgdone) { + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); + end_session = TRUE; + break; + } + + /* + * Present the next byte on the bus. + */ + ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); + ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); + break; + } + case MSG_TYPE_TARGET_MSGOUT: + { + int lastbyte; + int msgdone; + + /* + * The initiator signals that this is + * the last byte by dropping ATN. + */ + lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0; + + /* + * Read the latched byte, but turn off SPIOEN first + * so that we don't inadvertantly cause a REQ for the + * next byte. + */ + ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); + ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL); + msgdone = ahc_parse_msg(ahc, &devinfo); + if (msgdone == MSGLOOP_TERMINATED) { + /* + * The message is *really* done in that it caused + * us to go to bus free. The sequencer has already + * been reset at this point, so pull the ejection + * handle. + */ + return; + } + + ahc->msgin_index++; + + /* + * XXX Read spec about initiator dropping ATN too soon + * and use msgdone to detect it. + */ + if (msgdone == MSGLOOP_MSGCOMPLETE) { + ahc->msgin_index = 0; + + /* + * If this message illicited a response, transition + * to the Message in phase and send it. + */ + if (ahc->msgout_len != 0) { + ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO); + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | SPIOEN); + ahc->msg_type = MSG_TYPE_TARGET_MSGIN; + ahc->msgin_index = 0; + break; + } + } + + if (lastbyte) + end_session = TRUE; + else { + /* Ask for the next byte. */ + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | SPIOEN); + } + + break; + } + default: + panic("Unknown REQINIT message type"); + } + + if (end_session) { + ahc_clear_msg_state(ahc); + ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP); + } else + ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); +} + +/* + * See if we sent a particular extended message to the target. + * If "full" is true, return true only if the target saw the full + * message. If "full" is false, return true if the target saw at + * least the first byte of the message. + */ +static int +ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full) +{ + int found; + u_int index; + + found = FALSE; + index = 0; + + while (index < ahc->msgout_len) { + if (ahc->msgout_buf[index] == MSG_EXTENDED) { + u_int end_index; + + end_index = index + 1 + ahc->msgout_buf[index + 1]; + if (ahc->msgout_buf[index+2] == msgval + && type == AHCMSG_EXT) { + + if (full) { + if (ahc->msgout_index > end_index) + found = TRUE; + } else if (ahc->msgout_index > index) + found = TRUE; + } + index = end_index; + } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG + && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { + + /* Skip tag type and tag id or residue param*/ + index += 2; + } else { + /* Single byte message */ + if (type == AHCMSG_1B + && ahc->msgout_buf[index] == msgval + && ahc->msgout_index > index) + found = TRUE; + index++; + } + + if (found) + break; + } + return (found); +} + +/* + * Wait for a complete incomming message, parse it, and respond accordingly. + */ +static int +ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + int reject; + int done; + int response; + u_int targ_scsirate; + + done = MSGLOOP_IN_PROG; + response = FALSE; + reject = FALSE; + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, + devinfo->target, &tstate); + targ_scsirate = tinfo->scsirate; + + /* + * Parse as much of the message as is availible, + * rejecting it if we don't support it. When + * the entire message is availible and has been + * handled, return MSGLOOP_MSGCOMPLETE, indicating + * that we have parsed an entire message. + * + * In the case of extended messages, we accept the length + * byte outright and perform more checking once we know the + * extended message type. + */ + switch (ahc->msgin_buf[0]) { + case MSG_MESSAGE_REJECT: + response = ahc_handle_msg_reject(ahc, devinfo); + /* FALLTHROUGH */ + case MSG_NOOP: + done = MSGLOOP_MSGCOMPLETE; + break; + case MSG_EXTENDED: + { + /* Wait for enough of the message to begin validation */ + if (ahc->msgin_index < 2) + break; + switch (ahc->msgin_buf[2]) { + case MSG_EXT_SDTR: + { + struct ahc_syncrate *syncrate; + u_int period; + u_int ppr_options; + u_int offset; + u_int saved_offset; + + if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) { + reject = TRUE; + break; + } + + /* + * Wait until we have both args before validating + * and acting on this message. + * + * Add one to MSG_EXT_SDTR_LEN to account for + * the extended message preamble. + */ + if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1)) + break; + + period = ahc->msgin_buf[3]; + ppr_options = 0; + saved_offset = offset = ahc->msgin_buf[4]; + syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, + devinfo->role); + ahc_validate_offset(ahc, tinfo, syncrate, &offset, + targ_scsirate & WIDEXFER, + devinfo->role); + if (bootverbose) { + printf("(%s:%c:%d:%d): Received " + "SDTR period %x, offset %x\n\t" + "Filtered to period %x, offset %x\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun, + ahc->msgin_buf[3], saved_offset, + period, offset); + } + ahc_set_syncrate(ahc, devinfo, + syncrate, period, + offset, ppr_options, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + + /* + * See if we initiated Sync Negotiation + * and didn't have to fall down to async + * transfers. + */ + if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, TRUE)) { + /* We started it */ + if (saved_offset != offset) { + /* Went too low - force async */ + reject = TRUE; + } + } else { + /* + * Send our own SDTR in reply + */ + if (bootverbose) { + printf("(%s:%c:%d:%d): Target " + "Initiated SDTR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + } + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_construct_sdtr(ahc, devinfo, + period, offset); + ahc->msgout_index = 0; + response = TRUE; + } + done = MSGLOOP_MSGCOMPLETE; + break; + } + case MSG_EXT_WDTR: + { + u_int bus_width; + u_int saved_width; + u_int sending_reply; + + sending_reply = FALSE; + if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) { + reject = TRUE; + break; + } + + /* + * Wait until we have our arg before validating + * and acting on this message. + * + * Add one to MSG_EXT_WDTR_LEN to account for + * the extended message preamble. + */ + if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1)) + break; + + bus_width = ahc->msgin_buf[3]; + saved_width = bus_width; + ahc_validate_width(ahc, tinfo, &bus_width, + devinfo->role); + if (bootverbose) { + printf("(%s:%c:%d:%d): Received WDTR " + "%x filtered to %x\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun, + saved_width, bus_width); + } + + if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, TRUE)) { + /* + * Don't send a WDTR back to the + * target, since we asked first. + * If the width went higher than our + * request, reject it. + */ + if (saved_width > bus_width) { + reject = TRUE; + printf("(%s:%c:%d:%d): requested %dBit " + "transfers. Rejecting...\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun, + 8 * (0x01 << bus_width)); + bus_width = 0; + } + } else { + /* + * Send our own WDTR in reply + */ + if (bootverbose) { + printf("(%s:%c:%d:%d): Target " + "Initiated WDTR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + } + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_construct_wdtr(ahc, devinfo, bus_width); + ahc->msgout_index = 0; + response = TRUE; + sending_reply = TRUE; + } + ahc_set_width(ahc, devinfo, bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + /* After a wide message, we are async */ + ahc_set_syncrate(ahc, devinfo, + /*syncrate*/NULL, /*period*/0, + /*offset*/0, /*ppr_options*/0, + AHC_TRANS_ACTIVE, /*paused*/TRUE); + if (sending_reply == FALSE && reject == FALSE) { + + if (tinfo->goal.period) { + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_build_transfer_msg(ahc, devinfo); + ahc->msgout_index = 0; + response = TRUE; + } + } + done = MSGLOOP_MSGCOMPLETE; + break; + } + case MSG_EXT_PPR: + { + struct ahc_syncrate *syncrate; + u_int period; + u_int offset; + u_int bus_width; + u_int ppr_options; + u_int saved_width; + u_int saved_offset; + u_int saved_ppr_options; + + if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) { + reject = TRUE; + break; + } + + /* + * Wait until we have all args before validating + * and acting on this message. + * + * Add one to MSG_EXT_PPR_LEN to account for + * the extended message preamble. + */ + if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1)) + break; + + period = ahc->msgin_buf[3]; + offset = ahc->msgin_buf[5]; + bus_width = ahc->msgin_buf[6]; + saved_width = bus_width; + ppr_options = ahc->msgin_buf[7]; + /* + * According to the spec, a DT only + * period factor with no DT option + * set implies async. + */ + if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && period == 9) + offset = 0; + saved_ppr_options = ppr_options; + saved_offset = offset; + + /* + * Mask out any options we don't support + * on any controller. Transfer options are + * only available if we are negotiating wide. + */ + ppr_options &= MSG_EXT_PPR_DT_REQ; + if (bus_width == 0) + ppr_options = 0; + + ahc_validate_width(ahc, tinfo, &bus_width, + devinfo->role); + syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, + devinfo->role); + ahc_validate_offset(ahc, tinfo, syncrate, + &offset, bus_width, + devinfo->role); + + if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, TRUE)) { + /* + * If we are unable to do any of the + * requested options (we went too low), + * then we'll have to reject the message. + */ + if (saved_width > bus_width + || saved_offset != offset + || saved_ppr_options != ppr_options) { + reject = TRUE; + period = 0; + offset = 0; + bus_width = 0; + ppr_options = 0; + syncrate = NULL; + } + } else { + if (devinfo->role != ROLE_TARGET) + printf("(%s:%c:%d:%d): Target " + "Initiated PPR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + else + printf("(%s:%c:%d:%d): Initiator " + "Initiated PPR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_construct_ppr(ahc, devinfo, period, offset, + bus_width, ppr_options); + ahc->msgout_index = 0; + response = TRUE; + } + if (bootverbose) { + printf("(%s:%c:%d:%d): Received PPR width %x, " + "period %x, offset %x,options %x\n" + "\tFiltered to width %x, period %x, " + "offset %x, options %x\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun, + ahc->msgin_buf[3], saved_width, + saved_offset, saved_ppr_options, + bus_width, period, offset, ppr_options); + } + ahc_set_width(ahc, devinfo, bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + ahc_set_syncrate(ahc, devinfo, + syncrate, period, + offset, ppr_options, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + done = MSGLOOP_MSGCOMPLETE; + break; + } + default: + /* Unknown extended message. Reject it. */ + reject = TRUE; + break; + } + break; + } + case MSG_BUS_DEV_RESET: + ahc_handle_devreset(ahc, devinfo, + CAM_BDR_SENT, + "Bus Device Reset Received", + /*verbose_level*/0); + restart_sequencer(ahc); + done = MSGLOOP_TERMINATED; + break; + case MSG_ABORT_TAG: + case MSG_ABORT: + case MSG_CLEAR_QUEUE: +#ifdef AHC_TARGET_MODE + /* Target mode messages */ + if (devinfo->role != ROLE_TARGET) { + reject = TRUE; + break; + } + ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, + devinfo->lun, + ahc->msgin_buf[0] == MSG_ABORT_TAG + ? SCB_LIST_NULL + : ahc_inb(ahc, INITIATOR_TAG), + ROLE_TARGET, CAM_REQ_ABORTED); + + tstate = ahc->enabled_targets[devinfo->our_scsiid]; + if (tstate != NULL) { + struct tmode_lstate* lstate; + + lstate = tstate->enabled_luns[devinfo->lun]; + if (lstate != NULL) { + ahc_queue_lstate_event(ahc, lstate, + devinfo->our_scsiid, + ahc->msgin_buf[0], + /*arg*/0); + ahc_send_lstate_events(ahc, lstate); + } + } + done = MSGLOOP_MSGCOMPLETE; + break; +#endif + case MSG_TERM_IO_PROC: + default: + reject = TRUE; + break; + } + + if (reject) { + /* + * Setup to reject the message. + */ + ahc->msgout_index = 0; + ahc->msgout_len = 1; + ahc->msgout_buf[0] = MSG_MESSAGE_REJECT; + done = MSGLOOP_MSGCOMPLETE; + response = TRUE; + } + + if (done != MSGLOOP_IN_PROG && !response) + /* Clear the outgoing message buffer */ + ahc->msgout_len = 0; + + return (done); +} + +/* + * Process a message reject message. + */ +static int +ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + /* + * What we care about here is if we had an + * outstanding SDTR or WDTR message for this + * target. If we did, this is a signal that + * the target is refusing negotiation. + */ + struct scb *scb; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int scb_index; + u_int last_msg; + int response = 0; + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, + devinfo->our_scsiid, + devinfo->target, &tstate); + /* Might be necessary */ + last_msg = ahc_inb(ahc, LAST_MSG); + + if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) { + /* + * Target does not support the PPR message. + * Attempt to negotiate SPI-2 style. + */ + if (bootverbose) { + printf("(%s:%c:%d:%d): PPR Rejected. " + "Trying WDTR/SDTR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + } + tinfo->goal.ppr_options = 0; + tinfo->current.transport_version = 2; + tinfo->goal.transport_version = 2; + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_build_transfer_msg(ahc, devinfo); + ahc->msgout_index = 0; + response = 1; + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { + + /* note 8bit xfers */ + printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using " + "8bit transfers\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + /* + * No need to clear the sync rate. If the target + * did not accept the command, our syncrate is + * unaffected. If the target started the negotiation, + * but rejected our response, we already cleared the + * sync rate before sending our WDTR. + */ + if (tinfo->goal.period) { + + /* Start the sync negotiation */ + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_build_transfer_msg(ahc, devinfo); + ahc->msgout_index = 0; + response = 1; + } + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) { + /* note asynch xfers and clear flag */ + ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, /*period*/0, + /*offset*/0, /*ppr_options*/0, + AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, + /*paused*/TRUE); + printf("(%s:%c:%d:%d): refuses synchronous negotiation. " + "Using asynchronous transfers\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { + + printf("(%s:%c:%d:%d): refuses tagged commands. Performing " + "non-tagged I/O\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_tags(ahc, devinfo, FALSE); + + /* + * Resend the identify for this CCB as the target + * may believe that the selection is invalid otherwise. + */ + ahc_outb(ahc, SCB_CONTROL, + ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG); + scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; + ahc_set_transaction_tag(scb, /*enabled*/FALSE, + /*type*/MSG_SIMPLE_Q_TAG); + ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); + ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + + /* + * This transaction is now at the head of + * the untagged queue for this target. + */ + if ((ahc->flags & AHC_SCB_BTT) == 0) { + struct scb_tailq *untagged_q; + + untagged_q = + &(ahc->untagged_queues[devinfo->target_offset]); + TAILQ_INSERT_HEAD(untagged_q, scb, links.tqe); + scb->flags |= SCB_UNTAGGEDQ; + } + ahc_busy_tcl(ahc, BUILD_TCL(scb->hscb->scsiid, devinfo->lun), + scb->hscb->tag); + + /* + * Requeue all tagged commands for this target + * currently in our posession so they can be + * converted to untagged commands. + */ + ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL, + ROLE_INITIATOR, CAM_REQUEUE_REQ, + SEARCH_COMPLETE); + } else { + /* + * Otherwise, we ignore it. + */ + printf("%s:%c:%d: Message reject for %x -- ignored\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + last_msg); + } + return (response); +} + +/* + * Process an ingnore wide residue message. + */ +static void +ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + u_int scb_index; + struct scb *scb; + + scb_index = ahc_inb(ahc, SCB_TAG); + scb = ahc_lookup_scb(ahc, scb_index); + /* + * XXX Actually check data direction in the sequencer? + * Perhaps add datadir to some spare bits in the hscb? + */ + if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0 + || ahc_get_transfer_dir(scb) != CAM_DIR_IN) { + /* + * Ignore the message if we haven't + * seen an appropriate data phase yet. + */ + } else { + /* + * If the residual occurred on the last + * transfer and the transfer request was + * expected to end on an odd count, do + * nothing. Otherwise, subtract a byte + * and update the residual count accordingly. + */ + uint32_t sgptr; + + sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR); + if ((sgptr & SG_LIST_NULL) != 0 + && ahc_inb(ahc, DATA_COUNT_ODD) == 1) { + /* + * If the residual occurred on the last + * transfer and the transfer request was + * expected to end on an odd count, do + * nothing. + */ + } else { + struct ahc_dma_seg *sg; + uint32_t data_cnt; + uint32_t data_addr; + + /* Pull in the rest of the sgptr */ + sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8); + sgptr &= SG_PTR_MASK; + data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8) + | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT)); + + data_addr = (ahc_inb(ahc, SHADDR + 3) << 24) + | (ahc_inb(ahc, SHADDR + 2) << 16) + | (ahc_inb(ahc, SHADDR + 1) << 8) + | (ahc_inb(ahc, SHADDR)); + + data_cnt += 1; + data_addr -= 1; + + sg = ahc_sg_bus_to_virt(scb, sgptr); + /* + * The residual sg ptr points to the next S/G + * to load so we must go back one. + */ + sg--; + if (sg != scb->sg_list + && (sg->len & AHC_SG_LEN_MASK) < data_cnt) { + + sg--; + data_cnt = 1 | (sg->len & AHC_DMA_LAST_SEG); + data_addr = sg->addr + + (sg->len & AHC_SG_LEN_MASK) - 1; + + /* + * Increment sg so it points to the + * "next" sg. + */ + sg++; + sgptr = ahc_sg_virt_to_bus(scb, sg); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3, + sgptr >> 24); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2, + sgptr >> 16); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1, + sgptr >> 8); + ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr); + } + +/* XXX What about high address byte??? */ + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8); + ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt); + +/* XXX Perhaps better to just keep the saved address in sram */ + if ((ahc->features & AHC_ULTRA2) != 0) { + ahc_outb(ahc, HADDR + 3, data_addr >> 24); + ahc_outb(ahc, HADDR + 2, data_addr >> 16); + ahc_outb(ahc, HADDR + 1, data_addr >> 8); + ahc_outb(ahc, HADDR, data_addr); + ahc_outb(ahc, DFCNTRL, PRELOADEN); + ahc_outb(ahc, SXFRCTL0, + ahc_inb(ahc, SXFRCTL0) | CLRCHN); + } else { + ahc_outb(ahc, HADDR + 3, data_addr >> 24); + ahc_outb(ahc, HADDR + 2, data_addr >> 16); + ahc_outb(ahc, HADDR + 1, data_addr >> 8); + ahc_outb(ahc, HADDR, data_addr); + } + } + } +} + +/* + * Handle the effects of issuing a bus device reset message. + */ +static void +ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + cam_status status, char *message, int verbose_level) +{ +#ifdef AHC_TARGET_MODE + struct tmode_tstate* tstate; + u_int lun; +#endif + int found; + + found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, + CAM_LUN_WILDCARD, SCB_LIST_NULL, devinfo->role, + status); + +#ifdef AHC_TARGET_MODE + /* + * Send an immediate notify ccb to all target mord peripheral + * drivers affected by this action. + */ + tstate = ahc->enabled_targets[devinfo->our_scsiid]; + if (tstate != NULL) { + for (lun = 0; lun < AHC_NUM_LUNS; lun++) { + struct tmode_lstate* lstate; + + lstate = tstate->enabled_luns[lun]; + if (lstate == NULL) + continue; + + ahc_queue_lstate_event(ahc, lstate, devinfo->our_scsiid, + MSG_BUS_DEV_RESET, /*arg*/0); + ahc_send_lstate_events(ahc, lstate); + } + } +#endif + + /* + * Go back to async/narrow transfers and renegotiate. + */ + ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_CUR, /*paused*/TRUE); + ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, + /*period*/0, /*offset*/0, /*ppr_options*/0, + AHC_TRANS_CUR, /*paused*/TRUE); + + ahc_send_async(ahc, devinfo->channel, devinfo->target, + CAM_LUN_WILDCARD, AC_SENT_BDR); + + if (message != NULL + && (verbose_level <= bootverbose)) + printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc), + message, devinfo->channel, devinfo->target, found); +} + +#ifdef AHC_TARGET_MODE +void +ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) +{ + /* + * To facilitate adding multiple messages together, + * each routine should increment the index and len + * variables instead of setting them explicitly. + */ + ahc->msgout_index = 0; + ahc->msgout_len = 0; + + if ((ahc->targ_msg_req & devinfo->target_mask) != 0) + ahc_build_transfer_msg(ahc, devinfo); + else + panic("ahc_intr: AWAITING target message with no message"); + + ahc->msgout_index = 0; + ahc->msg_type = MSG_TYPE_TARGET_MSGIN; +} +#endif +/**************************** Initialization **********************************/ +/* + * Allocate a controller structure for a new device + * and perform initial initializion. + */ +struct ahc_softc * +ahc_alloc(void *platform_arg, char *name) +{ + struct ahc_softc *ahc; + int i; + +#ifndef __FreeBSD__ + ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT); + if (!ahc) { + printf("aic7xxx: cannot malloc softc!\n"); + free(name, M_DEVBUF); + return NULL; + } +#else + ahc = device_get_softc((device_t)platform_arg); +#endif + memset(ahc, 0, sizeof(*ahc)); + LIST_INIT(&ahc->pending_scbs); + /* We don't know our unit number until the OSM sets it */ + ahc->name = name; + for (i = 0; i < 16; i++) + TAILQ_INIT(&ahc->untagged_queues[i]); + if (ahc_platform_alloc(ahc, platform_arg) != 0) { + ahc_free(ahc); + ahc = NULL; + } + return (ahc); +} + +int +ahc_softc_init(struct ahc_softc *ahc, struct ahc_probe_config *config) +{ + + ahc->chip = config->chip; + ahc->features = config->features; + ahc->bugs = config->bugs; + ahc->flags = config->flags; + ahc->channel = config->channel; + ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; + ahc->description = config->description; + /* The IRQMS bit is only valid on VL and EISA chips */ + if ((ahc->chip & AHC_PCI) != 0) + ahc->unpause &= ~IRQMS; + ahc->pause = ahc->unpause | PAUSE; + /* XXX The shared scb data stuff should be depricated */ + if (ahc->scb_data == NULL) { + ahc->scb_data = malloc(sizeof(*ahc->scb_data), + M_DEVBUF, M_NOWAIT); + if (ahc->scb_data == NULL) + return (ENOMEM); + memset(ahc->scb_data, 0, sizeof(*ahc->scb_data)); + } + + return (0); +} + +void +ahc_softc_insert(struct ahc_softc *ahc) +{ + struct ahc_softc *list_ahc; + +#ifdef AHC_SUPPORT_PCI + /* + * Second Function PCI devices need to inherit some + * settings from function 0. We assume that function 0 + * will always be found prior to function 1. + */ + if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI + && ahc_get_pci_function(ahc->dev_softc) == 1) { + TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { + ahc_dev_softc_t list_pci; + ahc_dev_softc_t pci; + + list_pci = list_ahc->dev_softc; + pci = ahc->dev_softc; + if (ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci) + && ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) + && ahc_get_pci_function(list_pci) == 0) { + ahc->flags &= ~AHC_BIOS_ENABLED; + ahc->flags |= + list_ahc->flags & AHC_BIOS_ENABLED; + ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; + ahc->flags |= + list_ahc->flags & AHC_CHANNEL_B_PRIMARY; + break; + } + } + } +#endif + + /* + * Insertion sort into our list of softcs. + */ + list_ahc = TAILQ_FIRST(&ahc_tailq); + while (list_ahc != NULL + && ahc_softc_comp(list_ahc, ahc) <= 0) + list_ahc = TAILQ_NEXT(list_ahc, links); + if (list_ahc != NULL) + TAILQ_INSERT_BEFORE(list_ahc, ahc, links); + else + TAILQ_INSERT_TAIL(&ahc_tailq, ahc, links); + ahc->init_level++; +} + +void +ahc_set_unit(struct ahc_softc *ahc, int unit) +{ + ahc->unit = unit; +} + +void +ahc_set_name(struct ahc_softc *ahc, char *name) +{ + if (ahc->name != NULL) + free(ahc->name, M_DEVBUF); + ahc->name = name; +} + +void +ahc_free(struct ahc_softc *ahc) +{ + int i; + + ahc_fini_scbdata(ahc); + switch (ahc->init_level) { + default: + case 5: + ahc_shutdown(ahc); + TAILQ_REMOVE(&ahc_tailq, ahc, links); + /* FALLTHROUGH */ + case 4: + ahc_dmamap_unload(ahc, ahc->shared_data_dmat, + ahc->shared_data_dmamap); + /* FALLTHROUGH */ + case 3: + ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo, + ahc->shared_data_dmamap); + ahc_dmamap_destroy(ahc, ahc->shared_data_dmat, + ahc->shared_data_dmamap); + /* FALLTHROUGH */ + case 2: + ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat); + case 1: +#ifndef __linux__ + ahc_dma_tag_destroy(ahc, ahc->buffer_dmat); +#endif + break; + case 0: + break; + } + +#ifndef __linux__ + ahc_dma_tag_destroy(ahc, ahc->parent_dmat); +#endif + ahc_platform_free(ahc); + for (i = 0; i < AHC_NUM_TARGETS; i++) { + struct tmode_tstate *tstate; + + tstate = ahc->enabled_targets[i]; + if (tstate != NULL) { +#if AHC_TARGET_MODE + int j; + + for (j = 0; j < AHC_NUM_LUNS; j++) { + struct tmode_lstate *lstate; + + lstate = tstate->enabled_luns[j]; + if (lstate != NULL) { + xpt_free_path(lstate->path); + free(lstate, M_DEVBUF); + } + } +#endif + free(tstate, M_DEVBUF); + } + } +#if AHC_TARGET_MODE + if (ahc->black_hole != NULL) { + xpt_free_path(ahc->black_hole->path); + free(ahc->black_hole, M_DEVBUF); + } +#endif + if (ahc->name != NULL) + free(ahc->name, M_DEVBUF); +#ifndef __FreeBSD__ + free(ahc, M_DEVBUF); +#endif + return; +} + +void +ahc_shutdown(void *arg) +{ + struct ahc_softc *ahc; + int i; + + ahc = (struct ahc_softc *)arg; + + /* This will reset most registers to 0, but not all */ + ahc_reset(ahc); + ahc_outb(ahc, SCSISEQ, 0); + ahc_outb(ahc, SXFRCTL0, 0); + ahc_outb(ahc, DSPCISTATUS, 0); + + for (i = TARG_SCSIRATE; i < HA_274_BIOSCTRL; i++) + ahc_outb(ahc, i, 0); +} + +/* + * Reset the controller and record some information about it + * that is only availabel just after a reset. + */ +int +ahc_reset(struct ahc_softc *ahc) +{ + u_int sblkctl; + u_int sxfrctl1_a, sxfrctl1_b; + int wait; + + /* + * Preserve the value of the SXFRCTL1 register for all channels. + * It contains settings that affect termination and we don't want + * to disturb the integrity of the bus. + */ + pause_sequencer(ahc); + sxfrctl1_b = 0; + if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { + u_int sblkctl; + + /* + * Save channel B's settings in case this chip + * is setup for TWIN channel operation. + */ + sblkctl = ahc_inb(ahc, SBLKCTL); + ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB); + sxfrctl1_b = ahc_inb(ahc, SXFRCTL1); + ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB); + } + sxfrctl1_a = ahc_inb(ahc, SXFRCTL1); + + ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause); + + /* + * Ensure that the reset has finished + */ + wait = 1000; + do { + ahc_delay(1000); + } while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK)); + + if (wait == 0) { + printf("%s: WARNING - Failed chip reset! " + "Trying to initialize anyway.\n", ahc_name(ahc)); + } + ahc_outb(ahc, HCNTRL, ahc->pause); + + /* Determine channel configuration */ + sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE); + /* No Twin Channel PCI cards */ + if ((ahc->chip & AHC_PCI) != 0) + sblkctl &= ~SELBUSB; + switch (sblkctl) { + case 0: + /* Single Narrow Channel */ + break; + case 2: + /* Wide Channel */ + ahc->features |= AHC_WIDE; + break; + case 8: + /* Twin Channel */ + ahc->features |= AHC_TWIN; + break; + default: + printf(" Unsupported adapter type. Ignoring\n"); + return(-1); + } + + /* + * Reload sxfrctl1. + * + * We must always initialize STPWEN to 1 before we + * restore the saved values. STPWEN is initialized + * to a tri-state condition which can only be cleared + * by turning it on. + */ + if ((ahc->features & AHC_TWIN) != 0) { + u_int sblkctl; + + sblkctl = ahc_inb(ahc, SBLKCTL); + ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB); + ahc_outb(ahc, SXFRCTL1, sxfrctl1_b); + ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB); + } + ahc_outb(ahc, SXFRCTL1, sxfrctl1_a); + +#ifdef AHC_DUMP_SEQ + if (ahc->init_level == 0) + ahc_dumpseq(ahc); +#endif + + return (0); +} + +/* + * Determine the number of SCBs available on the controller + */ +int +ahc_probe_scbs(struct ahc_softc *ahc) { + int i; + + for (i = 0; i < AHC_SCB_MAX; i++) { + + ahc_outb(ahc, SCBPTR, i); + ahc_outb(ahc, SCB_BASE, i); + if (ahc_inb(ahc, SCB_BASE) != i) + break; + ahc_outb(ahc, SCBPTR, 0); + if (ahc_inb(ahc, SCB_BASE) != 0) + break; + } + return (i); +} + +void +ahc_init_probe_config(struct ahc_probe_config *probe_config) +{ + probe_config->description = NULL; + probe_config->channel = 'A'; + probe_config->channel_b = 'B'; + probe_config->chip = AHC_NONE; + probe_config->features = AHC_FENONE; + probe_config->bugs = AHC_BUGNONE; + probe_config->flags = AHC_FNONE; +} + +static void +ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + bus_addr_t *baddr; + + baddr = (bus_addr_t *)arg; + *baddr = segs->ds_addr; +} + +static void +ahc_build_free_scb_list(struct ahc_softc *ahc) +{ + int i; + + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + ahc_outb(ahc, SCBPTR, i); + + /* Clear the control byte. */ + ahc_outb(ahc, SCB_CONTROL, 0); + + /* Set the next pointer */ + if ((ahc->flags & AHC_PAGESCBS) != 0) + ahc_outb(ahc, SCB_NEXT, i+1); + else + ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); + + /* Make the tag number invalid */ + ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); + } + + /* Make sure that the last SCB terminates the free list */ + ahc_outb(ahc, SCBPTR, i-1); + ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); + + /* Ensure we clear the 0 SCB's control byte. */ + ahc_outb(ahc, SCBPTR, 0); + ahc_outb(ahc, SCB_CONTROL, 0); +} + +static int +ahc_init_scbdata(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + + scb_data = ahc->scb_data; + SLIST_INIT(&scb_data->free_scbs); + SLIST_INIT(&scb_data->sg_maps); + + /* Allocate SCB resources */ + scb_data->scbarray = + (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX, + M_DEVBUF, M_NOWAIT); + if (scb_data->scbarray == NULL) + return (ENOMEM); + memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX); + + /* Determine the number of hardware SCBs and initialize them */ + + scb_data->maxhscbs = ahc_probe_scbs(ahc); + if ((ahc->flags & AHC_PAGESCBS) != 0) { + /* SCB 0 heads the free list */ + ahc_outb(ahc, FREE_SCBH, 0); + } else { + ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL); + } + + if (ahc->scb_data->maxhscbs == 0) { + printf("%s: No SCB space found\n", ahc_name(ahc)); + return (ENXIO); + } + + ahc_build_free_scb_list(ahc); + + /* + * Create our DMA tags. These tags define the kinds of device + * accessible memory allocations and memory mappings we will + * need to perform during normal operation. + * + * Unless we need to further restrict the allocation, we rely + * on the restrictions of the parent dmat, hence the common + * use of MAXADDR and MAXSIZE. + */ + + /* DMA tag for our hardware scb structures */ + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + AHC_SCB_MAX * sizeof(struct hardware_scb), + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->hscb_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Allocation for our ccbs */ + if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat, + (void **)&scb_data->hscbs, + BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* And permanently map them */ + ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap, + scb_data->hscbs, + AHC_SCB_MAX * sizeof(struct hardware_scb), + ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0); + + scb_data->init_level++; + + /* DMA tag for our sense buffers */ + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + AHC_SCB_MAX * sizeof(struct scsi_sense_data), + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->sense_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Allocate them */ + if (ahc_dmamem_alloc(ahc, scb_data->sense_dmat, + (void **)&scb_data->sense, + BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* And permanently map them */ + ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap, + scb_data->sense, + AHC_SCB_MAX * sizeof(struct scsi_sense_data), + ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0); + + scb_data->init_level++; + + /* DMA tag for our S/G structures. We allocate in page sized chunks */ + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + PAGE_SIZE, /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->sg_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Perform initial CCB allocation */ + memset(scb_data->hscbs, 0, AHC_SCB_MAX * sizeof(struct hardware_scb)); + ahc_alloc_scbs(ahc); + + if (scb_data->numscbs == 0) { + printf("%s: ahc_init_scbdata - " + "Unable to allocate initial scbs\n", + ahc_name(ahc)); + goto error_exit; + } + + /* + * Tell the sequencer which SCB will be the next one it receives. + */ + ahc->next_queued_scb = ahc_get_scb(ahc); + ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); + + /* + * Note that we were successfull + */ + return (0); + +error_exit: + + return (ENOMEM); +} + +static void +ahc_fini_scbdata(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + + scb_data = ahc->scb_data; + if (scb_data == NULL) + return; + + switch (scb_data->init_level) { + default: + case 7: + { + struct sg_map_node *sg_map; + + while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) { + SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); + ahc_dmamap_unload(ahc, scb_data->sg_dmat, + sg_map->sg_dmamap); + ahc_dmamem_free(ahc, scb_data->sg_dmat, + sg_map->sg_vaddr, + sg_map->sg_dmamap); + free(sg_map, M_DEVBUF); + } + ahc_dma_tag_destroy(ahc, scb_data->sg_dmat); + } + case 6: + ahc_dmamap_unload(ahc, scb_data->sense_dmat, + scb_data->sense_dmamap); + case 5: + ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense, + scb_data->sense_dmamap); + ahc_dmamap_destroy(ahc, scb_data->sense_dmat, + scb_data->sense_dmamap); + case 4: + ahc_dma_tag_destroy(ahc, scb_data->sense_dmat); + case 3: + ahc_dmamap_unload(ahc, scb_data->hscb_dmat, + scb_data->hscb_dmamap); + case 2: + ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs, + scb_data->hscb_dmamap); + ahc_dmamap_destroy(ahc, scb_data->hscb_dmat, + scb_data->hscb_dmamap); + case 1: + ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat); + break; + case 0: + break; + } + if (scb_data->scbarray != NULL) + free(scb_data->scbarray, M_DEVBUF); +} + +void +ahc_alloc_scbs(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + struct scb *next_scb; + struct sg_map_node *sg_map; + bus_addr_t physaddr; + struct ahc_dma_seg *segs; + int newcount; + int i; + + scb_data = ahc->scb_data; + if (scb_data->numscbs >= AHC_SCB_MAX) + /* Can't allocate any more */ + return; + + next_scb = &scb_data->scbarray[scb_data->numscbs]; + + sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); + + if (sg_map == NULL) + return; + + /* Allocate S/G space for the next batch of SCBS */ + if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat, + (void **)&sg_map->sg_vaddr, + BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { + free(sg_map, M_DEVBUF); + return; + } + + SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); + + ahc_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap, + sg_map->sg_vaddr, PAGE_SIZE, ahc_dmamap_cb, + &sg_map->sg_physaddr, /*flags*/0); + + segs = sg_map->sg_vaddr; + physaddr = sg_map->sg_physaddr; + + newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg))); + for (i = 0; scb_data->numscbs < AHC_SCB_MAX && i < newcount; i++) { + struct scb_platform_data *pdata; +#ifndef __linux__ + int error; +#endif + pdata = (struct scb_platform_data *)malloc(sizeof(*pdata), + M_DEVBUF, M_NOWAIT); + if (pdata == NULL) + break; + next_scb->platform_data = pdata; + next_scb->sg_list = segs; + /* + * The sequencer always starts with the second entry. + * The first entry is embedded in the scb. + */ + next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg); + next_scb->ahc_softc = ahc; + next_scb->flags = SCB_FREE; +#ifndef __linux__ + error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0, + &next_scb->dmamap); + if (error != 0) + break; +#endif + next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; + next_scb->hscb->tag = ahc->scb_data->numscbs; + SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, + next_scb, links.sle); + segs += AHC_NSEG; + physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg)); + next_scb++; + ahc->scb_data->numscbs++; + } +} + +void +ahc_controller_info(struct ahc_softc *ahc, char *buf) +{ + int len; + + len = sprintf(buf, "%s: ", ahc_chip_names[ahc->chip & AHC_CHIPID_MASK]); + buf += len; + if ((ahc->features & AHC_TWIN) != 0) + len = sprintf(buf, "Twin Channel, A SCSI Id=%d, " + "B SCSI Id=%d, primary %c, ", + ahc->our_id, ahc->our_id_b, + ahc->flags & AHC_CHANNEL_B_PRIMARY ? 'B': 'A'); + else { + const char *type; + + if ((ahc->features & AHC_WIDE) != 0) { + type = "Wide"; + } else { + type = "Single"; + } + len = sprintf(buf, "%s Channel %c, SCSI Id=%d, ", + type, ahc->channel, ahc->our_id); + } + buf += len; + + if ((ahc->flags & AHC_PAGESCBS) != 0) + sprintf(buf, "%d/%d SCBs", + ahc->scb_data->maxhscbs, AHC_SCB_MAX); + else + sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs); +} + +/* + * Start the board, ready for normal operation + */ +int +ahc_init(struct ahc_softc *ahc) +{ + int max_targ; + int i; + int term; + u_int scsi_conf; + u_int scsiseq_template; + u_int ultraenb; + u_int discenable; + u_int tagenable; + size_t driver_data_size; + uint32_t physaddr; + +#ifdef AHC_DEBUG_SEQUENCER + ahc->flags |= AHC_SEQUENCER_DEBUG; +#endif + +#ifdef AHC_PRINT_SRAM + printf("Scratch Ram:"); + for (i = 0x20; i < 0x5f; i++) { + if (((i % 8) == 0) && (i != 0)) { + printf ("\n "); + } + printf (" 0x%x", ahc_inb(ahc, i)); + } + if ((ahc->features & AHC_MORE_SRAM) != 0) { + for (i = 0x70; i < 0x7f; i++) { + if (((i % 8) == 0) && (i != 0)) { + printf ("\n "); + } + printf (" 0x%x", ahc_inb(ahc, i)); + } + } + printf ("\n"); +#endif + max_targ = 15; + + /* + * Assume we have a board at this stage and it has been reset. + */ + if ((ahc->flags & AHC_USEDEFAULTS) != 0) + ahc->our_id = ahc->our_id_b = 7; + + /* + * Default to allowing initiator operations. + */ + ahc->flags |= AHC_INITIATORROLE; + + /* + * Only allow target mode features if this unit has them enabled. + */ + if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0) + ahc->features &= ~AHC_TARGETMODE; + +#ifndef __linux__ + /* DMA tag for mapping buffers into device visible space. */ + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG, + /*maxsegsz*/AHC_MAXTRANSFER_SIZE, + /*flags*/BUS_DMA_ALLOCNOW, + &ahc->buffer_dmat) != 0) { + return (ENOMEM); + } +#endif + + ahc->init_level++; + + /* + * DMA tag for our command fifos and other data in system memory + * the card's sequencer must be able to access. For initiator + * roles, we need to allocate space for the the qinfifo and qoutfifo. + * The qinfifo and qoutfifo are composed of 256 1 byte elements. + * When providing for the target mode role, we must additionally + * provide space for the incoming target command fifo and an extra + * byte to deal with a dma bug in some chip versions. + */ + driver_data_size = 2 * 256 * sizeof(uint8_t); + if ((ahc->features & AHC_TARGETMODE) != 0) + driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd) + + /*DMA WideOdd Bug Buffer*/1; + if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + driver_data_size, + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &ahc->shared_data_dmat) != 0) { + return (ENOMEM); + } + + ahc->init_level++; + + /* Allocation of driver data */ + if (ahc_dmamem_alloc(ahc, ahc->shared_data_dmat, + (void **)&ahc->qoutfifo, + BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) { + return (ENOMEM); + } + + ahc->init_level++; + + /* And permanently map it in */ + ahc_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, + ahc->qoutfifo, driver_data_size, ahc_dmamap_cb, + &ahc->shared_data_busaddr, /*flags*/0); + + if ((ahc->features & AHC_TARGETMODE) != 0) { + ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo; + ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[AHC_TMODE_CMDS]; + ahc->dma_bug_buf = ahc->shared_data_busaddr + + driver_data_size - 1; + /* All target command blocks start out invalid. */ + for (i = 0; i < AHC_TMODE_CMDS; i++) + ahc->targetcmds[i].cmd_valid = 0; + ahc->tqinfifonext = 1; + ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); + ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); + ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256]; + } + ahc->qinfifo = &ahc->qoutfifo[256]; + + ahc->init_level++; + + /* Allocate SCB data now that buffer_dmat is initialized */ + if (ahc->scb_data->maxhscbs == 0) + if (ahc_init_scbdata(ahc) != 0) + return (ENOMEM); + + /* + * Allocate a tstate to house information for our + * initiator presence on the bus as well as the user + * data for any target mode initiator. + */ + if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { + printf("%s: unable to allocate tmode_tstate. " + "Failing attach\n", ahc_name(ahc)); + return (-1); + } + + if ((ahc->features & AHC_TWIN) != 0) { + if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { + printf("%s: unable to allocate tmode_tstate. " + "Failing attach\n", ahc_name(ahc)); + return (-1); + } + } + + ahc_outb(ahc, SEQ_FLAGS, 0); + ahc_outb(ahc, SEQ_FLAGS2, 0); + + if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) { + ahc->flags |= AHC_PAGESCBS; + } else { + ahc->flags &= ~AHC_PAGESCBS; + } + +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWMISC) { + printf("%s: hardware scb %d bytes; kernel scb %d bytes; " + "ahc_dma %d bytes\n", + ahc_name(ahc), + sizeof(struct hardware_scb), + sizeof(struct scb), + sizeof(struct ahc_dma_seg)); + } +#endif /* AHC_DEBUG */ + + /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/ + if (ahc->features & AHC_TWIN) { + + /* + * The device is gated to channel B after a chip reset, + * so set those values first + */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); + term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0; + ahc_outb(ahc, SCSIID, ahc->our_id_b); + scsi_conf = ahc_inb(ahc, SCSICONF + 1); + ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) + |term|ahc->seltime_b|ENSTIMER|ACTNEGEN); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); + ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); + ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); + + if ((scsi_conf & RESET_SCSI) != 0 + && (ahc->flags & AHC_INITIATORROLE) != 0) + ahc->flags |= AHC_RESET_BUS_B; + + /* Select Channel A */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); + } + term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0; + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); + else + ahc_outb(ahc, SCSIID, ahc->our_id); + scsi_conf = ahc_inb(ahc, SCSICONF); + ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) + |term|ahc->seltime + |ENSTIMER|ACTNEGEN); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); + ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); + ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); + + if ((scsi_conf & RESET_SCSI) != 0 + && (ahc->flags & AHC_INITIATORROLE) != 0) + ahc->flags |= AHC_RESET_BUS_A; + + /* + * Look at the information that board initialization or + * the board bios has left us. + */ + ultraenb = 0; + tagenable = ALL_TARGETS_MASK; + + /* Grab the disconnection disable table and invert it for our needs */ + if (ahc->flags & AHC_USEDEFAULTS) { + printf("%s: Host Adapter Bios disabled. Using default SCSI " + "device parameters\n", ahc_name(ahc)); + ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B| + AHC_TERM_ENB_A|AHC_TERM_ENB_B; + discenable = ALL_TARGETS_MASK; + if ((ahc->features & AHC_ULTRA) != 0) + ultraenb = ALL_TARGETS_MASK; + } else { + discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) + | ahc_inb(ahc, DISC_DSB)); + if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0) + ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8) + | ahc_inb(ahc, ULTRA_ENB); + } + if ((ahc->flags & AHC_ULTRA_DISABLED) != 0) + ultraenb = 0; + + if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) + max_targ = 7; + + for (i = 0; i <= max_targ; i++) { + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int our_id; + u_int target_id; + char channel; + + channel = 'A'; + our_id = ahc->our_id; + target_id = i; + if (i > 7 && (ahc->features & AHC_TWIN) != 0) { + channel = 'B'; + our_id = ahc->our_id_b; + target_id = i % 8; + } + tinfo = ahc_fetch_transinfo(ahc, channel, our_id, + target_id, &tstate); + /* Default to async narrow across the board */ + memset(tinfo, 0, sizeof(*tinfo)); + if (ahc->flags & AHC_USEDEFAULTS) { + if ((ahc->features & AHC_WIDE) != 0) + tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; + + /* + * These will be truncated when we determine the + * connection type we have with the target. + */ + tinfo->user.period = ahc_syncrates->period; + tinfo->user.offset = ~0; + } else { + u_int scsirate; + uint16_t mask; + + /* Take the settings leftover in scratch RAM. */ + scsirate = ahc_inb(ahc, TARG_SCSIRATE + i); + mask = (0x01 << i); + if ((ahc->features & AHC_ULTRA2) != 0) { + u_int offset; + u_int maxsync; + + if ((scsirate & SOFS) == 0x0F) { + /* + * Haven't negotiated yet, + * so the format is different. + */ + scsirate = (scsirate & SXFR) >> 4 + | (ultraenb & mask) + ? 0x08 : 0x0 + | (scsirate & WIDEXFER); + offset = MAX_OFFSET_ULTRA2; + } else + offset = ahc_inb(ahc, TARG_OFFSET + i); + if ((scsirate & ~WIDEXFER) == 0 && offset != 0) + /* Set to the lowest sync rate, 5MHz */ + scsirate |= 0x1c; + maxsync = AHC_SYNCRATE_ULTRA2; + if ((ahc->features & AHC_DT) != 0) + maxsync = AHC_SYNCRATE_DT; + tinfo->user.period = + ahc_find_period(ahc, scsirate, maxsync); + if (offset == 0) + tinfo->user.period = 0; + else + tinfo->user.offset = ~0; + if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/ + && (ahc->features & AHC_DT) != 0) + tinfo->user.ppr_options = + MSG_EXT_PPR_DT_REQ; + } else if ((scsirate & SOFS) != 0) { + if ((scsirate & SXFR) == 0x40 + && (ultraenb & mask) != 0) { + /* Treat 10MHz as a non-ultra speed */ + scsirate &= ~SXFR; + ultraenb &= ~mask; + } + tinfo->user.period = + ahc_find_period(ahc, scsirate, + (ultraenb & mask) + ? AHC_SYNCRATE_ULTRA + : AHC_SYNCRATE_FAST); + if (tinfo->user.period != 0) + tinfo->user.offset = ~0; + } + if (tinfo->user.period == 0) + tinfo->user.offset = 0; + if ((scsirate & WIDEXFER) != 0 + && (ahc->features & AHC_WIDE) != 0) + tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; + tinfo->user.protocol_version = 4; + if ((ahc->features & AHC_DT) != 0) + tinfo->user.transport_version = 3; + else + tinfo->user.transport_version = 2; + tinfo->goal.protocol_version = 2; + tinfo->goal.transport_version = 2; + tinfo->current.protocol_version = 2; + tinfo->current.transport_version = 2; + } + tstate->ultraenb = ultraenb; + tstate->discenable = discenable; + tstate->tagenable = 0; /* Wait until the XPT says its okay */ + } + ahc->user_discenable = discenable; + ahc->user_tagenable = tagenable; + + /* There are no untagged SCBs active yet. */ + for (i = 0; i < 16; i++) { + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0)); + if ((ahc->flags & AHC_SCB_BTT) != 0) { + int lun; + + /* + * The SCB based BTT allows an entry per + * target and lun pair. + */ + for (lun = 1; lun < AHC_NUM_LUNS; lun++) + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun)); + } + } + + /* All of our queues are empty */ + for (i = 0; i < 256; i++) + ahc->qoutfifo[i] = SCB_LIST_NULL; + + for (i = 0; i < 256; i++) + ahc->qinfifo[i] = SCB_LIST_NULL; + + if ((ahc->features & AHC_MULTI_TID) != 0) { + ahc_outb(ahc, TARGID, 0); + ahc_outb(ahc, TARGID + 1, 0); + } + + /* + * Tell the sequencer where it can find our arrays in memory. + */ + physaddr = ahc->scb_data->hscb_busaddr; + ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); + + physaddr = ahc->shared_data_busaddr; + ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF); + + /* + * Initialize the group code to command length table. + * This overrides the values in TARG_SCSIRATE, so only + * setup the table after we have processed that information. + */ + ahc_outb(ahc, CMDSIZE_TABLE, 5); + ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); + ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); + ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); + ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); + ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); + ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); + ahc_outb(ahc, CMDSIZE_TABLE + 7, 0); + + /* Tell the sequencer of our initial queue positions */ + ahc_outb(ahc, KERNEL_QINPOS, 0); + ahc_outb(ahc, QINPOS, 0); + ahc_outb(ahc, QOUTPOS, 0); + + /* Don't have any special messages to send to targets */ + ahc_outb(ahc, TARGET_MSG_REQUEST, 0); + ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0); + + /* + * Use the built in queue management registers + * if they are available. + */ + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256); + ahc_outb(ahc, SDSCB_QOFF, 0); + ahc_outb(ahc, SNSCB_QOFF, 0); + ahc_outb(ahc, HNSCB_QOFF, 0); + } + + + /* We don't have any waiting selections */ + ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL); + + /* Our disconnection list is empty too */ + ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL); + + /* Message out buffer starts empty */ + ahc_outb(ahc, MSG_OUT, MSG_NOOP); + + /* + * Setup the allowed SCSI Sequences based on operational mode. + * If we are a target, we'll enalbe select in operations once + * we've had a lun enabled. + */ + scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; + if ((ahc->flags & AHC_INITIATORROLE) != 0) + scsiseq_template |= ENRSELI; + ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template); + + /* + * Load the Sequencer program and Enable the adapter + * in "fast" mode. + */ + if (bootverbose) + printf("%s: Downloading Sequencer Program...", + ahc_name(ahc)); + + ahc_loadseq(ahc); + + if ((ahc->features & AHC_ULTRA2) != 0) { + int wait; + + /* + * Wait for up to 500ms for our transceivers + * to settle. If the adapter does not have + * a cable attached, the tranceivers may + * never settle, so don't complain if we + * fail here. + */ + pause_sequencer(ahc); + for (wait = 5000; + (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; + wait--) + ahc_delay(100); + unpause_sequencer(ahc); + } + return (0); +} + +/* + * Ensure that the card is paused in a location + * outside of all critical sections and that all + * pending work is completed prior to returning. + * This routine should only be called from outside + * an interrupt context. + */ +void +ahc_pause_and_flushwork(struct ahc_softc *ahc) +{ + int intstat; + int maxloops; + + maxloops = 1000; + ahc->flags |= AHC_ALL_INTERRUPTS; + intstat = 0; + do { + ahc_intr(ahc); + pause_sequencer(ahc); + ahc_clear_critical_section(ahc); + if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) + break; + maxloops--; + } while (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) && --maxloops); + if (maxloops == 0) { + printf("Infinite interrupt loop, INTSTAT = %x", + ahc_inb(ahc, INTSTAT)); + } + ahc_platform_flushwork(ahc); + ahc->flags &= ~AHC_ALL_INTERRUPTS; +} + +int +ahc_suspend(struct ahc_softc *ahc) +{ + uint8_t *ptr; + int i; + + ahc_pause_and_flushwork(ahc); + + if (LIST_FIRST(&ahc->pending_scbs) != NULL) + return (EBUSY); + +#if AHC_TARGET_MODE + /* + * XXX What about ATIOs that have not yet been serviced? + * Perhaps we should just refuse to be suspended if we + * are acting in a target role. + */ + if (ahc->pending_device != NULL) + return (EBUSY); +#endif + + /* Save volatile registers */ + if ((ahc->features & AHC_TWIN) != 0) { + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); + ahc->suspend_state.channel[1].scsiseq = ahc_inb(ahc, SCSISEQ); + ahc->suspend_state.channel[1].sxfrctl0 = ahc_inb(ahc, SXFRCTL0); + ahc->suspend_state.channel[1].sxfrctl1 = ahc_inb(ahc, SXFRCTL1); + ahc->suspend_state.channel[1].simode0 = ahc_inb(ahc, SIMODE0); + ahc->suspend_state.channel[1].simode1 = ahc_inb(ahc, SIMODE1); + ahc->suspend_state.channel[1].seltimer = ahc_inb(ahc, SELTIMER); + ahc->suspend_state.channel[1].seqctl = ahc_inb(ahc, SEQCTL); + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); + } + ahc->suspend_state.channel[0].scsiseq = ahc_inb(ahc, SCSISEQ); + ahc->suspend_state.channel[0].sxfrctl0 = ahc_inb(ahc, SXFRCTL0); + ahc->suspend_state.channel[0].sxfrctl1 = ahc_inb(ahc, SXFRCTL1); + ahc->suspend_state.channel[0].simode0 = ahc_inb(ahc, SIMODE0); + ahc->suspend_state.channel[0].simode1 = ahc_inb(ahc, SIMODE1); + ahc->suspend_state.channel[0].seltimer = ahc_inb(ahc, SELTIMER); + ahc->suspend_state.channel[0].seqctl = ahc_inb(ahc, SEQCTL); + + if ((ahc->chip & AHC_PCI) != 0) { + ahc->suspend_state.dscommand0 = ahc_inb(ahc, DSCOMMAND0); + ahc->suspend_state.dspcistatus = ahc_inb(ahc, DSPCISTATUS); + } + + if ((ahc->features & AHC_DT) != 0) { + u_int sfunct; + + sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; + ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); + ahc->suspend_state.optionmode = ahc_inb(ahc, OPTIONMODE); + ahc_outb(ahc, SFUNCT, sfunct); + ahc->suspend_state.crccontrol1 = ahc_inb(ahc, CRCCONTROL1); + } + + if ((ahc->features & AHC_MULTI_FUNC) != 0) + ahc->suspend_state.scbbaddr = ahc_inb(ahc, SCBBADDR); + + if ((ahc->features & AHC_ULTRA2) != 0) + ahc->suspend_state.dff_thrsh = ahc_inb(ahc, DFF_THRSH); + + ptr = ahc->suspend_state.scratch_ram; + for (i = 0; i < 64; i++) + *ptr++ = ahc_inb(ahc, SRAM_BASE + i); + + if ((ahc->features & AHC_MORE_SRAM) != 0) { + for (i = 0; i < 16; i++) + *ptr++ = ahc_inb(ahc, TARG_OFFSET + i); + } + + ptr = ahc->suspend_state.btt; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + for (i = 0;i < AHC_NUM_TARGETS; i++) { + int j; + + for (j = 0;j < AHC_NUM_LUNS; j++) { + u_int tcl; + + tcl = BUILD_TCL(i << 4, j); + *ptr = ahc_index_busy_tcl(ahc, tcl); + } + } + } + ahc_shutdown(ahc); + return (0); +} + +int +ahc_resume(struct ahc_softc *ahc) +{ + uint8_t *ptr; + int i; + + ahc_reset(ahc); + + ahc_build_free_scb_list(ahc); + + /* Restore volatile registers */ + if ((ahc->features & AHC_TWIN) != 0) { + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); + ahc_outb(ahc, SCSIID, ahc->our_id); + ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[1].scsiseq); + ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[1].sxfrctl0); + ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[1].sxfrctl1); + ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[1].simode0); + ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[1].simode1); + ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[1].seltimer); + ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[1].seqctl); + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); + } + ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[0].scsiseq); + ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[0].sxfrctl0); + ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[0].sxfrctl1); + ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[0].simode0); + ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[0].simode1); + ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[0].seltimer); + ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[0].seqctl); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); + else + ahc_outb(ahc, SCSIID, ahc->our_id); + + if ((ahc->chip & AHC_PCI) != 0) { + ahc_outb(ahc, DSCOMMAND0, ahc->suspend_state.dscommand0); + ahc_outb(ahc, DSPCISTATUS, ahc->suspend_state.dspcistatus); + } + + if ((ahc->features & AHC_DT) != 0) { + u_int sfunct; + + sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; + ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); + ahc_outb(ahc, OPTIONMODE, ahc->suspend_state.optionmode); + ahc_outb(ahc, SFUNCT, sfunct); + ahc_outb(ahc, CRCCONTROL1, ahc->suspend_state.crccontrol1); + } + + if ((ahc->features & AHC_MULTI_FUNC) != 0) + ahc_outb(ahc, SCBBADDR, ahc->suspend_state.scbbaddr); + + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, DFF_THRSH, ahc->suspend_state.dff_thrsh); + + ptr = ahc->suspend_state.scratch_ram; + for (i = 0; i < 64; i++) + ahc_outb(ahc, SRAM_BASE + i, *ptr++); + + if ((ahc->features & AHC_MORE_SRAM) != 0) { + for (i = 0; i < 16; i++) + ahc_outb(ahc, TARG_OFFSET + i, *ptr++); + } + + ptr = ahc->suspend_state.btt; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + for (i = 0;i < AHC_NUM_TARGETS; i++) { + int j; + + for (j = 0;j < AHC_NUM_LUNS; j++) { + u_int tcl; + + tcl = BUILD_TCL(i << 4, j); + ahc_busy_tcl(ahc, tcl, *ptr); + } + } + } + return (0); +} + +/************************** Busy Target Table *********************************/ +/* + * Return the untagged transaction id for a given target/channel lun. + * Optionally, clear the entry. + */ +u_int +ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl) +{ + u_int scbid; + u_int target_offset; + + if ((ahc->flags & AHC_SCB_BTT) != 0) { + u_int saved_scbptr; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); + scbid = ahc_inb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl)); + ahc_outb(ahc, SCBPTR, saved_scbptr); + } else { + target_offset = TCL_TARGET_OFFSET(tcl); + scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset); + } + + return (scbid); +} + +void +ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl) +{ + u_int target_offset; + + if ((ahc->flags & AHC_SCB_BTT) != 0) { + u_int saved_scbptr; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); + ahc_outb(ahc, SCB_64_BTT+TCL_TARGET_OFFSET(tcl), SCB_LIST_NULL); + ahc_outb(ahc, SCBPTR, saved_scbptr); + } else { + target_offset = TCL_TARGET_OFFSET(tcl); + ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL); + } +} + +void +ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid) +{ + u_int target_offset; + + if ((ahc->flags & AHC_SCB_BTT) != 0) { + u_int saved_scbptr; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); + ahc_outb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl), scbid); + ahc_outb(ahc, SCBPTR, saved_scbptr); + } else { + target_offset = TCL_TARGET_OFFSET(tcl); + ahc_outb(ahc, BUSY_TARGETS + target_offset, scbid); + } +} + +/************************** SCB and SCB queue management **********************/ +int +ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target, + char channel, int lun, u_int tag, role_t role) +{ + int targ = SCB_GET_TARGET(ahc, scb); + char chan = SCB_GET_CHANNEL(ahc, scb); + int slun = SCB_GET_LUN(scb); + int match; + + match = ((chan == channel) || (channel == ALL_CHANNELS)); + if (match != 0) + match = ((targ == target) || (target == CAM_TARGET_WILDCARD)); + if (match != 0) + match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); + if (match != 0) { +#if AHC_TARGET_MODE + int group; + + group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); + if (role == ROLE_INITIATOR) { + match = (group != XPT_FC_GROUP_TMODE) + && ((tag == scb->hscb->tag) + || (tag == SCB_LIST_NULL)); + } else if (role == ROLE_TARGET) { + match = (group == XPT_FC_GROUP_TMODE) + && ((tag == scb->io_ctx->csio.tag_id) + || (tag == SCB_LIST_NULL)); + } +#else /* !AHC_TARGET_MODE */ + match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); +#endif /* AHC_TARGET_MODE */ + } + + return match; +} + +void +ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb) +{ + int target; + char channel; + int lun; + + target = SCB_GET_TARGET(ahc, scb); + lun = SCB_GET_LUN(scb); + channel = SCB_GET_CHANNEL(ahc, scb); + + ahc_search_qinfifo(ahc, target, channel, lun, + /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN, + CAM_REQUEUE_REQ, SEARCH_COMPLETE); + + ahc_platform_freeze_devq(ahc, scb); +} + +void +ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, struct scb *scb) +{ + struct scb *prev_scb; + + prev_scb = NULL; + if (ahc_qinfifo_count(ahc) != 0) { + u_int prev_tag; + uint8_t prev_pos; + + prev_pos = ahc->qinfifonext - 1; + prev_tag = ahc->qinfifo[prev_pos]; + prev_scb = ahc_lookup_scb(ahc, prev_tag); + } + ahc_qinfifo_requeue(ahc, prev_scb, scb); + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); + } else { + ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); + } +} + +static void +ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb, + struct scb *scb) +{ + if (prev_scb == NULL) + ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag); + else + prev_scb->hscb->next = scb->hscb->tag; + ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; + scb->hscb->next = ahc->next_queued_scb->hscb->tag; +} + +static int +ahc_qinfifo_count(struct ahc_softc *ahc) +{ + u_int8_t qinpos; + u_int8_t diff; + + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + qinpos = ahc_inb(ahc, SNSCB_QOFF); + ahc_outb(ahc, SNSCB_QOFF, qinpos); + } else + qinpos = ahc_inb(ahc, QINPOS); + diff = ahc->qinfifonext - qinpos; + return (diff); +} + +int +ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, + int lun, u_int tag, role_t role, uint32_t status, + ahc_search_action action) +{ + struct scb *scb; + struct scb *prev_scb; + uint8_t qinstart; + uint8_t qinpos; + uint8_t qintail; + uint8_t next, prev; + uint8_t curscbptr; + int found; + int maxtarget; + int i; + int have_qregs; + + qintail = ahc->qinfifonext; + have_qregs = (ahc->features & AHC_QUEUE_REGS) != 0; + if (have_qregs) { + qinstart = ahc_inb(ahc, SNSCB_QOFF); + ahc_outb(ahc, SNSCB_QOFF, qinstart); + } else + qinstart = ahc_inb(ahc, QINPOS); + qinpos = qinstart; + next = ahc_inb(ahc, NEXT_QUEUED_SCB); + found = 0; + prev_scb = NULL; + + if (action == SEARCH_COMPLETE) { + /* + * Don't attempt to run any queued untagged transactions + * until we are done with the abort process. + */ + ahc_freeze_untagged_queues(ahc); + } + + /* + * Start with an empty queue. Entries that are not chosen + * for removal will be re-added to the queue as we go. + */ + ahc->qinfifonext = qinpos; + ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); + + while (qinpos != qintail) { + scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]); + if (ahc_match_scb(ahc, scb, target, channel, lun, tag, role)) { + /* + * We found an scb that needs to be acted on. + */ + found++; + switch (action) { + case SEARCH_COMPLETE: + { + cam_status ostat; + cam_status cstat; + + ostat = ahc_get_transaction_status(scb); + if (ostat == CAM_REQ_INPROG) + ahc_set_transaction_status(scb, + status); + cstat = ahc_get_transaction_status(scb); + if (cstat != CAM_REQ_CMP) + ahc_freeze_scb(scb); + if ((scb->flags & SCB_ACTIVE) == 0) + printf("Inactive SCB in qinfifo\n"); + ahc_done(ahc, scb); + + /* FALLTHROUGH */ + case SEARCH_REMOVE: + break; + } + case SEARCH_COUNT: + ahc_qinfifo_requeue(ahc, prev_scb, scb); + prev_scb = scb; + break; + } + } else { + ahc_qinfifo_requeue(ahc, prev_scb, scb); + prev_scb = scb; + } + qinpos++; + } + + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); + } else { + ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); + } + + if (action != SEARCH_COUNT + && (found != 0) + && (qinstart != ahc->qinfifonext)) { + /* + * The sequencer may be in the process of dmaing + * down the SCB at the beginning of the queue. + * This could be problematic if either the first, + * or the second SCB is removed from the queue + * (the first SCB includes a pointer to the "next" + * SCB to dma). If we have removed any entries, swap + * the first element in the queue with the next HSCB + * so the sequencer will notice that NEXT_QUEUED_SCB + * has changed during its dma attempt and will retry + * the DMA. + */ + scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]); + + /* + * ahc_swap_with_next_hscb forces our next pointer to + * point to the reserved SCB for future commands. Save + * and restore our original next pointer to maintain + * queue integrity. + */ + next = scb->hscb->next; + ahc->scb_data->scbindex[scb->hscb->tag] = NULL; + ahc_swap_with_next_hscb(ahc, scb); + scb->hscb->next = next; + ahc->qinfifo[qinstart] = scb->hscb->tag; + + /* Tell the card about the new head of the qinfifo. */ + ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag); + + /* Fixup the tail "next" pointer. */ + qintail = ahc->qinfifonext - 1; + scb = ahc_lookup_scb(ahc, ahc->qinfifo[qintail]); + scb->hscb->next = ahc->next_queued_scb->hscb->tag; + } + + /* + * Search waiting for selection list. + */ + curscbptr = ahc_inb(ahc, SCBPTR); + next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */ + prev = SCB_LIST_NULL; + + while (next != SCB_LIST_NULL) { + uint8_t scb_index; + + ahc_outb(ahc, SCBPTR, next); + scb_index = ahc_inb(ahc, SCB_TAG); + if (scb_index >= ahc->scb_data->numscbs) { + printf("Waiting List inconsistency. " + "SCB index == %d, yet numscbs == %d.", + scb_index, ahc->scb_data->numscbs); + ahc_dump_card_state(ahc); + panic("for safety"); + } + scb = ahc_lookup_scb(ahc, scb_index); + if (ahc_match_scb(ahc, scb, target, channel, + lun, SCB_LIST_NULL, role)) { + /* + * We found an scb that needs to be acted on. + */ + found++; + switch (action) { + case SEARCH_COMPLETE: + { + cam_status ostat; + cam_status cstat; + + ostat = ahc_get_transaction_status(scb); + if (ostat == CAM_REQ_INPROG) + ahc_set_transaction_status(scb, + status); + cstat = ahc_get_transaction_status(scb); + if (cstat != CAM_REQ_CMP) + ahc_freeze_scb(scb); + if ((scb->flags & SCB_ACTIVE) == 0) + printf("Inactive SCB in Waiting List\n"); + ahc_done(ahc, scb); + /* FALLTHROUGH */ + } + case SEARCH_REMOVE: + next = ahc_rem_wscb(ahc, next, prev); + break; + case SEARCH_COUNT: + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + break; + } + } else { + + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + } + } + ahc_outb(ahc, SCBPTR, curscbptr); + + /* + * And lastly, the untagged holding queues. + */ + i = 0; + if ((ahc->flags & AHC_SCB_BTT) == 0) { + + maxtarget = 16; + if (target != CAM_TARGET_WILDCARD) { + + i = target; + if (channel == 'B') + i += 8; + maxtarget = i + 1; + } + } else { + maxtarget = 0; + } + + for (; i < maxtarget; i++) { + struct scb_tailq *untagged_q; + struct scb *next_scb; + + untagged_q = &(ahc->untagged_queues[i]); + next_scb = TAILQ_FIRST(untagged_q); + while (next_scb != NULL) { + + scb = next_scb; + next_scb = TAILQ_NEXT(scb, links.tqe); + + /* + * The head of the list may be the currently + * active untagged command for a device. + * We're only searching for commands that + * have not been started. A transaction + * marked active but still in the qinfifo + * is removed by the qinfifo scanning code + * above. + */ + if ((scb->flags & SCB_ACTIVE) != 0) + continue; + + if (ahc_match_scb(ahc, scb, target, channel, + lun, SCB_LIST_NULL, role)) { + /* + * We found an scb that needs to be acted on. + */ + found++; + switch (action) { + case SEARCH_COMPLETE: + { + cam_status ostat; + cam_status cstat; + + ostat = ahc_get_transaction_status(scb); + if (ostat == CAM_REQ_INPROG) + ahc_set_transaction_status(scb, + status); + cstat = ahc_get_transaction_status(scb); + if (cstat != CAM_REQ_CMP) + ahc_freeze_scb(scb); + if ((scb->flags & SCB_ACTIVE) == 0) + printf("Inactive SCB in untaggedQ\n"); + ahc_done(ahc, scb); + break; + } + case SEARCH_REMOVE: + TAILQ_REMOVE(untagged_q, scb, + links.tqe); + break; + case SEARCH_COUNT: + break; + } + } + } + } + + if (action == SEARCH_COMPLETE) + ahc_release_untagged_queues(ahc); + return (found); +} + +int +ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, + int lun, u_int tag, int stop_on_first, int remove, + int save_state) +{ + struct scb *scbp; + u_int next; + u_int prev; + u_int count; + u_int active_scb; + + count = 0; + next = ahc_inb(ahc, DISCONNECTED_SCBH); + prev = SCB_LIST_NULL; + + if (save_state) { + /* restore this when we're done */ + active_scb = ahc_inb(ahc, SCBPTR); + } else + /* Silence compiler */ + active_scb = SCB_LIST_NULL; + + while (next != SCB_LIST_NULL) { + u_int scb_index; + + ahc_outb(ahc, SCBPTR, next); + scb_index = ahc_inb(ahc, SCB_TAG); + if (scb_index >= ahc->scb_data->numscbs) { + printf("Disconnected List inconsistency. " + "SCB index == %d, yet numscbs == %d.", + scb_index, ahc->scb_data->numscbs); + ahc_dump_card_state(ahc); + panic("for safety"); + } + + if (next == prev) { + panic("Disconnected List Loop. " + "cur SCBPTR == %x, prev SCBPTR == %x.", + next, prev); + } + scbp = ahc_lookup_scb(ahc, scb_index); + if (ahc_match_scb(ahc, scbp, target, channel, lun, + tag, ROLE_INITIATOR)) { + count++; + if (remove) { + next = + ahc_rem_scb_from_disc_list(ahc, prev, next); + } else { + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + } + if (stop_on_first) + break; + } else { + prev = next; + next = ahc_inb(ahc, SCB_NEXT); + } + } + if (save_state) + ahc_outb(ahc, SCBPTR, active_scb); + return (count); +} + +/* + * Remove an SCB from the on chip list of disconnected transactions. + * This is empty/unused if we are not performing SCB paging. + */ +static u_int +ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr) +{ + u_int next; + + ahc_outb(ahc, SCBPTR, scbptr); + next = ahc_inb(ahc, SCB_NEXT); + + ahc_outb(ahc, SCB_CONTROL, 0); + + ahc_add_curscb_to_free_list(ahc); + + if (prev != SCB_LIST_NULL) { + ahc_outb(ahc, SCBPTR, prev); + ahc_outb(ahc, SCB_NEXT, next); + } else + ahc_outb(ahc, DISCONNECTED_SCBH, next); + + return (next); +} + +/* + * Add the SCB as selected by SCBPTR onto the on chip list of + * free hardware SCBs. This list is empty/unused if we are not + * performing SCB paging. + */ +static void +ahc_add_curscb_to_free_list(struct ahc_softc *ahc) +{ + /* + * Invalidate the tag so that our abort + * routines don't think it's active. + */ + ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); + + if ((ahc->flags & AHC_PAGESCBS) != 0) { + ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH)); + ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR)); + } +} + +/* + * Manipulate the waiting for selection list and return the + * scb that follows the one that we remove. + */ +static u_int +ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev) +{ + u_int curscb, next; + + /* + * Select the SCB we want to abort and + * pull the next pointer out of it. + */ + curscb = ahc_inb(ahc, SCBPTR); + ahc_outb(ahc, SCBPTR, scbpos); + next = ahc_inb(ahc, SCB_NEXT); + + /* Clear the necessary fields */ + ahc_outb(ahc, SCB_CONTROL, 0); + + ahc_add_curscb_to_free_list(ahc); + + /* update the waiting list */ + if (prev == SCB_LIST_NULL) { + /* First in the list */ + ahc_outb(ahc, WAITING_SCBH, next); + + /* + * Ensure we aren't attempting to perform + * selection for this entry. + */ + ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); + } else { + /* + * Select the scb that pointed to us + * and update its next pointer. + */ + ahc_outb(ahc, SCBPTR, prev); + ahc_outb(ahc, SCB_NEXT, next); + } + + /* + * Point us back at the original scb position. + */ + ahc_outb(ahc, SCBPTR, curscb); + return next; +} + +/******************************** Error Handling ******************************/ +/* + * Abort all SCBs that match the given description (target/channel/lun/tag), + * setting their status to the passed in status if the status has not already + * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer + * is paused before it is called. + */ +int +ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, + int lun, u_int tag, role_t role, uint32_t status) +{ + struct scb *scbp; + struct scb *scbp_next; + u_int active_scb; + int i, j; + int maxtarget; + int minlun; + int maxlun; + + int found; + + /* + * Don't attempt to run any queued untagged transactions + * until we are done with the abort process. + */ + ahc_freeze_untagged_queues(ahc); + + /* restore this when we're done */ + active_scb = ahc_inb(ahc, SCBPTR); + + found = ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL, + role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); + + /* + * Clean out the busy target table for any untagged commands. + */ + i = 0; + maxtarget = 16; + if (target != CAM_TARGET_WILDCARD) { + i = target; + if (channel == 'B') + i += 8; + maxtarget = i + 1; + } + + if (lun == CAM_LUN_WILDCARD) { + + /* + * Unless we are using an SCB based + * busy targets table, there is only + * one table entry for all luns of + * a target. + */ + minlun = 0; + maxlun = 1; + if ((ahc->flags & AHC_SCB_BTT) != 0) + maxlun = AHC_NUM_LUNS; + } else { + minlun = lun; + maxlun = lun + 1; + } + + for (;i < maxtarget; i++) { + for (j = minlun;j < maxlun; j++) + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j)); + } + + /* + * Go through the disconnected list and remove any entries we + * have queued for completion, 0'ing their control byte too. + * We save the active SCB and restore it ourselves, so there + * is no reason for this search to restore it too. + */ + ahc_search_disc_list(ahc, target, channel, lun, tag, + /*stop_on_first*/FALSE, /*remove*/TRUE, + /*save_state*/FALSE); + + /* + * Go through the hardware SCB array looking for commands that + * were active but not on any list. + */ + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + u_int scbid; + + ahc_outb(ahc, SCBPTR, i); + scbid = ahc_inb(ahc, SCB_TAG); + scbp = ahc_lookup_scb(ahc, scbid); + if (scbp != NULL + && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) + ahc_add_curscb_to_free_list(ahc); + } + + /* + * Go through the pending CCB list and look for + * commands for this target that are still active. + * These are other tagged commands that were + * disconnected when the reset occured. + */ + scbp_next = LIST_FIRST(&ahc->pending_scbs); + while (scbp_next != NULL) { + scbp = scbp_next; + scbp_next = LIST_NEXT(scbp, pending_links); + if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) { + cam_status ostat; + + ostat = ahc_get_transaction_status(scbp); + if (ostat == CAM_REQ_INPROG) + ahc_set_transaction_status(scbp, status); + if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP) + ahc_freeze_scb(scbp); + if ((scbp->flags & SCB_ACTIVE) == 0) + printf("Inactive SCB on pending list\n"); + ahc_done(ahc, scbp); + found++; + } + } + ahc_outb(ahc, SCBPTR, active_scb); + ahc_platform_abort_scbs(ahc, target, channel, lun, tag, role, status); + ahc_release_untagged_queues(ahc); + return found; +} + +static void +ahc_reset_current_bus(struct ahc_softc *ahc) +{ + uint8_t scsiseq; + + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST); + scsiseq = ahc_inb(ahc, SCSISEQ); + ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO); + ahc_delay(AHC_BUSRESET_DELAY); + /* Turn off the bus reset */ + ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO); + + ahc_clear_intstat(ahc); + + /* Re-enable reset interrupts */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST); +} + +int +ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) +{ + struct ahc_devinfo devinfo; + u_int initiator, target, max_scsiid; + u_int sblkctl; + int found; + int restart_needed; + char cur_channel; + + ahc->pending_device = NULL; + + ahc_compile_devinfo(&devinfo, + CAM_TARGET_WILDCARD, + CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD, + channel, ROLE_UNKNOWN); + pause_sequencer(ahc); + + /* Make sure the sequencer is in a safe location. */ + ahc_clear_critical_section(ahc); + + /* + * Run our command complete fifos to ensure that we perform + * completion processing on any commands that 'completed' + * before the reset occurred. + */ + ahc_run_qoutfifo(ahc); +#if AHC_TARGET_MODE + if ((ahc->flags & AHC_TARGETROLE) != 0) { + ahc_run_tqinfifo(ahc, /*paused*/TRUE); + } +#endif + + /* + * Reset the bus if we are initiating this reset + */ + sblkctl = ahc_inb(ahc, SBLKCTL); + cur_channel = 'A'; + if ((ahc->features & AHC_TWIN) != 0 + && ((sblkctl & SELBUSB) != 0)) + cur_channel = 'B'; + if (cur_channel != channel) { + /* Case 1: Command for another bus is active + * Stealthily reset the other bus without + * upsetting the current bus. + */ + ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); + ahc_outb(ahc, SIMODE1, + ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST)); + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); + if (initiate_reset) + ahc_reset_current_bus(ahc); + ahc_clear_intstat(ahc); + ahc_outb(ahc, SBLKCTL, sblkctl); + restart_needed = FALSE; + } else { + /* Case 2: A command from this bus is active or we're idle */ + ahc_clear_msg_state(ahc); + ahc_outb(ahc, SIMODE1, + ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST)); + ahc_outb(ahc, SCSISEQ, + ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); + if (initiate_reset) + ahc_reset_current_bus(ahc); + ahc_clear_intstat(ahc); + restart_needed = TRUE; + } + + /* + * Clean up all the state information for the + * pending transactions on this bus. + */ + found = ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, channel, + CAM_LUN_WILDCARD, SCB_LIST_NULL, + ROLE_UNKNOWN, CAM_SCSI_BUS_RESET); + + max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7; + +#ifdef AHC_TARGET_MODE + /* + * Send an immediate notify ccb to all target more peripheral + * drivers affected by this action. + */ + for (target = 0; target <= max_scsiid; target++) { + struct tmode_tstate* tstate; + u_int lun; + + tstate = ahc->enabled_targets[target]; + if (tstate == NULL) + continue; + for (lun = 0; lun < AHC_NUM_LUNS; lun++) { + struct tmode_lstate* lstate; + + lstate = tstate->enabled_luns[lun]; + if (lstate == NULL) + continue; + + ahc_queue_lstate_event(ahc, lstate, CAM_TARGET_WILDCARD, + EVENT_TYPE_BUS_RESET, /*arg*/0); + ahc_send_lstate_events(ahc, lstate); + } + } +#endif + /* Notify the XPT that a bus reset occurred */ + ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD, AC_BUS_RESET); + + /* + * Revert to async/narrow transfers until we renegotiate. + */ + for (target = 0; target <= max_scsiid; target++) { + + if (ahc->enabled_targets[target] == NULL) + continue; + for (initiator = 0; initiator <= max_scsiid; initiator++) { + struct ahc_devinfo devinfo; + + ahc_compile_devinfo(&devinfo, target, initiator, + CAM_LUN_WILDCARD, + channel, ROLE_UNKNOWN); + ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHC_TRANS_CUR, /*paused*/TRUE); + ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL, + /*period*/0, /*offset*/0, + /*ppr_options*/0, AHC_TRANS_CUR, + /*paused*/TRUE); + } + } + + if (restart_needed) + restart_sequencer(ahc); + else + unpause_sequencer(ahc); + return found; +} + + +/***************************** Residual Processing ****************************/ +/* + * Calculate the residual for a just completed SCB. + */ +static void +ahc_calc_residual(struct scb *scb) +{ + struct hardware_scb *hscb; + struct status_pkt *spkt; + uint32_t sgptr; + uint32_t resid_sgptr; + uint32_t resid; + + /* + * 5 cases. + * 1) No residual. + * SG_RESID_VALID clear in sgptr. + * 2) Transferless command + * 3) Never performed any transfers. + * sgptr has SG_FULL_RESID set. + * 4) No residual but target did not + * save data pointers after the + * last transfer, so sgptr was + * never updated. + * 5) We have a partial residual. + * Use residual_sgptr to determine + * where we are. + */ + + hscb = scb->hscb; + sgptr = ahc_le32toh(hscb->sgptr); + if ((sgptr & SG_RESID_VALID) == 0) + /* Case 1 */ + return; + sgptr &= ~SG_RESID_VALID; + + if ((sgptr & SG_LIST_NULL) != 0) + /* Case 2 */ + return; + + spkt = &hscb->shared_data.status; + resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr); + if ((sgptr & SG_FULL_RESID) != 0) { + /* Case 3 */ + resid = ahc_get_transfer_length(scb); + } else if ((resid_sgptr & SG_LIST_NULL) != 0) { + /* Case 4 */ + return; + } else if ((resid_sgptr & ~SG_PTR_MASK) != 0) { + panic("Bogus resid sgptr value 0x%x\n", resid_sgptr); + } else { + struct ahc_dma_seg *sg; + + /* + * Remainder of the SG where the transfer + * stopped. + */ + resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK; + sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK); + + /* The residual sg_ptr always points to the next sg */ + sg--; + + /* + * Add up the contents of all residual + * SG segments that are after the SG where + * the transfer stopped. + */ + while ((ahc_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) { + sg++; + resid += ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; + } + } + if ((scb->flags & SCB_SENSE) == 0) + ahc_set_residual(scb, resid); + else + ahc_set_sense_residual(scb, resid); + +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWMISC) { + ahc_print_path(ahc, scb); + printf("Handled Residual of %d bytes\n", resid); + } +#endif +} + +/******************************* Target Mode **********************************/ +#ifdef AHC_TARGET_MODE +/* + * Add a target mode event to this lun's queue + */ +static void +ahc_queue_lstate_event(struct ahc_softc *ahc, struct tmode_lstate *lstate, + u_int initiator_id, u_int event_type, u_int event_arg) +{ + struct ahc_tmode_event *event; + int pending; + + xpt_freeze_devq(lstate->path, /*count*/1); + if (lstate->event_w_idx >= lstate->event_r_idx) + pending = lstate->event_w_idx - lstate->event_r_idx; + else + pending = AHC_TMODE_EVENT_BUFFER_SIZE + 1 + - (lstate->event_r_idx - lstate->event_w_idx); + + if (event_type == EVENT_TYPE_BUS_RESET + || event_type == MSG_BUS_DEV_RESET) { + /* + * Any earlier events are irrelevant, so reset our buffer. + * This has the effect of allowing us to deal with reset + * floods (an external device holding down the reset line) + * without losing the event that is really interesting. + */ + lstate->event_r_idx = 0; + lstate->event_w_idx = 0; + xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE); + } + + if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) { + xpt_print_path(lstate->path); + printf("immediate event %x:%x lost\n", + lstate->event_buffer[lstate->event_r_idx].event_type, + lstate->event_buffer[lstate->event_r_idx].event_arg); + lstate->event_r_idx++; + if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) + lstate->event_r_idx = 0; + xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE); + } + + event = &lstate->event_buffer[lstate->event_w_idx]; + event->initiator_id = initiator_id; + event->event_type = event_type; + event->event_arg = event_arg; + lstate->event_w_idx++; + if (lstate->event_w_idx == AHC_TMODE_EVENT_BUFFER_SIZE) + lstate->event_w_idx = 0; +} + +/* + * Send any target mode events queued up waiting + * for immediate notify resources. + */ +void +ahc_send_lstate_events(struct ahc_softc *ahc, struct tmode_lstate *lstate) +{ + struct ccb_hdr *ccbh; + struct ccb_immed_notify *inot; + + while (lstate->event_r_idx != lstate->event_w_idx + && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { + struct ahc_tmode_event *event; + + event = &lstate->event_buffer[lstate->event_r_idx]; + SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); + inot = (struct ccb_immed_notify *)ccbh; + switch (event->event_type) { + case EVENT_TYPE_BUS_RESET: + ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; + break; + default: + ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; + inot->message_args[0] = event->event_type; + inot->message_args[1] = event->event_arg; + break; + } + inot->initiator_id = event->initiator_id; + inot->sense_len = 0; + xpt_done((union ccb *)inot); + lstate->event_r_idx++; + if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) + lstate->event_r_idx = 0; + } +} +#endif + +/******************** Sequencer Program Patching/Download *********************/ + +#ifdef AHC_DUMP_SEQ +void +ahc_dumpseq(struct ahc_softc* ahc) +{ + int i; + int max_prog; + + if ((ahc->chip & AHC_BUS_MASK) < AHC_PCI) + max_prog = 448; + else if ((ahc->features & AHC_ULTRA2) != 0) + max_prog = 768; + else + max_prog = 512; + + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); + ahc_outb(ahc, SEQADDR0, 0); + ahc_outb(ahc, SEQADDR1, 0); + for (i = 0; i < max_prog; i++) { + uint8_t ins_bytes[4]; + + ahc_insb(ahc, SEQRAM, ins_bytes, 4); + printf("0x%08x\n", ins_bytes[0] << 24 + | ins_bytes[1] << 16 + | ins_bytes[2] << 8 + | ins_bytes[3]); + } +} +#endif + +static void +ahc_loadseq(struct ahc_softc *ahc) +{ + struct cs cs_table[num_critical_sections]; + u_int begin_set[num_critical_sections]; + u_int end_set[num_critical_sections]; + struct patch *cur_patch; + u_int cs_count; + u_int cur_cs; + u_int i; + int downloaded; + u_int skip_addr; + u_int sg_prefetch_cnt; + uint8_t download_consts[7]; + + /* + * Start out with 0 critical sections + * that apply to this firmware load. + */ + cs_count = 0; + cur_cs = 0; + memset(begin_set, 0, sizeof(begin_set)); + memset(end_set, 0, sizeof(end_set)); + + /* Setup downloadable constant table */ + download_consts[QOUTFIFO_OFFSET] = 0; + if (ahc->targetcmds != NULL) + download_consts[QOUTFIFO_OFFSET] += 32; + download_consts[QINFIFO_OFFSET] = download_consts[QOUTFIFO_OFFSET] + 1; + download_consts[CACHESIZE_MASK] = ahc->pci_cachesize - 1; + download_consts[INVERTED_CACHESIZE_MASK] = ~(ahc->pci_cachesize - 1); + sg_prefetch_cnt = ahc->pci_cachesize; + if (sg_prefetch_cnt < (2 * sizeof(struct ahc_dma_seg))) + sg_prefetch_cnt = 2 * sizeof(struct ahc_dma_seg); + download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt; + download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_cnt - 1); + download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_cnt - 1); + + cur_patch = patches; + downloaded = 0; + skip_addr = 0; + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); + ahc_outb(ahc, SEQADDR0, 0); + ahc_outb(ahc, SEQADDR1, 0); + + for (i = 0; i < sizeof(seqprog)/4; i++) { + if (ahc_check_patch(ahc, &cur_patch, i, &skip_addr) == 0) { + /* + * Don't download this instruction as it + * is in a patch that was removed. + */ + continue; + } + /* + * Move through the CS table until we find a CS + * that might apply to this instruction. + */ + for (; cur_cs < num_critical_sections; cur_cs++) { + if (critical_sections[cur_cs].end <= i) { + if (begin_set[cs_count] == TRUE + && end_set[cs_count] == FALSE) { + cs_table[cs_count].end = downloaded; + end_set[cs_count] = TRUE; + cs_count++; + } + continue; + } + if (critical_sections[cur_cs].begin <= i + && begin_set[cs_count] == FALSE) { + cs_table[cs_count].begin = downloaded; + begin_set[cs_count] = TRUE; + } + break; + } + ahc_download_instr(ahc, i, download_consts); + downloaded++; + } + + ahc->num_critical_sections = cs_count; + if (cs_count != 0) { + + cs_count *= sizeof(struct cs); + ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT); + if (ahc->critical_sections == NULL) + panic("ahc_loadseq: Could not malloc"); + memcpy(ahc->critical_sections, cs_table, cs_count); + } + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); + restart_sequencer(ahc); + + if (bootverbose) + printf(" %d instructions downloaded\n", downloaded); +} + +static int +ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch, + u_int start_instr, u_int *skip_addr) +{ + struct patch *cur_patch; + struct patch *last_patch; + u_int num_patches; + + num_patches = sizeof(patches)/sizeof(struct patch); + last_patch = &patches[num_patches]; + cur_patch = *start_patch; + + while (cur_patch < last_patch && start_instr == cur_patch->begin) { + + if (cur_patch->patch_func(ahc) == 0) { + + /* Start rejecting code */ + *skip_addr = start_instr + cur_patch->skip_instr; + cur_patch += cur_patch->skip_patch; + } else { + /* Accepted this patch. Advance to the next + * one and wait for our intruction pointer to + * hit this point. + */ + cur_patch++; + } + } + + *start_patch = cur_patch; + if (start_instr < *skip_addr) + /* Still skipping */ + return (0); + + return (1); +} + +static void +ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) +{ + union ins_formats instr; + struct ins_format1 *fmt1_ins; + struct ins_format3 *fmt3_ins; + u_int opcode; + + /* + * The firmware is always compiled into a little endian format. + */ + instr.integer = ahc_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); + + fmt1_ins = &instr.format1; + fmt3_ins = NULL; + + /* Pull the opcode */ + opcode = instr.format1.opcode; + switch (opcode) { + case AIC_OP_JMP: + case AIC_OP_JC: + case AIC_OP_JNC: + case AIC_OP_CALL: + case AIC_OP_JNE: + case AIC_OP_JNZ: + case AIC_OP_JE: + case AIC_OP_JZ: + { + struct patch *cur_patch; + int address_offset; + u_int address; + u_int skip_addr; + u_int i; + + fmt3_ins = &instr.format3; + address_offset = 0; + address = fmt3_ins->address; + cur_patch = patches; + skip_addr = 0; + + for (i = 0; i < address;) { + + ahc_check_patch(ahc, &cur_patch, i, &skip_addr); + + if (skip_addr > i) { + int end_addr; + + end_addr = MIN(address, skip_addr); + address_offset += end_addr - i; + i = skip_addr; + } else { + i++; + } + } + address -= address_offset; + fmt3_ins->address = address; + /* FALLTHROUGH */ + } + case AIC_OP_OR: + case AIC_OP_AND: + case AIC_OP_XOR: + case AIC_OP_ADD: + case AIC_OP_ADC: + case AIC_OP_BMOV: + if (fmt1_ins->parity != 0) { + fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; + } + fmt1_ins->parity = 0; + if ((ahc->features & AHC_CMD_CHAN) == 0 + && opcode == AIC_OP_BMOV) { + /* + * Block move was added at the same time + * as the command channel. Verify that + * this is only a move of a single element + * and convert the BMOV to a MOV + * (AND with an immediate of FF). + */ + if (fmt1_ins->immediate != 1) + panic("%s: BMOV not supported\n", + ahc_name(ahc)); + fmt1_ins->opcode = AIC_OP_AND; + fmt1_ins->immediate = 0xff; + } + /* FALLTHROUGH */ + case AIC_OP_ROL: + if ((ahc->features & AHC_ULTRA2) != 0) { + int i, count; + + /* Calculate odd parity for the instruction */ + for (i = 0, count = 0; i < 31; i++) { + uint32_t mask; + + mask = 0x01 << i; + if ((instr.integer & mask) != 0) + count++; + } + if ((count & 0x01) == 0) + instr.format1.parity = 1; + } else { + /* Compress the instruction for older sequencers */ + if (fmt3_ins != NULL) { + instr.integer = + fmt3_ins->immediate + | (fmt3_ins->source << 8) + | (fmt3_ins->address << 16) + | (fmt3_ins->opcode << 25); + } else { + instr.integer = + fmt1_ins->immediate + | (fmt1_ins->source << 8) + | (fmt1_ins->destination << 16) + | (fmt1_ins->ret << 24) + | (fmt1_ins->opcode << 25); + } + } + /* The sequencer is a little endian cpu */ + instr.integer = ahc_htole32(instr.integer); + ahc_outsb(ahc, SEQRAM, instr.bytes, 4); + break; + default: + panic("Unknown opcode encountered in seq program"); + break; + } +} + +void +ahc_dump_card_state(struct ahc_softc *ahc) +{ + struct scb *scb; + struct scb_tailq *untagged_q; + int target; + int maxtarget; + int i; + uint8_t qinpos; + uint8_t qintail; + uint8_t qoutpos; + uint8_t scb_index; + uint8_t saved_scbptr; + + saved_scbptr = ahc_inb(ahc, SCBPTR); + + printf("%s: Dumping Card State at SEQADDR 0x%x\n", + ahc_name(ahc), + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); + + printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x, SSTAT0 0x%x\n", + ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL), + ahc_inb(ahc, SSTAT0)); + printf("SCB count = %d\n", ahc->scb_data->numscbs); + printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); + printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); + /* QINFIFO */ + printf("QINFIFO entries: "); + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + qinpos = ahc_inb(ahc, SNSCB_QOFF); + ahc_outb(ahc, SNSCB_QOFF, qinpos); + } else + qinpos = ahc_inb(ahc, QINPOS); + qintail = ahc->qinfifonext; + while (qinpos != qintail) { + printf("%d ", ahc->qinfifo[qinpos]); + qinpos++; + } + printf("\n"); + + printf("Waiting Queue entries: "); + scb_index = ahc_inb(ahc, WAITING_SCBH); + i = 0; + while (scb_index != SCB_LIST_NULL && i++ < 256) { + ahc_outb(ahc, SCBPTR, scb_index); + printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); + scb_index = ahc_inb(ahc, SCB_NEXT); + } + printf("\n"); + + printf("Disconnected Queue entries: "); + scb_index = ahc_inb(ahc, DISCONNECTED_SCBH); + i = 0; + while (scb_index != SCB_LIST_NULL && i++ < 256) { + ahc_outb(ahc, SCBPTR, scb_index); + printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); + scb_index = ahc_inb(ahc, SCB_NEXT); + } + printf("\n"); + + printf("QOUTFIFO entries: "); + qoutpos = ahc->qoutfifonext; + i = 0; + while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) { + printf("%d ", ahc->qoutfifo[qoutpos]); + qoutpos++; + } + printf("\n"); + + printf("Sequencer Free SCB List: "); + scb_index = ahc_inb(ahc, FREE_SCBH); + i = 0; + while (scb_index != SCB_LIST_NULL && i++ < 256) { + ahc_outb(ahc, SCBPTR, scb_index); + printf("%d ", scb_index); + scb_index = ahc_inb(ahc, SCB_NEXT); + } + printf("\n"); + + printf("Pending list: "); + i = 0; + LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { + if (i++ > 256) + break; + printf("%d ", scb->hscb->tag); + } + printf("\n"); + + printf("Kernel Free SCB list: "); + i = 0; + SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) { + if (i++ > 256) + break; + printf("%d ", scb->hscb->tag); + } + printf("\n"); + + maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7; + for (target = 0; target <= maxtarget; target++) { + untagged_q = &ahc->untagged_queues[target]; + if (TAILQ_FIRST(untagged_q) == NULL) + continue; + printf("Untagged Q(%d): ", target); + i = 0; + TAILQ_FOREACH(scb, untagged_q, links.tqe) { + if (i++ > 256) + break; + printf("%d ", scb->hscb->tag); + } + printf("\n"); + } + + ahc_platform_dump_card_state(ahc); + ahc_outb(ahc, SCBPTR, saved_scbptr); +} + +/************************* Target Mode ****************************************/ +#ifdef AHC_TARGET_MODE +cam_status +ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, + struct tmode_tstate **tstate, struct tmode_lstate **lstate, + int notfound_failure) +{ + + if ((ahc->features & AHC_TARGETMODE) == 0) + return (CAM_REQ_INVALID); + + /* + * Handle the 'black hole' device that sucks up + * requests to unattached luns on enabled targets. + */ + if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD + && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { + *tstate = NULL; + *lstate = ahc->black_hole; + } else { + u_int max_id; + + max_id = (ahc->features & AHC_WIDE) ? 15 : 7; + if (ccb->ccb_h.target_id > max_id) + return (CAM_TID_INVALID); + + if (ccb->ccb_h.target_lun >= AHC_NUM_LUNS) + return (CAM_LUN_INVALID); + + *tstate = ahc->enabled_targets[ccb->ccb_h.target_id]; + *lstate = NULL; + if (*tstate != NULL) + *lstate = + (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; + } + + if (notfound_failure != 0 && *lstate == NULL) + return (CAM_PATH_INVALID); + + return (CAM_REQ_CMP); +} + +void +ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) +{ + struct tmode_tstate *tstate; + struct tmode_lstate *lstate; + struct ccb_en_lun *cel; + cam_status status; + u_int target; + u_int lun; + u_int target_mask; + u_long s; + char channel; + + status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, + /*notfound_failure*/FALSE); + + if (status != CAM_REQ_CMP) { + ccb->ccb_h.status = status; + return; + } + + if ((ahc->features & AHC_MULTIROLE) != 0) { + u_int our_id; + + if (cam_sim_bus(sim) == 0) + our_id = ahc->our_id; + else + our_id = ahc->our_id_b; + + if (ccb->ccb_h.target_id != our_id) { + if ((ahc->features & AHC_MULTI_TID) != 0 + && (ahc->flags & AHC_INITIATORROLE) != 0) { + /* + * Only allow additional targets if + * the initiator role is disabled. + * The hardware cannot handle a re-select-in + * on the initiator id during a re-select-out + * on a different target id. + */ + status = CAM_TID_INVALID; + } else if ((ahc->flags & AHC_INITIATORROLE) != 0 + || ahc->enabled_luns > 0) { + /* + * Only allow our target id to change + * if the initiator role is not configured + * and there are no enabled luns which + * are attached to the currently registered + * scsi id. + */ + status = CAM_TID_INVALID; + } + } + } + + if (status != CAM_REQ_CMP) { + ccb->ccb_h.status = status; + return; + } + + /* + * We now have an id that is valid. + * If we aren't in target mode, switch modes. + */ + if ((ahc->flags & AHC_TARGETROLE) == 0 + && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { + u_long s; + + printf("Configuring Target Mode\n"); + ahc_lock(ahc, &s); + if (LIST_FIRST(&ahc->pending_scbs) != NULL) { + ccb->ccb_h.status = CAM_BUSY; + ahc_unlock(ahc, &s); + return; + } + ahc->flags |= AHC_TARGETROLE; + if ((ahc->features & AHC_MULTIROLE) == 0) + ahc->flags &= ~AHC_INITIATORROLE; + pause_sequencer(ahc); + ahc_loadseq(ahc); + ahc_unlock(ahc, &s); + } + cel = &ccb->cel; + target = ccb->ccb_h.target_id; + lun = ccb->ccb_h.target_lun; + channel = SIM_CHANNEL(ahc, sim); + target_mask = 0x01 << target; + if (channel == 'B') + target_mask <<= 8; + + if (cel->enable != 0) { + u_int scsiseq; + + /* Are we already enabled?? */ + if (lstate != NULL) { + xpt_print_path(ccb->ccb_h.path); + printf("Lun already enabled\n"); + ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; + return; + } + + if (cel->grp6_len != 0 + || cel->grp7_len != 0) { + /* + * Don't (yet?) support vendor + * specific commands. + */ + ccb->ccb_h.status = CAM_REQ_INVALID; + printf("Non-zero Group Codes\n"); + return; + } + + /* + * Seems to be okay. + * Setup our data structures. + */ + if (target != CAM_TARGET_WILDCARD && tstate == NULL) { + tstate = ahc_alloc_tstate(ahc, target, channel); + if (tstate == NULL) { + xpt_print_path(ccb->ccb_h.path); + printf("Couldn't allocate tstate\n"); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + return; + } + } + lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT); + if (lstate == NULL) { + xpt_print_path(ccb->ccb_h.path); + printf("Couldn't allocate lstate\n"); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + return; + } + memset(lstate, 0, sizeof(*lstate)); + status = xpt_create_path(&lstate->path, /*periph*/NULL, + xpt_path_path_id(ccb->ccb_h.path), + xpt_path_target_id(ccb->ccb_h.path), + xpt_path_lun_id(ccb->ccb_h.path)); + if (status != CAM_REQ_CMP) { + free(lstate, M_DEVBUF); + xpt_print_path(ccb->ccb_h.path); + printf("Couldn't allocate path\n"); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + return; + } + SLIST_INIT(&lstate->accept_tios); + SLIST_INIT(&lstate->immed_notifies); + ahc_lock(ahc, &s); + pause_sequencer(ahc); + if (target != CAM_TARGET_WILDCARD) { + tstate->enabled_luns[lun] = lstate; + ahc->enabled_luns++; + + if ((ahc->features & AHC_MULTI_TID) != 0) { + u_int targid_mask; + + targid_mask = ahc_inb(ahc, TARGID) + | (ahc_inb(ahc, TARGID + 1) << 8); + + targid_mask |= target_mask; + ahc_outb(ahc, TARGID, targid_mask); + ahc_outb(ahc, TARGID+1, (targid_mask >> 8)); + + ahc_update_scsiid(ahc, targid_mask); + } else { + u_int our_id; + char channel; + + channel = SIM_CHANNEL(ahc, sim); + our_id = SIM_SCSI_ID(ahc, sim); + + /* + * This can only happen if selections + * are not enabled + */ + if (target != our_id) { + u_int sblkctl; + char cur_channel; + int swap; + + sblkctl = ahc_inb(ahc, SBLKCTL); + cur_channel = (sblkctl & SELBUSB) + ? 'B' : 'A'; + if ((ahc->features & AHC_TWIN) == 0) + cur_channel = 'A'; + swap = cur_channel != channel; + if (channel == 'A') + ahc->our_id = target; + else + ahc->our_id_b = target; + + if (swap) + ahc_outb(ahc, SBLKCTL, + sblkctl ^ SELBUSB); + + ahc_outb(ahc, SCSIID, target); + + if (swap) + ahc_outb(ahc, SBLKCTL, sblkctl); + } + } + } else + ahc->black_hole = lstate; + /* Allow select-in operations */ + if (ahc->black_hole != NULL && ahc->enabled_luns > 0) { + scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); + scsiseq |= ENSELI; + ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); + scsiseq = ahc_inb(ahc, SCSISEQ); + scsiseq |= ENSELI; + ahc_outb(ahc, SCSISEQ, scsiseq); + } + unpause_sequencer(ahc); + ahc_unlock(ahc, &s); + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_print_path(ccb->ccb_h.path); + printf("Lun now enabled for target mode\n"); + } else { + struct scb *scb; + int i, empty; + + if (lstate == NULL) { + ccb->ccb_h.status = CAM_LUN_INVALID; + return; + } + + ahc_lock(ahc, &s); + + ccb->ccb_h.status = CAM_REQ_CMP; + LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { + struct ccb_hdr *ccbh; + + ccbh = &scb->io_ctx->ccb_h; + if (ccbh->func_code == XPT_CONT_TARGET_IO + && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ + printf("CTIO pending\n"); + ccb->ccb_h.status = CAM_REQ_INVALID; + ahc_unlock(ahc, &s); + return; + } + } + + if (SLIST_FIRST(&lstate->accept_tios) != NULL) { + printf("ATIOs pending\n"); + ccb->ccb_h.status = CAM_REQ_INVALID; + } + + if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { + printf("INOTs pending\n"); + ccb->ccb_h.status = CAM_REQ_INVALID; + } + + if (ccb->ccb_h.status != CAM_REQ_CMP) { + ahc_unlock(ahc, &s); + return; + } + + xpt_print_path(ccb->ccb_h.path); + printf("Target mode disabled\n"); + xpt_free_path(lstate->path); + free(lstate, M_DEVBUF); + + pause_sequencer(ahc); + /* Can we clean up the target too? */ + if (target != CAM_TARGET_WILDCARD) { + tstate->enabled_luns[lun] = NULL; + ahc->enabled_luns--; + for (empty = 1, i = 0; i < 8; i++) + if (tstate->enabled_luns[i] != NULL) { + empty = 0; + break; + } + + if (empty) { + ahc_free_tstate(ahc, target, channel, + /*force*/FALSE); + if (ahc->features & AHC_MULTI_TID) { + u_int targid_mask; + + targid_mask = ahc_inb(ahc, TARGID) + | (ahc_inb(ahc, TARGID + 1) + << 8); + + targid_mask &= ~target_mask; + ahc_outb(ahc, TARGID, targid_mask); + ahc_outb(ahc, TARGID+1, + (targid_mask >> 8)); + ahc_update_scsiid(ahc, targid_mask); + } + } + } else { + + ahc->black_hole = NULL; + + /* + * We can't allow selections without + * our black hole device. + */ + empty = TRUE; + } + if (ahc->enabled_luns == 0) { + /* Disallow select-in */ + u_int scsiseq; + + scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); + scsiseq &= ~ENSELI; + ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); + scsiseq = ahc_inb(ahc, SCSISEQ); + scsiseq &= ~ENSELI; + ahc_outb(ahc, SCSISEQ, scsiseq); + + if ((ahc->features & AHC_MULTIROLE) == 0) { + printf("Configuring Initiator Mode\n"); + ahc->flags &= ~AHC_TARGETROLE; + ahc->flags |= AHC_INITIATORROLE; + pause_sequencer(ahc); + ahc_loadseq(ahc); + } + } + unpause_sequencer(ahc); + ahc_unlock(ahc, &s); + } +} + +static void +ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask) +{ + u_int scsiid_mask; + u_int scsiid; + + if ((ahc->features & AHC_MULTI_TID) == 0) + panic("ahc_update_scsiid called on non-multitid unit\n"); + + /* + * Since we will rely on the the TARGID mask + * for selection enables, ensure that OID + * in SCSIID is not set to some other ID + * that we don't want to allow selections on. + */ + if ((ahc->features & AHC_ULTRA2) != 0) + scsiid = ahc_inb(ahc, SCSIID_ULTRA2); + else + scsiid = ahc_inb(ahc, SCSIID); + scsiid_mask = 0x1 << (scsiid & OID); + if ((targid_mask & scsiid_mask) == 0) { + u_int our_id; + + /* ffs counts from 1 */ + our_id = ffs(targid_mask); + if (our_id == 0) + our_id = ahc->our_id; + else + our_id--; + scsiid &= TID; + scsiid |= our_id; + } + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIID_ULTRA2, scsiid); + else + ahc_outb(ahc, SCSIID, scsiid); +} + +void +ahc_run_tqinfifo(struct ahc_softc *ahc, int paused) +{ + struct target_cmd *cmd; + + /* + * If the card supports auto-access pause, + * we can access the card directly regardless + * of whether it is paused or not. + */ + if ((ahc->features & AHC_AUTOPAUSE) != 0) + paused = TRUE; + + while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) { + + /* + * Only advance through the queue if we + * have the resources to process the command. + */ + if (ahc_handle_target_cmd(ahc, cmd) != 0) + break; + + ahc->tqinfifonext++; + cmd->cmd_valid = 0; + + /* + * Lazily update our position in the target mode incomming + * command queue as seen by the sequencer. + */ + if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { + if ((ahc->features & AHC_HS_MAILBOX) != 0) { + u_int hs_mailbox; + + hs_mailbox = ahc_inb(ahc, HS_MAILBOX); + hs_mailbox &= ~HOST_TQINPOS; + hs_mailbox |= ahc->tqinfifonext & HOST_TQINPOS; + ahc_outb(ahc, HS_MAILBOX, hs_mailbox); + } else { + if (!paused) + pause_sequencer(ahc); + ahc_outb(ahc, KERNEL_TQINPOS, + ahc->tqinfifonext & HOST_TQINPOS); + if (!paused) + unpause_sequencer(ahc); + } + } + } +} + +static int +ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) +{ + struct tmode_tstate *tstate; + struct tmode_lstate *lstate; + struct ccb_accept_tio *atio; + uint8_t *byte; + int initiator; + int target; + int lun; + + initiator = SCSIID_TARGET(ahc, cmd->scsiid); + target = SCSIID_OUR_ID(cmd->scsiid); + lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); + + byte = cmd->bytes; + tstate = ahc->enabled_targets[target]; + lstate = NULL; + if (tstate != NULL) + lstate = tstate->enabled_luns[lun]; + + /* + * Commands for disabled luns go to the black hole driver. + */ + if (lstate == NULL) + lstate = ahc->black_hole; + + atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); + if (atio == NULL) { + ahc->flags |= AHC_TQINFIFO_BLOCKED; + /* + * Wait for more ATIOs from the peripheral driver for this lun. + */ + return (1); + } else + ahc->flags &= ~AHC_TQINFIFO_BLOCKED; +#if 0 + printf("Incoming command from %d for %d:%d%s\n", + initiator, target, lun, + lstate == ahc->black_hole ? "(Black Holed)" : ""); +#endif + SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); + + if (lstate == ahc->black_hole) { + /* Fill in the wildcards */ + atio->ccb_h.target_id = target; + atio->ccb_h.target_lun = lun; + } + + /* + * Package it up and send it off to + * whomever has this lun enabled. + */ + atio->sense_len = 0; + atio->init_id = initiator; + if (byte[0] != 0xFF) { + /* Tag was included */ + atio->tag_action = *byte++; + atio->tag_id = *byte++; + atio->ccb_h.flags = CAM_TAG_ACTION_VALID; + } else { + atio->ccb_h.flags = 0; + } + byte++; + + /* Okay. Now determine the cdb size based on the command code */ + switch (*byte >> CMD_GROUP_CODE_SHIFT) { + case 0: + atio->cdb_len = 6; + break; + case 1: + case 2: + atio->cdb_len = 10; + break; + case 4: + atio->cdb_len = 16; + break; + case 5: + atio->cdb_len = 12; + break; + case 3: + default: + /* Only copy the opcode. */ + atio->cdb_len = 1; + printf("Reserved or VU command code type encountered\n"); + break; + } + + memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len); + + atio->ccb_h.status |= CAM_CDB_RECVD; + + if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) { + /* + * We weren't allowed to disconnect. + * We're hanging on the bus until a + * continue target I/O comes in response + * to this accept tio. + */ +#if 0 + printf("Received Immediate Command %d:%d:%d - %p\n", + initiator, target, lun, ahc->pending_device); +#endif + ahc->pending_device = lstate; + ahc_freeze_ccb((union ccb *)atio); + atio->ccb_h.flags |= CAM_DIS_DISCONNECT; + } + xpt_done((union ccb*)atio); + return (0); +} + +#endif diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.h linux/drivers/scsi/aic7xxx/aic7xxx.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,1202 @@ +/* + * Core definitions and data structures shareable across OS platforms. + * + * Copyright (c) 1994-2001 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aic7xxx.h#19 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $ + */ + +#ifndef _AIC7XXX_H_ +#define _AIC7XXX_H_ + +/* Register Definitions */ +#include "aic7xxx_reg.h" + +/************************* Forward Declarations *******************************/ +struct ahc_platform_data; +struct scb_platform_data; + +/****************************** Useful Macros *********************************/ +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array)) + +#define ALL_CHANNELS '\0' +#define ALL_TARGETS_MASK 0xFFFF +#define INITIATOR_WILDCARD (~0) + +#define SCSIID_TARGET(ahc, scsiid) \ + (((scsiid) & ((((ahc)->features & AHC_TWIN) != 0) ? TWIN_TID : TID)) \ + >> TID_SHIFT) +#define SCSIID_OUR_ID(scsiid) \ + ((scsiid) & OID) +#define SCSIID_CHANNEL(ahc, scsiid) \ + ((((ahc)->features & AHC_TWIN) != 0) \ + ? ((((scsiid) & TWIN_CHNLB) != 0) ? 'B' : 'A') \ + : 'A') +#define SCB_IS_SCSIBUS_B(ahc, scb) \ + (SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) == 'B') +#define SCB_GET_OUR_ID(scb) \ + SCSIID_OUR_ID((scb)->hscb->scsiid) +#define SCB_GET_TARGET(ahc, scb) \ + SCSIID_TARGET((ahc), (scb)->hscb->scsiid) +#define SCB_GET_CHANNEL(ahc, scb) \ + SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) +#define SCB_GET_LUN(scb) \ + ((scb)->hscb->lun) +#define SCB_GET_TARGET_OFFSET(ahc, scb) \ + (SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0)) +#define SCB_GET_TARGET_MASK(ahc, scb) \ + (0x01 << (SCB_GET_TARGET_OFFSET(ahc, scb))) +#define TCL_TARGET_OFFSET(tcl) \ + ((((tcl) >> 4) & TID) >> 4) +#define TCL_LUN(tcl) \ + (tcl & (AHC_NUM_LUNS - 1)) +#define BUILD_TCL(scsiid, lun) \ + ((lun) | (((scsiid) & TID) << 4)) + +#ifndef AHC_TARGET_MODE +#undef AHC_TMODE_ENABLE +#define AHC_TMODE_ENABLE 0 +#endif + +/**************************** Driver Constants ********************************/ +/* + * The maximum number of supported targets. + */ +#define AHC_NUM_TARGETS 16 + +/* + * The maximum number of supported luns. + * The identify message only supports 64 luns in SPI3. + * You can have 2^64 luns when information unit transfers are enabled, + * but it is doubtful this driver will ever support IUTs. + */ +#define AHC_NUM_LUNS 64 + +/* + * The maximum transfer per S/G segment. + */ +#define AHC_MAXTRANSFER_SIZE 0x00ffffff /* limited by 24bit counter */ + +/* + * The maximum amount of SCB storage in hardware on a controller. + * This value represents an upper bound. Controllers vary in the number + * they actually support. + */ +#define AHC_SCB_MAX 255 + +/* + * The maximum number of concurrent transactions supported per driver instance. + * Sequencer Control Blocks (SCBs) store per-transaction information. Although + * the space for SCBs on the host adapter varies by model, the driver will + * page the SCBs between host and controller memory as needed. We are limited + * to 253 because: + * 1) The 8bit nature of the RISC engine holds us to an 8bit value. + * 2) We reserve one value, 255, to represent the invalid element. + * 3) Our input queue scheme requires one SCB to always be reserved + * in advance of queuing any SCBs. This takes us down to 254. + * 4) To handle our output queue correctly on machines that only + * support 32bit stores, we must clear the array 4 bytes at a + * time. To avoid colliding with a DMA write from the sequencer, + * we must be sure that 4 slots are empty when we write to clear + * the queue. This reduces us to 253 SCBs: 1 that just completed + * and the known three additional empty slots in the queue that + * preceed it. + */ +#define AHC_MAX_QUEUE 253 + +/* + * Ring Buffer of incoming target commands. + * We allocate 256 to simplify the logic in the sequencer + * by using the natural wrap point of an 8bit counter. + */ +#define AHC_TMODE_CMDS 256 + +/* Reset line assertion time in us */ +#define AHC_BUSRESET_DELAY 250 + +/******************* Chip Characteristics/Operating Settings *****************/ +/* + * Chip Type + * The chip order is from least sophisticated to most sophisticated. + */ +typedef enum { + AHC_NONE = 0x0000, + AHC_CHIPID_MASK = 0x00FF, + AHC_AIC7770 = 0x0001, + AHC_AIC7850 = 0x0002, + AHC_AIC7855 = 0x0003, + AHC_AIC7859 = 0x0004, + AHC_AIC7860 = 0x0005, + AHC_AIC7870 = 0x0006, + AHC_AIC7880 = 0x0007, + AHC_AIC7895 = 0x0008, + AHC_AIC7895C = 0x0009, + AHC_AIC7890 = 0x000a, + AHC_AIC7896 = 0x000b, + AHC_AIC7892 = 0x000c, + AHC_AIC7899 = 0x000d, + AHC_VL = 0x0100, /* Bus type VL */ + AHC_EISA = 0x0200, /* Bus type EISA */ + AHC_PCI = 0x0400, /* Bus type PCI */ + AHC_BUS_MASK = 0x0F00 +} ahc_chip; + +/* + * Features available in each chip type. + */ +typedef enum { + AHC_FENONE = 0x00000, + AHC_ULTRA = 0x00001, /* Supports 20MHz Transfers */ + AHC_ULTRA2 = 0x00002, /* Supports 40MHz Transfers */ + AHC_WIDE = 0x00004, /* Wide Channel */ + AHC_TWIN = 0x00008, /* Twin Channel */ + AHC_MORE_SRAM = 0x00010, /* 80 bytes instead of 64 */ + AHC_CMD_CHAN = 0x00020, /* Has a Command DMA Channel */ + AHC_QUEUE_REGS = 0x00040, /* Has Queue management registers */ + AHC_SG_PRELOAD = 0x00080, /* Can perform auto-SG preload */ + AHC_SPIOCAP = 0x00100, /* Has a Serial Port I/O Cap Register */ + AHC_MULTI_TID = 0x00200, /* Has bitmask of TIDs for select-in */ + AHC_HS_MAILBOX = 0x00400, /* Has HS_MAILBOX register */ + AHC_DT = 0x00800, /* Double Transition transfers */ + AHC_NEW_TERMCTL = 0x01000, /* Newer termination scheme */ + AHC_MULTI_FUNC = 0x02000, /* Multi-Function Twin Channel Device */ + AHC_LARGE_SCBS = 0x04000, /* 64byte SCBs */ + AHC_AUTORATE = 0x08000, /* Automatic update of SCSIRATE/OFFSET*/ + AHC_AUTOPAUSE = 0x10000, /* Automatic pause on register access */ + AHC_TARGETMODE = 0x20000, /* Has tested target mode support */ + AHC_MULTIROLE = 0x40000, /* Space for two roles at a time */ + AHC_REMOVABLE = 0x80000, /* Hot-Swap supported */ + AHC_AIC7770_FE = AHC_FENONE, + AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE, + AHC_AIC7855_FE = AHC_AIC7850_FE, + AHC_AIC7860_FE = AHC_AIC7850_FE|AHC_ULTRA, + AHC_AIC7870_FE = AHC_TARGETMODE, + AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, + /* + * Although we have space for both the initiator and + * target roles on ULTRA2 chips, we currently disable + * the initiator role to allow multi-scsi-id target mode + * configurations. We can only respond on the same SCSI + * ID as our initiator role if we allow initiator operation. + * At some point, we should add a configuration knob to + * allow both roles to be loaded. + */ + AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2 + |AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_MULTI_TID + |AHC_HS_MAILBOX|AHC_NEW_TERMCTL|AHC_LARGE_SCBS + |AHC_TARGETMODE, + AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_DT|AHC_AUTORATE|AHC_AUTOPAUSE, + AHC_AIC7895_FE = AHC_AIC7880_FE|AHC_MORE_SRAM|AHC_AUTOPAUSE + |AHC_CMD_CHAN|AHC_MULTI_FUNC|AHC_LARGE_SCBS, + AHC_AIC7895C_FE = AHC_AIC7895_FE|AHC_MULTI_TID, + AHC_AIC7896_FE = AHC_AIC7890_FE|AHC_MULTI_FUNC, + AHC_AIC7899_FE = AHC_AIC7892_FE|AHC_MULTI_FUNC +} ahc_feature; + +/* + * Bugs in the silicon that we work around in software. + */ +typedef enum { + AHC_BUGNONE = 0x00, + /* + * On all chips prior to the U2 product line, + * the WIDEODD S/G segment feature does not + * work during scsi->HostBus transfers. + */ + AHC_TMODE_WIDEODD_BUG = 0x01, + /* + * On the aic7890/91 Rev 0 chips, the autoflush + * feature does not work. A manual flush of + * the DMA FIFO is required. + */ + AHC_AUTOFLUSH_BUG = 0x02, + /* + * On many chips, cacheline streaming does not work. + */ + AHC_CACHETHEN_BUG = 0x04, + /* + * On the aic7896/97 chips, cacheline + * streaming must be enabled. + */ + AHC_CACHETHEN_DIS_BUG = 0x08, + /* + * PCI 2.1 Retry failure on non-empty data fifo. + */ + AHC_PCI_2_1_RETRY_BUG = 0x10, + /* + * Controller does not handle cacheline residuals + * properly on S/G segments if PCI MWI instructions + * are allowed. + */ + AHC_PCI_MWI_BUG = 0x20, + /* + * An SCB upload using the SCB channel's + * auto array entry copy feature may + * corrupt data. This appears to only + * occur on 66MHz systems. + */ + AHC_SCBCHAN_UPLOAD_BUG = 0x40 +} ahc_bug; + +/* + * Configuration specific settings. + * The driver determines these settings by probing the + * chip/controller's configuration. + */ +typedef enum { + AHC_FNONE = 0x000, + AHC_PAGESCBS = 0x001,/* Enable SCB paging */ + AHC_CHANNEL_B_PRIMARY = 0x002,/* + * On twin channel adapters, probe + * channel B first since it is the + * primary bus. + */ + AHC_USEDEFAULTS = 0x004,/* + * For cards without an seeprom + * or a BIOS to initialize the chip's + * SRAM, we use the default target + * settings. + */ + AHC_SEQUENCER_DEBUG = 0x008, + AHC_SHARED_SRAM = 0x010, + AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ + AHC_RESET_BUS_A = 0x040, + AHC_RESET_BUS_B = 0x080, + AHC_EXTENDED_TRANS_A = 0x100, + AHC_EXTENDED_TRANS_B = 0x200, + AHC_TERM_ENB_A = 0x400, + AHC_TERM_ENB_B = 0x800, + AHC_INITIATORROLE = 0x1000,/* + * Allow initiator operations on + * this controller. + */ + AHC_TARGETROLE = 0x2000,/* + * Allow target operations on this + * controller. + */ + AHC_NEWEEPROM_FMT = 0x4000, + AHC_RESOURCE_SHORTAGE = 0x8000, + AHC_TQINFIFO_BLOCKED = 0x10000,/* Blocked waiting for ATIOs */ + AHC_INT50_SPEEDFLEX = 0x20000,/* + * Internal 50pin connector + * sits behind an aic3860 + */ + AHC_SCB_BTT = 0x40000,/* + * The busy targets table is + * stored in SCB space rather + * than SRAM. + */ + AHC_BIOS_ENABLED = 0x80000, + AHC_ALL_INTERRUPTS = 0x100000, + AHC_ULTRA_DISABLED = 0x200000/* + * The precision resistor for + * ultra transmission speeds is + * missing, so we must limit + * ourselves to fast SCSI. + */ +} ahc_flag; + +/* + * Controller Information composed at probe time. + */ +struct ahc_probe_config { + const char *description; + char channel; + char channel_b; + ahc_chip chip; + ahc_feature features; + ahc_bug bugs; + ahc_flag flags; +}; + +/************************* Hardware SCB Definition ***************************/ + +/* + * The driver keeps up to MAX_SCB scb structures per card in memory. The SCB + * consists of a "hardware SCB" mirroring the fields availible on the card + * and additional information the kernel stores for each transaction. + * + * To minimize space utilization, a portion of the hardware scb stores + * different data during different portions of a SCSI transaction. + * As initialized by the host driver for the initiator role, this area + * contains the SCSI cdb (or a pointer to the cdb) to be executed. After + * the cdb has been presented to the target, this area serves to store + * residual transfer information and the SCSI status byte. + * For the target role, the contents of this area do not change, but + * still serve a different purpose than for the initiator role. See + * struct target_data for details. + */ + +/* + * Status information embedded in the shared poriton of + * an SCB after passing the cdb to the target. The kernel + * driver will only read this data for transactions that + * complete abnormally (non-zero status byte). + */ +struct status_pkt { + uint32_t residual_datacnt; /* Residual in the current S/G seg */ + uint32_t residual_sg_ptr; /* The next S/G for this transfer */ + uint8_t scsi_status; /* Standard SCSI status byte */ +}; + +/* + * Target mode version of the shared data SCB segment. + */ +struct target_data { + uint8_t target_phases; /* Bitmap of phases to execute */ + uint8_t data_phase; /* Data-In or Data-Out */ + uint8_t scsi_status; /* SCSI status to give to initiator */ + uint8_t initiator_tag; /* Initiator's transaction tag */ +}; + +struct hardware_scb { +/*0*/ union { + /* + * If the cdb is 12 bytes or less, we embed it directly + * in the SCB. For longer cdbs, we embed the address + * of the cdb payload as seen by the chip and a DMA + * is used to pull it in. + */ + uint8_t cdb[12]; + uint32_t cdb_ptr; + struct status_pkt status; + struct target_data tdata; + } shared_data; +/* + * A word about residuals. + * The scb is presented to the sequencer with the dataptr and datacnt + * fields initialized to the contents of the first S/G element to + * transfer. The sgptr field is initialized to the bus address for + * the S/G element that follows the first in the in core S/G array + * or'ed with the SG_FULL_RESID flag. Sgptr may point to an invalid + * S/G entry for this transfer (single S/G element transfer with the + * first elements address and length preloaded in the dataptr/datacnt + * fields). If no transfer is to occur, sgptr is set to SG_LIST_NULL. + * The SG_FULL_RESID flag ensures that the residual will be correctly + * noted even if no data transfers occur. Once the data phase is entered, + * the residual sgptr and datacnt are loaded from the sgptr and the + * datacnt fields. After each S/G element's dataptr and length are + * loaded into the hardware, the residual sgptr is advanced. After + * each S/G element is expired, its datacnt field is checked to see + * if the LAST_SEG flag is set. If so, SG_LIST_NULL is set in the + * residual sg ptr and the transfer is considered complete. If the + * sequencer determines that there is a residual in the tranfer, it + * will set the SG_RESID_VALID flag in sgptr and dma the scb back into + * host memory. To sumarize: + * + * Sequencer: + * o A residual has occurred if SG_FULL_RESID is set in sgptr, + * or residual_sgptr does not have SG_LIST_NULL set. + * + * o We are transfering the last segment if residual_datacnt has + * the SG_LAST_SEG flag set. + * + * Host: + * o A residual has occurred if a completed scb has the + * SG_RESID_VALID flag set. + * + * o residual_sgptr and sgptr refer to the "next" sg entry + * and so may point beyond the last valid sg entry for the + * transfer. + */ +/*12*/ uint32_t dataptr; +/*16*/ uint32_t datacnt; /* + * Byte 3 (numbered from 0) of + * the datacnt is really the + * 4th byte in that data address. + */ +/*20*/ uint32_t sgptr; +#define SG_PTR_MASK 0xFFFFFFF8 +/*24*/ uint8_t control; /* See SCB_CONTROL in aic7xxx.reg for details */ +/*25*/ uint8_t scsiid; /* what to load in the SCSIID register */ +/*26*/ uint8_t lun; +/*27*/ uint8_t tag; /* + * Index into our kernel SCB array. + * Also used as the tag for tagged I/O + */ +/*28*/ uint8_t cdb_len; +/*29*/ uint8_t scsirate; /* Value for SCSIRATE register */ +/*30*/ uint8_t scsioffset; /* Value for SCSIOFFSET register */ +/*31*/ uint8_t next; /* + * Used for threading SCBs in the + * "Waiting for Selection" and + * "Disconnected SCB" lists down + * in the sequencer. + */ +/*32*/ uint8_t cdb32[32]; /* + * CDB storage for cdbs of size + * 13->32. We store them here + * because hardware scbs are + * allocated from DMA safe + * memory so we are guaranteed + * the controller can access + * this data. + */ +}; + +/************************ Kernel SCB Definitions ******************************/ +/* + * Some fields of the SCB are OS dependent. Here we collect the + * definitions for elements that all OS platforms need to include + * in there SCB definition. + */ + +/* + * Definition of a scatter/gather element as transfered to the controller. + * The aic7xxx chips only support a 24bit length. We use the top byte of + * the length to store additional address bits and a flag to indicate + * that a given segment terminates the transfer. This gives us an + * addressable range of 512GB on machines with 64bit PCI or with chips + * that can support dual address cycles on 32bit PCI busses. + */ +struct ahc_dma_seg { + uint32_t addr; + uint32_t len; +#define AHC_DMA_LAST_SEG 0x80000000 +#define AHC_SG_HIGH_ADDR_MASK 0x7F000000 +#define AHC_SG_LEN_MASK 0x00FFFFFF +}; + +/* + * The current state of this SCB. + */ +typedef enum { + SCB_FREE = 0x0000, + SCB_OTHERTCL_TIMEOUT = 0x0002,/* + * Another device was active + * during the first timeout for + * this SCB so we gave ourselves + * an additional timeout period + * in case it was hogging the + * bus. + */ + SCB_DEVICE_RESET = 0x0004, + SCB_SENSE = 0x0008, + SCB_CDB32_PTR = 0x0010, + SCB_RECOVERY_SCB = 0x0040, + SCB_NEGOTIATE = 0x0080, + SCB_ABORT = 0x1000, + SCB_UNTAGGEDQ = 0x2000, + SCB_ACTIVE = 0x4000, + SCB_TARGET_IMMEDIATE = 0x8000 +} scb_flag; + +struct scb { + struct hardware_scb *hscb; + union { + SLIST_ENTRY(scb) sle; + TAILQ_ENTRY(scb) tqe; + } links; + LIST_ENTRY(scb) pending_links; + ahc_io_ctx_t io_ctx; + struct ahc_softc *ahc_softc; + scb_flag flags; +#ifndef __linux__ + bus_dmamap_t dmamap; +#endif + struct scb_platform_data *platform_data; + struct ahc_dma_seg *sg_list; + bus_addr_t sg_list_phys; + u_int sg_count;/* How full ahc_dma_seg is */ +}; + +struct sg_map_node { + bus_dmamap_t sg_dmamap; + bus_addr_t sg_physaddr; + struct ahc_dma_seg* sg_vaddr; + SLIST_ENTRY(sg_map_node) links; +}; + +struct scb_data { + SLIST_HEAD(, scb) free_scbs; /* + * Pool of SCBs ready to be assigned + * commands to execute. + */ + struct scb *scbindex[AHC_SCB_MAX + 1];/* Mapping from tag to SCB */ + struct hardware_scb *hscbs; /* Array of hardware SCBs */ + struct scb *scbarray; /* Array of kernel SCBs */ + struct scsi_sense_data *sense; /* Per SCB sense data */ + + /* + * "Bus" addresses of our data structures. + */ + bus_dma_tag_t hscb_dmat; /* dmat for our hardware SCB array */ + bus_dmamap_t hscb_dmamap; + bus_addr_t hscb_busaddr; + bus_dma_tag_t sense_dmat; + bus_dmamap_t sense_dmamap; + bus_addr_t sense_busaddr; + bus_dma_tag_t sg_dmat; /* dmat for our sg segments */ + SLIST_HEAD(, sg_map_node) sg_maps; + uint8_t numscbs; + uint8_t maxhscbs; /* Number of SCBs on the card */ + uint8_t init_level; /* + * How far we've initialized + * this structure. + */ +}; + +/************************ Target Mode Definitions *****************************/ + +/* + * Connection desciptor for select-in requests in target mode. + */ +struct target_cmd { + uint8_t scsiid; /* Our ID and the initiator's ID */ + uint8_t identify; /* Identify message */ + uint8_t bytes[22]; /* + * Bytes contains any additional message + * bytes terminated by 0xFF. The remainder + * is the cdb to execute. + */ + uint8_t cmd_valid; /* + * When a command is complete, the firmware + * will set cmd_valid to all bits set. + * After the host has seen the command, + * the bits are cleared. This allows us + * to just peek at host memory to determine + * if more work is complete. cmd_valid is on + * an 8 byte boundary to simplify setting + * it on aic7880 hardware which only has + * limited direct access to the DMA FIFO. + */ + uint8_t pad[7]; +}; + +/* + * Number of events we can buffer up if we run out + * of immediate notify ccbs. + */ +#define AHC_TMODE_EVENT_BUFFER_SIZE 8 +struct ahc_tmode_event { + uint8_t initiator_id; + uint8_t event_type; /* MSG type or EVENT_TYPE_BUS_RESET */ +#define EVENT_TYPE_BUS_RESET 0xFF + uint8_t event_arg; +}; + +/* + * Per enabled lun target mode state. + * As this state is directly influenced by the host OS'es target mode + * environment, we let the OS module define it. Forward declare the + * structure here so we can store arrays of them, etc. in OS neutral + * data structures. + */ +#ifdef AHC_TARGET_MODE +struct tmode_lstate { + struct cam_path *path; + struct ccb_hdr_slist accept_tios; + struct ccb_hdr_slist immed_notifies; + struct ahc_tmode_event event_buffer[AHC_TMODE_EVENT_BUFFER_SIZE]; + uint8_t event_r_idx; + uint8_t event_w_idx; +}; +#else +struct tmode_lstate; +#endif + +/******************** Transfer Negotiation Datastructures *********************/ +#define AHC_TRANS_CUR 0x01 /* Modify current neogtiation status */ +#define AHC_TRANS_ACTIVE 0x03 /* Assume this target is on the bus */ +#define AHC_TRANS_GOAL 0x04 /* Modify negotiation goal */ +#define AHC_TRANS_USER 0x08 /* Modify user negotiation settings */ + +/* + * Transfer Negotiation Information. + */ +struct ahc_transinfo { + uint8_t protocol_version; /* SCSI Revision level */ + uint8_t transport_version; /* SPI Revision level */ + uint8_t width; /* Bus width */ + uint8_t period; /* Sync rate factor */ + uint8_t offset; /* Sync offset */ + uint8_t ppr_options; /* Parallel Protocol Request options */ +}; + +/* + * Per-initiator current, goal and user transfer negotiation information. */ +struct ahc_initiator_tinfo { + uint8_t scsirate; /* Computed value for SCSIRATE reg */ + struct ahc_transinfo current; + struct ahc_transinfo goal; + struct ahc_transinfo user; +}; + +/* + * Per enabled target ID state. + * Pointers to lun target state as well as sync/wide negotiation information + * for each initiator<->target mapping. For the initiator role we pretend + * that we are the target and the targets are the initiators since the + * negotiation is the same regardless of role. + */ +struct tmode_tstate { + struct tmode_lstate* enabled_luns[AHC_NUM_LUNS]; + struct ahc_initiator_tinfo transinfo[AHC_NUM_TARGETS]; + + /* + * Per initiator state bitmasks. + */ + uint16_t ultraenb; /* Using ultra sync rate */ + uint16_t discenable; /* Disconnection allowed */ + uint16_t tagenable; /* Tagged Queuing allowed */ +}; + +/* + * Data structure for our table of allowed synchronous transfer rates. + */ +struct ahc_syncrate { + u_int sxfr_u2; /* Value of the SXFR parameter for Ultra2+ Chips */ + u_int sxfr; /* Value of the SXFR parameter for <= Ultra Chips */ +#define ULTRA_SXFR 0x100 /* Rate Requires Ultra Mode set */ +#define ST_SXFR 0x010 /* Rate Single Transition Only */ +#define DT_SXFR 0x040 /* Rate Double Transition Only */ + uint8_t period; /* Period to send to SCSI target */ + char *rate; +}; + +/* + * The synchronouse transfer rate table. + */ +extern struct ahc_syncrate ahc_syncrates[]; + +/* + * Indexes into our table of syncronous transfer rates. + */ +#define AHC_SYNCRATE_DT 0 +#define AHC_SYNCRATE_ULTRA2 1 +#define AHC_SYNCRATE_ULTRA 3 +#define AHC_SYNCRATE_FAST 6 + +/***************************** Lookup Tables **********************************/ +/* + * Textual descriptions of the different chips indexed by chip type. + */ +extern char *ahc_chip_names[]; +extern const u_int num_chip_names; + +/* + * Hardware error codes. + */ +struct hard_error_entry { + uint8_t errno; + char *errmesg; +}; +extern struct hard_error_entry hard_error[]; +extern const u_int num_errors; + +/* + * Phase -> name and message out response + * to parity errors in each phase table. + */ +struct phase_table_entry { + uint8_t phase; + uint8_t mesg_out; /* Message response to parity errors */ + char *phasemsg; +}; +extern struct phase_table_entry phase_table[]; +extern const u_int num_phases; + +/************************** Serial EEPROM Format ******************************/ + +struct seeprom_config { +/* + * Per SCSI ID Configuration Flags + */ + uint16_t device_flags[16]; /* words 0-15 */ +#define CFXFER 0x0007 /* synchronous transfer rate */ +#define CFSYNCH 0x0008 /* enable synchronous transfer */ +#define CFDISC 0x0010 /* enable disconnection */ +#define CFWIDEB 0x0020 /* wide bus device */ +#define CFSYNCHISULTRA 0x0040 /* CFSYNCH is an ultra offset (2940AU)*/ +#define CFSYNCSINGLE 0x0080 /* Single-Transition signalling */ +#define CFSTART 0x0100 /* send start unit SCSI command */ +#define CFINCBIOS 0x0200 /* include in BIOS scan */ +#define CFRNFOUND 0x0400 /* report even if not found */ +#define CFMULTILUNDEV 0x0800 /* Probe multiple luns in BIOS scan */ +#define CFWBCACHEENB 0x4000 /* Enable W-Behind Cache on disks */ +#define CFWBCACHENOP 0xc000 /* Don't touch W-Behind Cache */ + +/* + * BIOS Control Bits + */ + uint16_t bios_control; /* word 16 */ +#define CFSUPREM 0x0001 /* support all removeable drives */ +#define CFSUPREMB 0x0002 /* support removeable boot drives */ +#define CFBIOSEN 0x0004 /* BIOS enabled */ +/* UNUSED 0x0008 */ +#define CFSM2DRV 0x0010 /* support more than two drives */ +#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ +#define CFSTPWLEVEL 0x0010 /* Termination level control */ +#define CFEXTEND 0x0080 /* extended translation enabled */ +#define CFSCAMEN 0x0100 /* SCAM enable */ +/* UNUSED 0xff00 */ + +/* + * Host Adapter Control Bits + */ + uint16_t adapter_control; /* word 17 */ +#define CFAUTOTERM 0x0001 /* Perform Auto termination */ +#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable */ +#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */ +#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */ +#define CFSTERM 0x0004 /* SCSI low byte termination */ +#define CFWSTERM 0x0008 /* SCSI high byte termination */ +#define CFSPARITY 0x0010 /* SCSI parity */ +#define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */ +#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */ +#define CFRESETB 0x0040 /* reset SCSI bus at boot */ +#define CFCLUSTERENB 0x0080 /* Cluster Enable */ +#define CFCHNLBPRIMARY 0x0100 /* aic7895 probe B channel first */ +#define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/ +#define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */ +#define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */ +#define CFDOMAINVAL 0x4000 /* Perform Domain Validation*/ + +/* + * Bus Release Time, Host Adapter ID + */ + uint16_t brtime_id; /* word 18 */ +#define CFSCSIID 0x000f /* host adapter SCSI ID */ +/* UNUSED 0x00f0 */ +#define CFBRTIME 0xff00 /* bus release time */ + +/* + * Maximum targets + */ + uint16_t max_targets; /* word 19 */ +#define CFMAXTARG 0x00ff /* maximum targets */ +#define CFBOOTLUN 0x0f00 /* Lun to boot from */ +#define CFBOOTID 0xf000 /* Target to boot from */ + uint16_t res_1[10]; /* words 20-29 */ + uint16_t signature; /* Signature == 0x250 */ +#define CFSIGNATURE 0x250 + uint16_t checksum; /* word 31 */ +}; + +/**************************** Message Buffer *********************************/ +typedef enum { + MSG_TYPE_NONE = 0x00, + MSG_TYPE_INITIATOR_MSGOUT = 0x01, + MSG_TYPE_INITIATOR_MSGIN = 0x02, + MSG_TYPE_TARGET_MSGOUT = 0x03, + MSG_TYPE_TARGET_MSGIN = 0x04 +} ahc_msg_type; + +typedef enum { + MSGLOOP_IN_PROG, + MSGLOOP_MSGCOMPLETE, + MSGLOOP_TERMINATED +} msg_loop_stat; + +/*********************** Software Configuration Structure *********************/ +TAILQ_HEAD(scb_tailq, scb); + +struct ahc_suspend_channel_state { + uint8_t scsiseq; + uint8_t sxfrctl0; + uint8_t sxfrctl1; + uint8_t simode0; + uint8_t simode1; + uint8_t seltimer; + uint8_t seqctl; +}; + +struct ahc_suspend_state { + struct ahc_suspend_channel_state channel[2]; + uint8_t optionmode; + uint8_t dscommand0; + uint8_t dspcistatus; + /* hsmailbox */ + uint8_t crccontrol1; + uint8_t scbbaddr; + /* Host and sequencer SCB counts */ + uint8_t dff_thrsh; + uint8_t *scratch_ram; + uint8_t *btt; +}; + +struct ahc_softc { + bus_space_tag_t tag; + bus_space_handle_t bsh; +#ifndef __linux__ + bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */ +#endif + struct scb_data *scb_data; + + struct scb *next_queued_scb; + + /* + * SCBs that have been sent to the controller + */ + LIST_HEAD(, scb) pending_scbs; + + /* + * Counting lock for deferring the release of additional + * untagged transactions from the untagged_queues. When + * the lock is decremented to 0, all queues in the + * untagged_queues array are run. + */ + u_int untagged_queue_lock; + + /* + * Per-target queue of untagged-transactions. The + * transaction at the head of the queue is the + * currently pending untagged transaction for the + * target. The driver only allows a single untagged + * transaction per target. + */ + struct scb_tailq untagged_queues[AHC_NUM_TARGETS]; + + /* + * Platform specific data. + */ + struct ahc_platform_data *platform_data; + + /* + * Platform specific device information. + */ + ahc_dev_softc_t dev_softc; + + /* + * Target mode related state kept on a per enabled lun basis. + * Targets that are not enabled will have null entries. + * As an initiator, we keep one target entry for our initiator + * ID to store our sync/wide transfer settings. + */ + struct tmode_tstate* enabled_targets[AHC_NUM_TARGETS]; + + /* + * The black hole device responsible for handling requests for + * disabled luns on enabled targets. + */ + struct tmode_lstate* black_hole; + + /* + * Device instance currently on the bus awaiting a continue TIO + * for a command that was not given the disconnect priveledge. + */ + struct tmode_lstate* pending_device; + + /* + * Card characteristics + */ + ahc_chip chip; + ahc_feature features; + ahc_bug bugs; + ahc_flag flags; + + /* Values to store in the SEQCTL register for pause and unpause */ + uint8_t unpause; + uint8_t pause; + + /* Command Queues */ + uint8_t qoutfifonext; + uint8_t qinfifonext; + uint8_t *qoutfifo; + uint8_t *qinfifo; + + /* Critical Section Data */ + struct cs *critical_sections; + u_int num_critical_sections; + + /* Links for chaining softcs */ + TAILQ_ENTRY(ahc_softc) links; + + /* Channel Names ('A', 'B', etc.) */ + char channel; + char channel_b; + + /* Initiator Bus ID */ + uint8_t our_id; + uint8_t our_id_b; + + /* Targets that need negotiation messages */ + uint16_t targ_msg_req; + + /* + * PCI error detection. + */ + int unsolicited_ints; + + /* + * Target incoming command FIFO. + */ + struct target_cmd *targetcmds; + uint8_t tqinfifonext; + + /* + * Incoming and outgoing message handling. + */ + uint8_t send_msg_perror; + ahc_msg_type msg_type; + uint8_t msgout_buf[12];/* Message we are sending */ + uint8_t msgin_buf[12];/* Message we are receiving */ + u_int msgout_len; /* Length of message to send */ + u_int msgout_index; /* Current index in msgout */ + u_int msgin_index; /* Current index in msgin */ + + /* + * Mapping information for data structures shared + * between the sequencer and kernel. + */ + bus_dma_tag_t parent_dmat; + bus_dma_tag_t shared_data_dmat; + bus_dmamap_t shared_data_dmamap; + bus_addr_t shared_data_busaddr; + + /* + * Bus address of the one byte buffer used to + * work-around a DMA bug for chips <= aic7880 + * in target mode. + */ + bus_addr_t dma_bug_buf; + + /* Information saved through suspend/resume cycles */ + struct ahc_suspend_state suspend_state; + + /* Number of enabled target mode device on this card */ + u_int enabled_luns; + + /* Initialization level of this data structure */ + u_int init_level; + + /* PCI cacheline size. */ + u_int pci_cachesize; + + /* Per-Unit descriptive information */ + const char *description; + char *name; + int unit; + + /* Selection Timer settings */ + int seltime; + int seltime_b; + + uint16_t user_discenable;/* Disconnection allowed */ + uint16_t user_tagenable;/* Tagged Queuing allowed */ +}; + +TAILQ_HEAD(ahc_softc_tailq, ahc_softc); +extern struct ahc_softc_tailq ahc_tailq; + +/************************ Active Device Information ***************************/ +typedef enum { + ROLE_UNKNOWN, + ROLE_INITIATOR, + ROLE_TARGET +} role_t; + +struct ahc_devinfo { + int our_scsiid; + int target_offset; + uint16_t target_mask; + u_int target; + u_int lun; + char channel; + role_t role; /* + * Only guaranteed to be correct if not + * in the busfree state. + */ +}; + +/****************************** PCI Structures ********************************/ +typedef int (ahc_device_setup_t)(ahc_dev_softc_t, + struct ahc_probe_config *); + +struct ahc_pci_identity { + uint64_t full_id; + uint64_t id_mask; + char *name; + ahc_device_setup_t *setup; +}; +extern struct ahc_pci_identity ahc_pci_ident_table []; +extern const u_int ahc_num_pci_devs; + +/***************************** VL/EISA Declarations ***************************/ +struct aic7770_identity { + uint32_t full_id; + uint32_t id_mask; + char *name; + ahc_device_setup_t *setup; +}; +extern struct aic7770_identity aic7770_ident_table []; +extern const int ahc_num_aic7770_devs; + +#define AHC_EISA_SLOT_OFFSET 0xc00 +#define AHC_EISA_IOSIZE 0x100 + +/*************************** Function Declarations ****************************/ +/******************************************************************************/ +u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl); +void ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl); +void ahc_busy_tcl(struct ahc_softc *ahc, + u_int tcl, u_int busyid); + +/***************************** PCI Front End *********************************/ +struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t); +int ahc_pci_config(struct ahc_softc *, + struct ahc_pci_identity *); + +/*************************** EISA/VL Front End ********************************/ +struct aic7770_identity *aic7770_find_device(uint32_t); +int aic7770_config(struct ahc_softc *ahc, + struct aic7770_identity *); + +/************************** SCB and SCB queue management **********************/ +int ahc_probe_scbs(struct ahc_softc *); +void ahc_run_untagged_queues(struct ahc_softc *ahc); +void ahc_run_untagged_queue(struct ahc_softc *ahc, + struct scb_tailq *queue); +void ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, + struct scb *scb); +int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, + int target, char channel, int lun, + u_int tag, role_t role); + +/****************************** Initialization ********************************/ +void ahc_init_probe_config(struct ahc_probe_config *); +struct ahc_softc *ahc_alloc(void *platform_arg, char *name); +int ahc_softc_init(struct ahc_softc *, + struct ahc_probe_config*); +void ahc_controller_info(struct ahc_softc *ahc, char *buf); +int ahc_init(struct ahc_softc *ahc); +void ahc_pause_and_flushwork(struct ahc_softc *ahc); +int ahc_suspend(struct ahc_softc *ahc); +int ahc_resume(struct ahc_softc *ahc); +void ahc_softc_insert(struct ahc_softc *); +void ahc_set_unit(struct ahc_softc *, int); +void ahc_set_name(struct ahc_softc *, char *); +void ahc_alloc_scbs(struct ahc_softc *ahc); +void ahc_free(struct ahc_softc *ahc); +int ahc_reset(struct ahc_softc *ahc); +void ahc_shutdown(void *arg); + +/*************************** Interrupt Services *******************************/ +void ahc_pci_intr(struct ahc_softc *ahc); +void ahc_clear_intstat(struct ahc_softc *ahc); +void ahc_run_qoutfifo(struct ahc_softc *ahc); +#ifdef AHC_TARGET_MODE +void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused); +#endif +void ahc_handle_brkadrint(struct ahc_softc *ahc); +void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat); +void ahc_handle_scsiint(struct ahc_softc *ahc, + u_int intstat); +void ahc_clear_critical_section(struct ahc_softc *ahc); + +/***************************** Error Recovery *********************************/ +typedef enum { + SEARCH_COMPLETE, + SEARCH_COUNT, + SEARCH_REMOVE +} ahc_search_action; +int ahc_search_qinfifo(struct ahc_softc *ahc, int target, + char channel, int lun, u_int tag, + role_t role, uint32_t status, + ahc_search_action action); +int ahc_search_disc_list(struct ahc_softc *ahc, int target, + char channel, int lun, u_int tag, + int stop_on_first, int remove, + int save_state); +void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb); +int ahc_reset_channel(struct ahc_softc *ahc, char channel, + int initiate_reset); +void restart_sequencer(struct ahc_softc *ahc); +/*************************** Utility Functions ********************************/ +void ahc_compile_devinfo(struct ahc_devinfo *devinfo, + u_int our_id, u_int target, + u_int lun, char channel, + role_t role); +/************************** Transfer Negotiation ******************************/ +struct ahc_syncrate* ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, + u_int *ppr_options, u_int maxsync); +u_int ahc_find_period(struct ahc_softc *ahc, + u_int scsirate, u_int maxsync); +void ahc_validate_offset(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, + struct ahc_syncrate *syncrate, + u_int *offset, int wide, + role_t role); +void ahc_validate_width(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, + u_int *bus_width, + role_t role); +void ahc_update_target_msg_request(struct ahc_softc *ahc, + struct ahc_devinfo *dinfo, + struct ahc_initiator_tinfo *tinfo, + int force, int paused); +void ahc_set_width(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + u_int width, u_int type, int paused); +void ahc_set_syncrate(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, + struct ahc_syncrate *syncrate, + u_int period, u_int offset, + u_int ppr_options, + u_int type, int paused); +void ahc_set_tags(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, int enable); + +/**************************** Target Mode *************************************/ +#ifdef AHC_TARGET_MODE +void ahc_send_lstate_events(struct ahc_softc *, + struct tmode_lstate *); +void ahc_handle_en_lun(struct ahc_softc *ahc, + struct cam_sim *sim, union ccb *ccb); +cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, + struct cam_sim *sim, union ccb *ccb, + struct tmode_tstate **tstate, + struct tmode_lstate **lstate, + int notfound_failure); +void ahc_setup_target_msgin(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); +#ifndef AHC_TMODE_ENABLE +#define AHC_TMODE_ENABLE 0 +#endif +#endif +/******************************* Debug ***************************************/ +void ahc_print_scb(struct scb *scb); +void ahc_dump_card_state(struct ahc_softc *ahc); +#endif /* _AIC7XXX_H_ */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.reg Thu Feb 10 19:00:35 2000 +++ linux/drivers/scsi/aic7xxx/aic7xxx.reg Sun Mar 4 14:30:18 2001 @@ -1,7 +1,7 @@ /* * Aic7xxx register and scratch ram definitions. * - * Copyright (c) 1994-1998 Justin Gibbs. + * Copyright (c) 1994-2001 Justin Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -9,16 +9,12 @@ * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. + * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * - * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -32,7 +28,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $ + * $Id: //depot/src/aic7xxx/aic7xxx.reg#13 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.31 2000/11/10 20:13:40 gibbs Exp $ */ /* @@ -114,6 +112,8 @@ mask PHASE_MASK CDI|IOI|MSGI mask P_DATAOUT 0x00 mask P_DATAIN IOI + mask P_DATAOUT_DT P_DATAOUT|MSGI + mask P_DATAIN_DT P_DATAIN|MSGI mask P_COMMAND CDI mask P_MESGOUT CDI|MSGI mask P_STATUS CDI|IOI @@ -160,8 +160,10 @@ address 0x004 access_mode RW bit WIDEXFER 0x80 /* Wide transfer control */ + bit ENABLE_CRC 0x40 /* CRC for D-Phases */ + bit SINGLE_EDGE 0x10 /* Disable DT Transfers */ mask SXFR 0x70 /* Sync transfer rate */ - mask SXFR_ULTRA2 0x7f /* Sync transfer rate */ + mask SXFR_ULTRA2 0x0f /* Sync transfer rate */ mask SOFS 0x0f /* Sync offset */ } @@ -174,6 +176,8 @@ address 0x005 access_mode RW mask TID 0xf0 /* Target ID mask */ + mask TWIN_TID 0x70 + bit TWIN_CHNLB 0x80 mask OID 0x0f /* Our ID mask */ /* * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book) @@ -213,24 +217,27 @@ access_mode RW } -/* - * Option Mode Register (Alternate Mode) (p. 5-198) - * This register is used to set certain options on Ultra3 based chips. - * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set) - */ +/* ALT_MODE register on Ultra160 chips */ register OPTIONMODE { address 0x008 access_mode RW - bit AUTORATEEN 0x80 - bit AUTOACKEN 0x40 - bit ATNMGMNTEN 0x20 - bit BUSFREEREV 0x10 - bit EXPPHASEDIS 0x08 - bit SCSIDATL_IMGEN 0x04 - bit AUTO_MSGOUT_DE 0x02 + bit AUTORATEEN 0x80 + bit AUTOACKEN 0x40 + bit ATNMGMNTEN 0x20 + bit BUSFREEREV 0x10 + bit EXPPHASEDIS 0x08 + bit SCSIDATL_IMGEN 0x04 + bit AUTO_MSGOUT_DE 0x02 bit DIS_MSGIN_DUALEDGE 0x01 + mask OPTIONMODE_DEFAULTS AUTO_MSGOUT_DE|DIS_MSGIN_DUALEDGE } +/* ALT_MODE register on Ultra160 chips */ +register TARGCRCCNT { + address 0x00a + size 2 + access_mode RW +} /* * Clear SCSI Interrupt 0 (p. 3-20) @@ -243,6 +250,7 @@ bit CLRSELDI 0x20 bit CLRSELINGO 0x10 bit CLRSWRAP 0x08 + bit CLRIOERR 0x08 /* Ultra2 Only */ bit CLRSPIORDY 0x02 } @@ -304,13 +312,12 @@ address 0x00d access_mode RO bit OVERRUN 0x80 - bit SHVALID 0x40 - bit WIDE_RES 0x20 + bit SHVALID 0x40 /* Shaddow Layer non-zero */ bit EXP_ACTIVE 0x10 /* SCSI Expander Active */ - bit CRCVALERR 0x08 /* CRC Value Error */ - bit CRCENDERR 0x04 /* CRC End Error */ - bit CRCREQERR 0x02 /* CRC REQ Error */ - bit DUAL_EDGE_ERROR 0x01 /* Invalid pins for Dual Edge phase */ + bit CRCVALERR 0x08 /* CRC doesn't match (U3 only) */ + bit CRCENDERR 0x04 /* No terminal CRC packet (U3 only) */ + bit CRCREQERR 0x02 /* Illegal CRC packet req (U3 only) */ + bit DUAL_EDGE_ERR 0x01 /* Incorrect data phase (U3 only) */ mask SFCNT 0x1f } @@ -376,12 +383,12 @@ */ register SCSIBUSL { address 0x012 - access_mode RO + access_mode RW } register SCSIBUSH { address 0x013 - access_mode RO + access_mode RW } /* @@ -410,6 +417,7 @@ bit STAGE3 0x04 bit STAGE2 0x02 bit STAGE1 0x01 + alias TARGIDIN } /* @@ -424,6 +432,25 @@ bit ONEBIT 0x08 } +register SCAMCTL { + address 0x01a + access_mode RW + bit ENSCAMSELO 0x80 + bit CLRSCAMSELID 0x40 + bit ALTSTIM 0x20 + bit DFLTTID 0x10 + mask SCAMLVL 0x03 +} + +/* + * Target Mode Selecting in ID bitmask (aic7890/91/96/97) + */ +register TARGID { + address 0x01b + size 2 + access_mode RW +} + /* * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book) * Indicates if external logic has been attached to the chip to @@ -445,6 +472,59 @@ bit SSPIOCPS 0x01 /* Termination and cable detection */ } +register BRDCTL { + address 0x01d + bit BRDDAT7 0x80 + bit BRDDAT6 0x40 + bit BRDDAT5 0x20 + bit BRDSTB 0x10 + bit BRDCS 0x08 + bit BRDRW 0x04 + bit BRDCTL1 0x02 + bit BRDCTL0 0x01 + /* 7890 Definitions */ + bit BRDDAT4 0x10 + bit BRDDAT3 0x08 + bit BRDDAT2 0x04 + bit BRDRW_ULTRA2 0x02 + bit BRDSTB_ULTRA2 0x01 +} + +/* + * Serial EEPROM Control (p. 4-92 in 7870 Databook) + * Controls the reading and writing of an external serial 1-bit + * EEPROM Device. In order to access the serial EEPROM, you must + * first set the SEEMS bit that generates a request to the memory + * port for access to the serial EEPROM device. When the memory + * port is not busy servicing another request, it reconfigures + * to allow access to the serial EEPROM. When this happens, SEERDY + * gets set high to verify that the memory port access has been + * granted. + * + * After successful arbitration for the memory port, the SEECS bit of + * the SEECTL register is connected to the chip select. The SEECK, + * SEEDO, and SEEDI are connected to the clock, data out, and data in + * lines respectively. The SEERDY bit of SEECTL is useful in that it + * gives us an 800 nsec timer. After a write to the SEECTL register, + * the SEERDY goes high 800 nsec later. The one exception to this is + * when we first request access to the memory port. The SEERDY goes + * high to signify that access has been granted and, for this case, has + * no implied timing. + * + * See 93cx6.c for detailed information on the protocol necessary to + * read the serial EEPROM. + */ +register SEECTL { + address 0x01e + bit EXTARBACK 0x80 + bit EXTARBREQ 0x40 + bit SEEMS 0x20 + bit SEERDY 0x10 + bit SEECS 0x08 + bit SEECK 0x04 + bit SEEDO 0x02 + bit SEEDI 0x01 +} /* * SCSI Block Control (p. 3-32) * Controls Bus type and channel selection. In a twin channel configuration @@ -585,30 +665,22 @@ bit ENABLE 0x01 } -register DSCOMMAND0 { - address 0x084 - access_mode RW - bit CACHETHEN 0x80 - bit DPARCKEN 0x40 - bit MPARCKEN 0x20 - bit EXTREQLCK 0x10 - bit INTSCBRAMSEL 0x08 - bit RAMPS 0x04 - bit USCBSIZE32 0x02 - bit CIOPARCKEN 0x01 -} - /* * On the aic78X0 chips, Board Control is replaced by the DSCommand * register (p. 4-64) */ -register DSCOMMAND { +register DSCOMMAND0 { address 0x084 access_mode RW bit CACHETHEN 0x80 /* Cache Threshold enable */ bit DPARCKEN 0x40 /* Data Parity Check Enable */ bit MPARCKEN 0x20 /* Memory Parity Check Enable */ bit EXTREQLCK 0x10 /* External Request Lock */ + /* aic7890/91/96/97 only */ + bit INTSCBRAMSEL 0x08 /* Internal SCB RAM Select */ + bit RAMPS 0x04 /* External SCB RAM Present */ + bit USCBSIZE32 0x02 /* Use 32byte SCB Page Size */ + bit CIOPARCKEN 0x01 /* Internal bus parity error enable */ } /* @@ -622,7 +694,7 @@ } /* - * Bus Speed (p. 3-45) + * Bus Speed (p. 3-45) aic7770 only */ register BUSSPD { address 0x086 @@ -631,8 +703,26 @@ mask STBOFF 0x38 mask STBON 0x07 mask DFTHRSH_100 0xc0 + mask DFTHRSH_75 0x80 +} + +/* aic7850/55/60/70/80/95 only */ +register DSPCISTATUS { + address 0x086 + mask DFTHRSH_100 0xc0 +} + +/* aic7890/91/96/97 only */ +register HS_MAILBOX { + address 0x086 + mask HOST_MAILBOX 0xF0 + mask SEQ_MAILBOX 0x0F + mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */ } +const HOST_MAILBOX_SHIFT 4 +const SEQ_MAILBOX_SHIFT 0 + /* * Host Control (p. 3-47) R/W * Overall host control of the device. @@ -668,7 +758,7 @@ /* * SCB Pointer (p. 3-49) - * Gate one of the four SCBs into the SCBARRAY window. + * Gate one of the SCBs into the SCBARRAY window. */ register SCBPTR { address 0x090 @@ -690,31 +780,48 @@ mask SEND_REJECT 0x10|SEQINT /* sending a message reject */ mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/ mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */ - mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */ - mask WIDE_RESIDUE 0x50|SEQINT /* need kernel to back up */ - /* the SG array for us */ - mask REJECT_MSG 0x60|SEQINT /* Reject message received */ - mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ - mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */ - mask AWAITING_MSG 0xa0|SEQINT /* - * Kernel requested to specify - * a message to this target - * (command was null), so tell - * it that it can fill the - * message buffer. + mask IGN_WIDE_RES 0x40|SEQINT /* Complex IGN Wide Res Msg */ + mask RESIDUAL 0x50|SEQINT /* Residual byte count != 0 */ + mask HOST_MSG_LOOP 0x60|SEQINT /* + * The bus is ready for the + * host to perform another + * message transaction. This + * mechanism is used for things + * like sync/wide negotiation + * that require a kernel based + * message state engine. */ - mask TRACEPOINT 0xb0|SEQINT - mask TRACEPOINT2 0xc0|SEQINT - mask MSGIN_PHASEMIS 0xd0|SEQINT /* - * Target changed phase on us - * when we were expecting - * another msgin byte. + mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ + mask PERR_DETECTED 0x80|SEQINT /* + * Either the phase_lock + * or inb_next routine has + * noticed a parity error. */ - mask DATA_OVERRUN 0xe0|SEQINT /* + mask DATA_OVERRUN 0x90|SEQINT /* * Target attempted to write * beyond the bounds of its * command. */ + mask MKMSG_FAILED 0xa0|SEQINT /* + * Target completed command + * without honoring our ATN + * request to issue a message. + */ + mask MISSED_BUSFREE 0xb0|SEQINT /* + * The sequencer never saw + * the bus go free after + * either a command complete + * or disconnect message. + */ + mask SCB_MISMATCH 0xc0|SEQINT /* + * Downloaded SCB's tag does + * not match the entry we + * intended to download. + */ + mask NO_FREE_SCB 0xd0|SEQINT /* + * get_free_or_disc_scb failed. + */ + mask OUT_OF_RANGE 0xe0|SEQINT mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */ mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT) @@ -735,7 +842,6 @@ bit SQPARERR 0x08 bit ILLOPCODE 0x04 bit ILLSADDR 0x02 - bit DSCTMOUT 0x02 /* Ultra3 only */ bit ILLHADDR 0x01 } @@ -779,6 +885,16 @@ bit FIFOEMP 0x01 } +register DFWADDR { + address 0x95 + access_mode RW +} + +register DFRADDR { + address 0x97 + access_mode RW +} + register DFDAT { address 0x099 access_mode RW @@ -815,17 +931,6 @@ } /* - * SCSIDATL IMAGE Register (p. 5-104) - * Write to this register also go to SCSIDATL but this register will preserve - * the data for later reading as long as the SCSIDATL_IMGEN bit in the - * OPTIONMODE register is set. - */ -register SCSIDATL_IMG { - address 0x09c - access_mode RW -} - -/* * Queue Out FIFO (p. 3-61) * Queue of SCBs that have completed and await the host */ @@ -834,21 +939,18 @@ access_mode WO } -/* - * CRC Control 1 Register (p. 5-105) - * Control bits for the Ultra 160/m CRC facilities - */ register CRCCONTROL1 { address 0x09d access_mode RW - bit CRCONSEEN 0x80 /* CRC ON Single Edge ENable */ - bit CRCVALCHKEN 0x40 /* CRC Value Check Enable */ - bit CRCENDCHKEN 0x20 /* CRC End Check Enable */ - bit CRCREQCHKEN 0x10 - bit TARGCRCENDEN 0x08 /* Enable End CRC transfer when target */ - bit TARGCRCCNTEN 0x04 /* Enable CRC transfer when target */ + bit CRCONSEEN 0x80 + bit CRCVALCHKEN 0x40 + bit CRCENDCHKEN 0x20 + bit CRCREQCHKEN 0x10 + bit TARGCRCENDEN 0x08 + bit TARGCRCCNTEN 0x04 } + /* * Queue Out Count (p. 3-61) * Number of queued SCBs in the Out FIFO @@ -858,19 +960,15 @@ access_mode RO } -/* - * SCSI Phase Register (p. 5-106) - * Current bus phase - */ register SCSIPHASE { address 0x09e access_mode RO - bit SP_STATUS 0x20 - bit SP_COMMAND 0x10 - bit SP_MSG_IN 0x08 - bit SP_MSG_OUT 0x04 - bit SP_DATA_IN 0x02 - bit SP_DATA_OUT 0x01 + bit STATUS_PHASE 0x20 + bit COMMAND_PHASE 0x10 + bit MSG_IN_PHASE 0x08 + bit MSG_OUT_PHASE 0x04 + bit DATA_IN_PHASE 0x02 + bit DATA_OUT_PHASE 0x01 } /* @@ -887,33 +985,19 @@ */ scb { address 0x0a0 - SCB_CONTROL { - size 1 - bit MK_MESSAGE 0x80 - bit DISCENB 0x40 - bit TAG_ENB 0x20 - bit DISCONNECTED 0x04 - mask SCB_TAG_TYPE 0x03 - } - SCB_TCL { - size 1 - bit SELBUSB 0x08 - mask TID 0xf0 - mask LID 0x07 - } - SCB_TARGET_STATUS { - size 1 - } - SCB_SGCOUNT { - size 1 + SCB_CDB_PTR { + size 4 + alias SCB_RESIDUAL_DATACNT + alias SCB_CDB_STORE + alias SCB_TARGET_INFO } - SCB_SGPTR { + SCB_RESIDUAL_SGPTR { size 4 } - SCB_RESID_SGCNT { + SCB_SCSI_STATUS { size 1 } - SCB_RESID_DCNT { + SCB_CDB_STORE_PAD { size 3 } SCB_DATAPTR { @@ -921,31 +1005,67 @@ } SCB_DATACNT { /* - * Really only 3 bytes, but padded to make - * the kernel's job easier. + * The last byte is really the high address bits for + * the data address. */ size 4 + bit SG_LAST_SEG 0x80 /* In the fourth byte */ + mask SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ } - SCB_CMDPTR { + SCB_SGPTR { size 4 + bit SG_RESID_VALID 0x04 /* In the first byte */ + bit SG_FULL_RESID 0x02 /* In the first byte */ + bit SG_LIST_NULL 0x01 /* In the first byte */ + } + SCB_CONTROL { + size 1 + bit TARGET_SCB 0x80 + bit DISCENB 0x40 + bit TAG_ENB 0x20 + bit MK_MESSAGE 0x10 + bit ULTRAENB 0x08 + bit DISCONNECTED 0x04 + mask SCB_TAG_TYPE 0x03 } - SCB_CMDLEN { + SCB_SCSIID { + size 1 + bit TWIN_CHNLB 0x80 + mask TWIN_TID 0x70 + mask TID 0xf0 + mask OID 0x0f + } + SCB_LUN { + mask LID 0xff size 1 } SCB_TAG { size 1 } - SCB_NEXT { + SCB_CDB_LEN { size 1 } - SCB_PREV { + SCB_SCSIRATE { size 1 } - SCB_BUSYTARGETS { - size 4 + SCB_SCSIOFFSET { + size 1 + } + SCB_NEXT { + size 1 + } + SCB_64_SPARE { + size 16 + } + SCB_64_BTT { + size 16 } } +const SCB_UPLOAD_SIZE 32 +const SCB_DOWNLOAD_SIZE 32 +const SCB_DOWNLOAD_SIZE_64 48 + const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ /* --------------------- AHA-2840-only definitions -------------------- */ @@ -969,11 +1089,6 @@ /* --------------------- AIC-7870-only definitions -------------------- */ -register DSPCISTATUS { - address 0x086 - mask DFTHRSH_100 0xc0 -} - register CCHADDR { address 0x0E0 size 8 @@ -995,7 +1110,7 @@ address 0x0EB bit CCSGDONE 0x80 bit CCSGEN 0x08 - bit FLAG 0x02 + bit SG_FETCH_NEEDED 0x02 /* Bit used for software state */ bit CCSGRESET 0x01 } @@ -1021,6 +1136,14 @@ address 0xEC } +/* + * SCB bank address (7895/7896/97 only) + */ +register SCBBADDR { + address 0x0F0 + access_mode RW +} + register CCSCBPTR { address 0x0F1 } @@ -1029,29 +1152,19 @@ address 0x0F4 } -register HESCB_QOFF { - address 0x0F5 -} - register SNSCB_QOFF { address 0x0F6 } -register SESCB_QOFF { - address 0x0F7 -} - register SDSCB_QOFF { address 0x0F8 } register QOFF_CTLSTA { address 0x0FA - bit ESTABLISH_SCB_AVAIL 0x80 bit SCB_AVAIL 0x40 bit SNSCB_ROLLOVER 0x20 bit SDSCB_ROLLOVER 0x10 - bit SESCB_ROLLOVER 0x08 mask SCB_QSIZE 0x07 mask SCB_QSIZE_256 0x06 } @@ -1078,66 +1191,22 @@ mask WR_DFTHRSH_MAX 0x70 } -register SG_CACHEPTR { - access_mode RW +register SG_CACHE_PRE { + access_mode WO address 0x0fc - mask SG_USER_DATA 0xfc + mask SG_ADDR_MASK 0xf8 + bit ODD_SEG 0x04 bit LAST_SEG 0x02 bit LAST_SEG_DONE 0x01 } -register BRDCTL { - address 0x01d - bit BRDDAT7 0x80 - bit BRDDAT6 0x40 - bit BRDDAT5 0x20 - bit BRDSTB 0x10 - bit BRDCS 0x08 - bit BRDRW 0x04 - bit BRDCTL1 0x02 - bit BRDCTL0 0x01 - /* 7890 Definitions */ - bit BRDDAT4 0x10 - bit BRDDAT3 0x08 - bit BRDDAT2 0x04 - bit BRDRW_ULTRA2 0x02 - bit BRDSTB_ULTRA2 0x01 -} - -/* - * Serial EEPROM Control (p. 4-92 in 7870 Databook) - * Controls the reading and writing of an external serial 1-bit - * EEPROM Device. In order to access the serial EEPROM, you must - * first set the SEEMS bit that generates a request to the memory - * port for access to the serial EEPROM device. When the memory - * port is not busy servicing another request, it reconfigures - * to allow access to the serial EEPROM. When this happens, SEERDY - * gets set high to verify that the memory port access has been - * granted. - * - * After successful arbitration for the memory port, the SEECS bit of - * the SEECTL register is connected to the chip select. The SEECK, - * SEEDO, and SEEDI are connected to the clock, data out, and data in - * lines respectively. The SEERDY bit of SEECTL is useful in that it - * gives us an 800 nsec timer. After a write to the SEECTL register, - * the SEERDY goes high 800 nsec later. The one exception to this is - * when we first request access to the memory port. The SEERDY goes - * high to signify that access has been granted and, for this case, has - * no implied timing. - * - * See 93cx6.c for detailed information on the protocol necessary to - * read the serial EEPROM. - */ -register SEECTL { - address 0x01e - bit EXTARBACK 0x80 - bit EXTARBREQ 0x40 - bit SEEMS 0x20 - bit SEERDY 0x10 - bit SEECS 0x08 - bit SEECK 0x04 - bit SEEDO 0x02 - bit SEEDI 0x01 +register SG_CACHE_SHADOW { + access_mode RO + address 0x0fc + mask SG_ADDR_MASK 0xf8 + bit ODD_SEG 0x04 + bit LAST_SEG 0x02 + bit LAST_SEG_DONE 0x01 } /* ---------------------- Scratch RAM Offsets ------------------------- */ /* These offsets are either to values that are initialized by the board's @@ -1160,21 +1229,46 @@ /* * 1 byte per target starting at this address for configuration values */ - TARG_SCSIRATE { + BUSY_TARGETS { + alias TARG_SCSIRATE size 16 } /* - * Bit vector of targets that have ULTRA enabled. + * Bit vector of targets that have ULTRA enabled as set by + * the BIOS. The Sequencer relies on a per-SCB field to + * control whether to enable Ultra transfers or not. During + * initialization, we read this field and reuse it for 2 + * entries in the busy target table. */ ULTRA_ENB { + alias CMDSIZE_TABLE size 2 } /* - * Bit vector of targets that have disconnection disabled. + * Bit vector of targets that have disconnection disabled as set by + * the BIOS. The Sequencer relies in a per-SCB field to control the + * disconnect priveldge. During initialization, we read this field + * and reuse it for 2 entries in the busy target table. */ DISC_DSB { size 2 } + CMDSIZE_TABLE_TAIL { + size 4 + } + /* + * Partial transfer past cacheline end to be + * transferred using an extra S/G. + */ + MWI_RESIDUAL { + size 1 + } + /* + * SCBID of the next SCB to be started by the controller. + */ + NEXT_QUEUED_SCB { + size 1 + } /* * Single byte buffer used to designate the type or message * to send to a target. @@ -1198,29 +1292,27 @@ } SEQ_FLAGS { size 1 - bit IDENTIFY_SEEN 0x80 - bit SCBPTR_VALID 0x20 - bit DPHASE 0x10 - bit AMTARGET 0x08 - bit WIDE_BUS 0x02 - bit TWIN_BUS 0x01 + bit IDENTIFY_SEEN 0x80 + bit TARGET_CMD_IS_TAGGED 0x40 + bit DPHASE 0x20 + /* Target flags */ + bit TARG_CMD_PENDING 0x10 + bit CMDPHASE_PENDING 0x08 + bit DPHASE_PENDING 0x04 + bit SPHASE_PENDING 0x02 + bit NO_DISCONNECT 0x01 } /* * Temporary storage for the * target/channel/lun of a * reconnecting target */ - SAVED_TCL { + SAVED_SCSIID { size 1 } - /* Working value of the number of SG segments left */ - SG_COUNT { + SAVED_LUN { size 1 } - /* Working value of SG pointer */ - SG_NEXT { - size 4 - } /* * The last bus phase as seen by the sequencer. */ @@ -1261,23 +1353,25 @@ size 1 } /* - * Address of the hardware scb array in the host. + * head of list of SCBs that have + * completed but have not been + * put into the qoutfifo. */ - HSCB_ADDR { - size 4 + COMPLETE_SCBH { + size 1 } /* - * Address of the 256 byte array storing the SCBID of outstanding - * untagged SCBs indexed by TCL. + * Address of the hardware scb array in the host. */ - SCBID_ADDR { + HSCB_ADDR { size 4 } /* - * Address of the array of command descriptors used to store - * information about incoming selections. + * Base address of our shared data with the kernel driver in host + * memory. This includes the qoutfifo and target mode + * incoming command queue. */ - TMODE_CMDADDR { + SHARED_DATA_ADDR { size 4 } KERNEL_QINPOS { @@ -1290,18 +1384,25 @@ size 1 } /* - * Offset into the command descriptor array for the next - * available desciptor to use. + * Kernel and sequencer offsets into the queue of + * incoming target mode command descriptors. The + * queue is full when the KERNEL_TQINPOS == TQINPOS. */ - TMODE_CMDADDR_NEXT { + KERNEL_TQINPOS { + size 1 + } + TQINPOS { size 1 } ARG_1 { size 1 - mask SEND_MSG 0x80 - mask SEND_SENSE 0x40 - mask SEND_REJ 0x20 - mask MSGOUT_PHASEMIS 0x10 + mask SEND_MSG 0x80 + mask SEND_SENSE 0x40 + mask SEND_REJ 0x20 + mask MSGOUT_PHASEMIS 0x10 + mask EXIT_MSG_LOOP 0x08 + mask CONT_MSG_LOOP 0x04 + mask CONT_TARG_SESSION 0x02 alias RETURN_1 } ARG_2 { @@ -1317,15 +1418,49 @@ } /* - * Number of times we have filled the CCSGRAM with prefetched - * SG elements. + * Interrupt kernel for a message to this target on + * the next transaction. This is usually used for + * negotiation requests. + */ + TARGET_MSG_REQUEST { + size 2 + } + + /* + * Sequences the kernel driver has okayed for us. This allows + * the driver to do things like prevent initiator or target + * operations. */ - PREFETCH_CNT { + SCSISEQ_TEMPLATE { size 1 + bit ENSELO 0x40 + bit ENSELI 0x20 + bit ENRSELI 0x10 + bit ENAUTOATNO 0x08 + bit ENAUTOATNI 0x04 + bit ENAUTOATNP 0x02 } + /* + * Track whether the transfer byte count for + * the current data phase is odd. + */ + DATA_COUNT_ODD { + size 1 + } /* + * The initiator specified tag for this target mode transaction. + */ + INITIATOR_TAG { + size 1 + } + + SEQ_FLAGS2 { + size 1 + bit SCB_DMA 0x01 + } + /* * These are reserved registers in the card's scratch ram. Some of * the values are specified in the AHA2742 technical reference manual * and are initialized by the BIOS at boot time. @@ -1335,9 +1470,16 @@ size 1 bit TERM_ENB 0x80 bit RESET_SCSI 0x40 + bit ENSPCHK 0x20 mask HSCSIID 0x07 /* our SCSI ID */ mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ } + INTDEF { + address 0x05c + size 1 + bit EDGE_TRIG 0x80 + mask VECTOR 0x0f + } HOSTCONF { address 0x05d size 1 @@ -1358,16 +1500,13 @@ } } +const TID_SHIFT 4 const SCB_LIST_NULL 0xff +const TARGET_CMD_CMPLT 0xfe const CCSGADDR_MAX 0x80 const CCSGRAM_MAXSEGS 16 -/* Offsets into the SCBID array where different data is stored */ -const UNTAGGEDSCB_OFFSET 0 -const QOUTFIFO_OFFSET 1 -const QINFIFO_OFFSET 2 - /* WDTR Message values */ const BUS_8_BIT 0x00 const BUS_16_BIT 0x01 @@ -1381,16 +1520,23 @@ /* Target mode command processing constants */ const CMD_GROUP_CODE_SHIFT 0x05 -const CMD_GROUP0_BYTE_DELTA -4 -const CMD_GROUP2_BYTE_DELTA -6 -const CMD_GROUP4_BYTE_DELTA 4 -const CMD_GROUP5_BYTE_DELTA 11 -/* - * Downloaded (kernel inserted) constants - */ +const STATUS_BUSY 0x08 +const STATUS_QUEUE_FULL 0x28 +const SCB_TARGET_PHASES 0 +const SCB_TARGET_DATA_DIR 1 +const SCB_TARGET_STATUS 2 +const SCB_INITIATOR_TAG 3 +const TARGET_DATA_IN 1 /* - * Number of command descriptors in the command descriptor array. + * Downloaded (kernel inserted) constants */ -const TMODE_NUMCMDS download +/* Offsets into the SCBID array where different data is stored */ +const QOUTFIFO_OFFSET download +const QINFIFO_OFFSET download +const CACHESIZE_MASK download +const INVERTED_CACHESIZE_MASK download +const SG_PREFETCH_CNT download +const SG_PREFETCH_ALIGN_MASK download +const SG_PREFETCH_ADDR_MASK download diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.seq Wed Jun 21 17:25:03 2000 +++ linux/drivers/scsi/aic7xxx/aic7xxx.seq Sun Mar 4 14:30:18 2001 @@ -1,7 +1,7 @@ /* * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. * - * Copyright (c) 1994-1999 Justin Gibbs. + * Copyright (c) 1994-2001 Justin Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -9,16 +9,12 @@ * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. + * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * - * Where this Software is combined with software released under the terms of - * the GNU Public License (GPL) and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -32,7 +28,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $ + * $Id: //depot/src/aic7xxx/aic7xxx.seq#22 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $ */ #include "aic7xxx.reg" @@ -48,7 +46,7 @@ * a later time. This problem cannot be resolved by holding a single entry * in scratch ram since a reconnecting target can request sense and this will * create yet another SCB waiting for selection. The solution used here is to - * use byte 27 of the SCB as a pseudo-next pointer and to thread a list + * use byte 27 of the SCB as a psuedo-next pointer and to thread a list * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to * this list everytime a request sense occurs or after completing a non-tagged @@ -56,200 +54,386 @@ * automatically consume the entries. */ -reset: - clr SCSISIGO; /* De-assert BSY */ - and SXFRCTL1, ~BITBUCKET; - /* Always allow reselection */ - mvi SCSISEQ, ENRSELI|ENAUTOATNP; - - if ((p->features & AHC_CMD_CHAN) != 0) { - /* Ensure that no DMA operations are in progress */ - clr CCSGCTL; - clr CCSCBCTL; - } - - call clear_target_state; +bus_free_sel: + /* + * Turn off the selection hardware. We need to reset the + * selection request in order to perform a new selection. + */ + and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; + and SIMODE1, ~ENBUSFREE; poll_for_work: + call clear_target_state; and SXFRCTL0, ~SPIOEN; - if ((p->features & AHC_QUEUE_REGS) == 0) { - mov A, QINPOS; + if ((ahc->features & AHC_ULTRA2) != 0) { + clr SCSIBUSL; } -poll_for_work_loop: - if ((p->features & AHC_QUEUE_REGS) == 0) { - and SEQCTL, ~PAUSEDIS; - } - test SSTAT0, SELDO|SELDI jnz selection; - test SCSISEQ, ENSELO jnz poll_for_work; - if ((p->features & AHC_TWIN) != 0) { - /* - * Twin channel devices cannot handle things like SELTO - * interrupts on the "background" channel. So, if we - * are selecting, keep polling the current channel util - * either a selection or reselection occurs. - */ + test SCSISEQ, ENSELO jnz poll_for_selection; + if ((ahc->features & AHC_TWIN) != 0) { xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ - test SSTAT0, SELDO|SELDI jnz selection; - test SCSISEQ, ENSELO jnz poll_for_work; - xor SBLKCTL,SELBUSB; /* Toggle back */ + test SCSISEQ, ENSELO jnz poll_for_selection; } cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; +poll_for_work_loop: + if ((ahc->features & AHC_TWIN) != 0) { + xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ + } + test SSTAT0, SELDO|SELDI jnz selection; test_queue: /* Has the driver posted any work for us? */ - if ((p->features & AHC_QUEUE_REGS) != 0) { +BEGIN_CRITICAL + if ((ahc->features & AHC_QUEUE_REGS) != 0) { test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; - mov NONE, SNSCB_QOFF; - inc QINPOS; } else { - or SEQCTL, PAUSEDIS; + mov A, QINPOS; cmp KERNEL_QINPOS, A je poll_for_work_loop; - inc QINPOS; - and SEQCTL, ~PAUSEDIS; } + mov ARG_1, NEXT_QUEUED_SCB; -/* - * We have at least one queued SCB now and we don't have any - * SCBs in the list of SCBs awaiting selection. If we have - * any SCBs available for use, pull the tag from the QINFIFO - * and get to work on it. - */ - if ((p->flags & AHC_PAGESCBS) != 0) { + /* + * We have at least one queued SCB now and we don't have any + * SCBs in the list of SCBs awaiting selection. Allocate a + * card SCB for the host's SCB and get to work on it. + */ + if ((ahc->flags & AHC_PAGESCBS) != 0) { mov ALLZEROS call get_free_or_disc_scb; - } - -dequeue_scb: - add A, -1, QINPOS; - mvi QINFIFO_OFFSET call fetch_byte; - - if ((p->flags & AHC_PAGESCBS) == 0) { + } else { /* In the non-paging case, the SCBID == hardware SCB index */ - mov SCBPTR, RETURN_2; + mov SCBPTR, ARG_1; } + or SEQ_FLAGS2, SCB_DMA; +END_CRITICAL dma_queued_scb: -/* - * DMA the SCB from host ram into the current SCB location. - */ + /* + * DMA the SCB from host ram into the current SCB location. + */ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov RETURN_2 call dma_scb; - -/* - * Preset the residual fields in case we never go through a data phase. - * This isn't done by the host so we can avoid a DMA to clear these - * fields for the normal case of I/O that completes without underrun - * or overrun conditions. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, SCB_DATACNT, 3; - } else { - mov SCB_RESID_DCNT[0],SCB_DATACNT[0]; - mov SCB_RESID_DCNT[1],SCB_DATACNT[1]; - mov SCB_RESID_DCNT[2],SCB_DATACNT[2]; - } - mov SCB_RESID_SGCNT, SCB_SGCOUNT; - -start_scb: + mov ARG_1 call dma_scb; /* - * Place us on the waiting list in case our selection - * doesn't win during bus arbitration. + * Check one last time to see if this SCB was canceled + * before we completed the DMA operation. If it was, + * the QINFIFO next pointer will not match our saved + * value. */ + mov A, ARG_1; +BEGIN_CRITICAL + cmp NEXT_QUEUED_SCB, A jne abort_qinscb; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + cmp SCB_TAG, A je . + 2; + mvi SCB_MISMATCH call set_seqint; + } + mov NEXT_QUEUED_SCB, SCB_NEXT; mov SCB_NEXT,WAITING_SCBH; mov WAITING_SCBH, SCBPTR; + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + mov NONE, SNSCB_QOFF; + } else { + inc QINPOS; + } + and SEQ_FLAGS2, ~SCB_DMA; +END_CRITICAL start_waiting: /* - * Pull the first entry off of the waiting SCB list. + * Start the first entry on the waiting SCB list. */ mov SCBPTR, WAITING_SCBH; call start_selection; - jmp poll_for_work; + +poll_for_selection: + /* + * Twin channel devices cannot handle things like SELTO + * interrupts on the "background" channel. So, while + * selecting, keep polling the current channel until + * either a selection or reselection occurs. + */ + test SSTAT0, SELDO|SELDI jz poll_for_selection; + +selection: + /* + * We aren't expecting a bus free, so interrupt + * the kernel driver if it happens. + */ + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; + + /* + * Guard against a bus free after (re)selection + * but prior to enabling the busfree interrupt. SELDI + * and SELDO will be cleared in that case. + */ + test SSTAT0, SELDI|SELDO jz bus_free_sel; + test SSTAT0,SELDO jnz select_out; +select_in: + if ((ahc->flags & AHC_TARGETROLE) != 0) { + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT0, TARGET jz initiator_reselect; + } + mvi CLRSINT0, CLRSELDI; + + /* + * We've just been selected. Assert BSY and + * setup the phase for receiving messages + * from the target. + * + * If bus reset interrupts have been disabled (from a + * previous reset), re-enable them now. Resets are only + * of interest when we have outstanding transactions, so + * we can safely defer re-enabling the interrupt until, + * as a target, we start receiving transactions again. + */ + test SIMODE1, ENSCSIRST jnz . + 3; + mvi CLRSINT1, CLRSCSIRSTI; + or SIMODE1, ENSCSIRST; + mvi SCSISIGO, P_MESGOUT|BSYO; + + /* + * Setup the DMA for sending the identify and + * command information. + */ + or SEQ_FLAGS, CMDPHASE_PENDING; + + mov A, TQINPOS; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi SHARED_DATA_ADDR call set_32byte_addr; + mvi CCSCBCTL, CCSCBRESET; + } else { + mvi DINDEX, HADDR; + mvi SHARED_DATA_ADDR call set_32byte_addr; + mvi DFCNTRL, FIFORESET; + } + + /* Initiator that selected us */ + and SAVED_SCSIID, SELID_MASK, SELID; + /* The Target ID we were selected at */ + if ((ahc->features & AHC_MULTI_TID) != 0) { + and A, OID, TARGIDIN; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + and A, OID, SCSIID_ULTRA2; + } else { + and A, OID, SCSIID; + } + or SAVED_SCSIID, A; + if ((ahc->features & AHC_TWIN) != 0) { + test SBLKCTL, SELBUSB jz . + 2; + or SAVED_SCSIID, TWIN_CHNLB; + } + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, SAVED_SCSIID; + } else { + mov DFDAT, SAVED_SCSIID; + } + + /* + * If ATN isn't asserted, the target isn't interested + * in talking to us. Go directly to bus free. + * XXX SCSI-1 may require us to assume lun 0 if + * ATN is false. + */ + test SCSISIGI, ATNI jz target_busfree; + + /* + * Watch ATN closely now as we pull in messages from the + * initiator. We follow the guidlines from section 6.5 + * of the SCSI-2 spec for what messages are allowed when. + */ + call target_inb; + + /* + * Our first message must be one of IDENTIFY, ABORT, or + * BUS_DEVICE_RESET. + */ + test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; + /* Store for host */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, DINDEX; + } else { + mov DFDAT, DINDEX; + } + + /* Remember for disconnection decision */ + test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; + /* XXX Honor per target settings too */ + or SEQ_FLAGS, NO_DISCONNECT; + + test SCSISIGI, ATNI jz ident_messages_done; + call target_inb; + /* + * If this is a tagged request, the tagged message must + * immediately follow the identify. We test for a valid + * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and + * < MSG_IGN_WIDE_RESIDUE. + */ + add A, -MSG_SIMPLE_Q_TAG, DINDEX; + jnc ident_messages_done; + add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; + jc ident_messages_done; + /* Store for host */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, DINDEX; + } else { + mov DFDAT, DINDEX; + } + + /* + * If the initiator doesn't feel like providing a tag number, + * we've got a failed selection and must transition to bus + * free. + */ + test SCSISIGI, ATNI jz target_busfree; + + /* + * Store the tag for the host. + */ + call target_inb; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, DINDEX; + } else { + mov DFDAT, DINDEX; + } + mov INITIATOR_TAG, DINDEX; + or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; + test SCSISIGI, ATNI jz . + 2; + /* Initiator still wants to give us messages */ + call target_inb; + jmp ident_messages_done; + + /* + * Pushed message loop to allow the kernel to + * run it's own target mode message state engine. + */ +host_target_message_loop: + mvi HOST_MSG_LOOP call set_seqint; + cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; + test SSTAT0, SPIORDY jz .; + jmp host_target_message_loop; + +ident_messages_done: + /* If ring buffer is full, return busy or queue full */ + if ((ahc->features & AHC_HS_MAILBOX) != 0) { + and A, HOST_TQINPOS, HS_MAILBOX; + } else { + mov A, KERNEL_TQINPOS; + } + cmp TQINPOS, A jne tqinfifo_has_space; + mvi P_STATUS|BSYO call change_phase; + test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; + mvi STATUS_QUEUE_FULL call target_outb; + jmp target_busfree_wait; + mvi STATUS_BUSY call target_outb; + jmp target_busfree_wait; +tqinfifo_has_space: + /* Terminate the ident list */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mvi CCSCBRAM, SCB_LIST_NULL; + } else { + mvi DFDAT, SCB_LIST_NULL; + } + or SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN; + test SCSISIGI, ATNI jnz target_mesgout_pending; + jmp target_ITloop; + } + +if ((ahc->flags & AHC_INITIATORROLE) != 0) { +/* + * Reselection has been initiated by a target. Make a note that we've been + * reselected, but haven't seen an IDENTIFY message from the target yet. + */ +initiator_reselect: + /* XXX test for and handle ONE BIT condition */ + or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; + and SAVED_SCSIID, SELID_MASK, SELID; + if ((ahc->features & AHC_ULTRA2) != 0) { + and A, OID, SCSIID_ULTRA2; + } else { + and A, OID, SCSIID; + } + or SAVED_SCSIID, A; + if ((ahc->features & AHC_TWIN) != 0) { + test SBLKCTL, SELBUSB jz . + 2; + or SAVED_SCSIID, TWIN_CHNLB; + } + mvi CLRSINT0, CLRSELDI; + jmp ITloop; +} + +abort_qinscb: + call add_scb_to_free_list; + jmp poll_for_work_loop; start_selection: - if ((p->features & AHC_TWIN) != 0) { + /* + * If bus reset interrupts have been disabled (from a previous + * reset), re-enable them now. Resets are only of interest + * when we have outstanding transactions, so we can safely + * defer re-enabling the interrupt until, as an initiator, + * we start sending out transactions again. + */ + test SIMODE1, ENSCSIRST jnz . + 3; + mvi CLRSINT1, CLRSCSIRSTI; + or SIMODE1, ENSCSIRST; + if ((ahc->features & AHC_TWIN) != 0) { and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ - and A,SELBUSB,SCB_TCL; /* Get new channel bit */ - or SINDEX,A; + test SCB_SCSIID, TWIN_CHNLB jz . + 2; + or SINDEX, SELBUSB; mov SBLKCTL,SINDEX; /* select channel */ } initialize_scsiid: - if ((p->features & AHC_ULTRA2) != 0) { - and A, TID, SCB_TCL; /* Get target ID */ - and SCSIID_ULTRA2, OID; /* Clear old target */ - or SCSIID_ULTRA2, A; - } else { - and A, TID, SCB_TCL; /* Get target ID */ - and SCSIID, OID; /* Clear old target */ - or SCSIID, A; - } - mov SCSIDATL, ALLZEROS; /* clear out the latched */ - /* data register, this */ - /* fixes a bug on some */ - /* controllers where the */ - /* last byte written to */ - /* this register can leak */ - /* onto the data bus at */ - /* bad times, such as during */ - /* selection timeouts */ - mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; + if ((ahc->features & AHC_ULTRA2) != 0) { + mov SCSIID_ULTRA2, SCB_SCSIID; + } else if ((ahc->features & AHC_TWIN) != 0) { + and SCSIID, TWIN_TID|OID, SCB_SCSIID; + } else { + mov SCSIID, SCB_SCSIID; + } + if ((ahc->flags & AHC_TARGETROLE) != 0) { + mov SINDEX, SCSISEQ_TEMPLATE; + test SCB_CONTROL, TARGET_SCB jz . + 2; + or SINDEX, TEMODE; + mov SCSISEQ, SINDEX ret; + } else { + mov SCSISEQ, SCSISEQ_TEMPLATE ret; + } /* - * Initialize Ultra mode setting and clear the SCSI channel. + * Initialize transfer settings and clear the SCSI channel. * SINDEX should contain any additional bit's the client wants - * set in SXFRCTL0. + * set in SXFRCTL0. We also assume that the current SCB is + * a valid SCB for the target we wish to talk to. */ initialize_channel: - or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; - if ((p->features & AHC_ULTRA) != 0) { -ultra: - mvi SINDEX, ULTRA_ENB+1; - test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ - dec SINDEX; -ultra_2: - mov FUNCTION1,SAVED_TCL; - mov A,FUNCTION1; - test SINDIR, A jz ndx_dtr; + or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; +set_transfer_settings: + if ((ahc->features & AHC_ULTRA) != 0) { + test SCB_CONTROL, ULTRAENB jz . + 2; or SXFRCTL0, FAST20; } -/* - * Initialize SCSIRATE with the appropriate value for this target. - * The SCSIRATE settings for each target are stored in an array - * based at TARG_SCSIRATE. - */ -ndx_dtr: - shr A,4,SAVED_TCL; - if ((p->features & AHC_TWIN) != 0) { - test SBLKCTL,SELBUSB jz ndx_dtr_2; - or SAVED_TCL, SELBUSB; - or A,0x08; /* Channel B entries add 8 */ -ndx_dtr_2: - } - - if ((p->features & AHC_ULTRA2) != 0) { - add SINDEX, TARG_OFFSET, A; - mov SCSIOFFSET, SINDIR; + /* + * Initialize SCSIRATE with the appropriate value for this target. + */ + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov SCSIRATE, SCB_SCSIRATE, 2 ret; + } else { + mov SCSIRATE, SCB_SCSIRATE ret; } - add SINDEX,TARG_SCSIRATE,A; - mov SCSIRATE,SINDIR ret; - - -selection: - test SSTAT0,SELDO jnz select_out; +if ((ahc->flags & AHC_TARGETROLE) != 0) { /* - * Reselection has been initiated by a target. Make a note that we've been - * reselected, but haven't seen an IDENTIFY message from the target yet. + * We carefully toggle SPIOEN to allow us to return the + * message byte we receive so it can be checked prior to + * driving REQ on the bus for the next byte. */ -initiator_reselect: - mvi CLRSINT0, CLRSELDI; - /* XXX test for and handle ONE BIT condition */ - and SAVED_TCL, SELID_MASK, SELID; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; /* - * We aren't expecting a - * bus free, so interrupt - * the kernel driver if it - * happens. - */ - mvi SPIOEN call initialize_channel; - mvi MSG_OUT, MSG_NOOP; /* No message to send */ - jmp ITloop; +target_inb: + /* + * Drive REQ on the bus by enabling SCSI PIO. + */ + or SXFRCTL0, SPIOEN; + /* Wait for the byte */ + test SSTAT0, SPIORDY jz .; + /* Prevent our read from triggering another REQ */ + and SXFRCTL0, ~SPIOEN; + /* Save latched contents */ + mov DINDEX, SCSIDATL ret; +} /* * After the selection, remove this SCB from the "waiting SCB" @@ -259,33 +443,198 @@ */ select_out: /* Turn off the selection hardware */ - mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* - * ATN on parity errors - * for "in" phases - */ + and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; mvi CLRSINT0, CLRSELDO; mov SCBPTR, WAITING_SCBH; mov WAITING_SCBH,SCB_NEXT; - mov SAVED_TCL, SCB_TCL; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; /* - * We aren't expecting a - * bus free, so interrupt - * the kernel driver if it - * happens. - */ - mvi SPIOEN call initialize_channel; -/* - * As soon as we get a successful selection, the target should go - * into the message out phase since we have ATN asserted. - */ + mov SAVED_SCSIID, SCB_SCSIID; + mov SAVED_LUN, SCB_LUN; + call initialize_channel; + if ((ahc->flags & AHC_TARGETROLE) != 0) { + test SSTAT0, TARGET jz initiator_select; + + /* + * We've just re-selected an initiator. + * Assert BSY and setup the phase for + * sending our identify messages. + */ + mvi P_MESGIN|BSYO call change_phase; + + /* + * Start out with a simple identify message. + */ + or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; + + /* + * If we are the result of a tagged command, send + * a simple Q tag and the tag id. + */ + test SCB_CONTROL, TAG_ENB jz . + 3; + mvi MSG_SIMPLE_Q_TAG call target_outb; + mov SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb; +target_synccmd: + /* + * Now determine what phases the host wants us + * to go through. + */ + mov SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES]; + +target_ITloop: + /* + * Start honoring ATN signals now that + * we properly identified ourselves. + */ + test SCSISIGI, ATNI jnz target_mesgout; + test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; + test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; + test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; + + /* + * No more work to do. Either disconnect or not depending + * on the state of NO_DISCONNECT. + */ + test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } + mov RETURN_1, ALLZEROS; + call complete_target_cmd; + cmp RETURN_1, CONT_MSG_LOOP jne .; + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + mov SCB_TAG call dma_scb; + jmp target_synccmd; + +target_mesgout: + mvi SCSISIGO, P_MESGOUT|BSYO; +target_mesgout_continue: + call target_inb; +target_mesgout_pending: + /* Local Processing goes here... */ + jmp host_target_message_loop; + +target_disconnect: + mvi P_MESGIN|BSYO call change_phase; + test SEQ_FLAGS, DPHASE jz . + 2; + mvi MSG_SAVEDATAPOINTER call target_outb; + mvi MSG_DISCONNECT call target_outb; + +target_busfree_wait: + /* Wait for preceeding I/O session to complete. */ + test SCSISIGI, ACKI jnz .; +target_busfree: + and SIMODE1, ~ENBUSFREE; + if ((ahc->features & AHC_ULTRA2) != 0) { + clr SCSIBUSL; + } + clr SCSISIGO; + mvi LASTPHASE, P_BUSFREE; + call complete_target_cmd; + jmp poll_for_work; + +target_cmdphase: + mvi P_COMMAND|BSYO call change_phase; + call target_inb; + mov A, DINDEX; + /* Store for host */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, A; + } else { + mov DFDAT, A; + } + + /* + * Determine the number of bytes to read + * based on the command group code via table lookup. + * We reuse the first 8 bytes of the TARG_SCSIRATE + * BIOS array for this table. Count is one less than + * the total for the command since we've already fetched + * the first byte. + */ + shr A, CMD_GROUP_CODE_SHIFT; + add SINDEX, CMDSIZE_TABLE, A; + mov A, SINDIR; + + test A, 0xFF jz command_phase_done; + or SXFRCTL0, SPIOEN; +command_loop: + test SSTAT0, SPIORDY jz .; + cmp A, 1 jne . + 2; + and SXFRCTL0, ~SPIOEN; /* Last Byte */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + mov CCSCBRAM, SCSIDATL; + } else { + mov DFDAT, SCSIDATL; + } + dec A; + test A, 0xFF jnz command_loop; + +command_phase_done: + and SEQ_FLAGS, ~CMDPHASE_PENDING; + jmp target_ITloop; + +target_dphase: + /* + * Data phases on the bus are from the + * perspective of the initiator. The dma + * code looks at LASTPHASE to determine the + * data direction of the DMA. Toggle it for + * target transfers. + */ + xor LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR]; + or SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO + call change_phase; + jmp p_data; + +target_sphase: + mvi P_STATUS|BSYO call change_phase; + mvi LASTPHASE, P_STATUS; + mov SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb; + /* XXX Watch for ATN or parity errors??? */ + mvi SCSISIGO, P_MESGIN|BSYO; + /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ + mov ALLZEROS call target_outb; + jmp target_busfree_wait; + +complete_target_cmd: + test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; + mov SCB_TAG jmp complete_post; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Set the valid byte */ + mvi CCSCBADDR, 24; + mov CCSCBRAM, ALLONES; + mvi CCHCNT, 28; + or CCSCBCTL, CCSCBEN|CCSCBRESET; + test CCSCBCTL, CCSCBDONE jz .; + clr CCSCBCTL; + } else { + /* Set the valid byte */ + or DFCNTRL, FIFORESET; + mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ + mov DFDAT, ALLONES; + mvi 28 call set_hcnt; + or DFCNTRL, HDMAEN|FIFOFLUSH; + call dma_finish; + } + inc TQINPOS; + mvi INTSTAT,CMDCMPLT ret; + } + +if ((ahc->flags & AHC_INITIATORROLE) != 0) { +initiator_select: + /* + * As soon as we get a successful selection, the target + * should go into the message out phase since we have ATN + * asserted. + */ mvi MSG_OUT, MSG_IDENTIFYFLAG; or SEQ_FLAGS, IDENTIFY_SEEN; -/* - * Main loop for information transfer phases. Wait for the target - * to assert REQ before checking MSG, C/D and I/O for the bus phase. - */ + /* + * Main loop for information transfer phases. Wait for the + * target to assert REQ before checking MSG, C/D and I/O for + * the bus phase. + */ +mesgin_phasemis: ITloop: call phase_lock; @@ -297,17 +646,20 @@ cmp A,P_STATUS je p_status; cmp A,P_MESGIN je p_mesgin; - mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ + mvi BAD_PHASE call set_seqint; jmp ITloop; /* Try reading the bus again. */ await_busfree: and SIMODE1, ~ENBUSFREE; - call clear_target_state; mov NONE, SCSIDATL; /* Ack the last byte */ + if ((ahc->features & AHC_ULTRA2) != 0) { + clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ + } and SXFRCTL0, ~SPIOEN; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz poll_for_work; - mvi INTSTAT, BAD_PHASE; + mvi MISSED_BUSFREE call set_seqint; +} clear_target_state: /* @@ -316,42 +668,160 @@ * clear DFCNTRL too. */ clr DFCNTRL; + or SXFRCTL0, CLRSTCNT|CLRCHN; /* * We don't know the target we will connect to, * so default to narrow transfers to avoid * parity problems. */ - if ((p->features & AHC_ULTRA2) != 0) { - bmov SCSIRATE, ALLZEROS, 2; + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov SCSIRATE, ALLZEROS, 2; } else { - clr SCSIRATE; - and SXFRCTL0, ~(FAST20); + clr SCSIRATE; + if ((ahc->features & AHC_ULTRA) != 0) { + and SXFRCTL0, ~(FAST20); + } } mvi LASTPHASE, P_BUSFREE; /* clear target specific flags */ clr SEQ_FLAGS ret; +sg_advance: + clr A; /* add sizeof(struct scatter) */ + add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; + adc SCB_RESIDUAL_SGPTR[1],A; + adc SCB_RESIDUAL_SGPTR[2],A; + adc SCB_RESIDUAL_SGPTR[3],A ret; + +if ((ahc->features & AHC_CMD_CHAN) != 0) { +disable_ccsgen: + test CCSGCTL, CCSGEN jz return; + test CCSGCTL, CCSGDONE jz .; +disable_ccsgen_fetch_done: + clr CCSGCTL; + test CCSGCTL, CCSGEN jnz .; + ret; +idle_loop: + /* Did we just finish fetching segs? */ + cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; + + /* Are we actively fetching segments? */ + test CCSGCTL, CCSGEN jnz return; + + /* + * Do we need any more segments? + */ + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; + + /* + * Do we have any prefetch left??? + */ + cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; + + /* + * Need to fetch segments, but we can only do that + * if the command channel is completely idle. Make + * sure we don't have an SCB prefetch going on. + */ + test CCSCBCTL, CCSCBEN jnz return; + + /* + * We fetch a "cacheline aligned" and sized amount of data + * so we don't end up referencing a non-existant page. + * Cacheline aligned is in quotes because the kernel will + * set the prefetch amount to a reasonable level if the + * cacheline size is unknown. + */ + mvi CCHCNT, SG_PREFETCH_CNT; + and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; + bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; + mvi CCSGCTL, CCSGEN|CCSGRESET ret; +idle_sgfetch_complete: + call disable_ccsgen_fetch_done; + and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; +idle_sg_avail: + if ((ahc->features & AHC_ULTRA2) != 0) { + /* Does the hardware have space for another SG entry? */ + test DFSTATUS, PRELOAD_AVAIL jz return; + bmov HADDR, CCSGRAM, 4; + bmov SINDEX, CCSGRAM, 1; + test SINDEX, 0x1 jz . + 2; + xor DATA_COUNT_ODD, 0x1; + bmov HCNT[0], SINDEX, 1; + bmov HCNT[1], CCSGRAM, 2; + bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; + call sg_advance; + mov SINDEX, SCB_RESIDUAL_SGPTR[0]; + test DATA_COUNT_ODD, 0x1 jz . + 2; + or SINDEX, ODD_SEG; + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; + or SINDEX, LAST_SEG; + mov SG_CACHE_PRE, SINDEX; + /* Load the segment by writing DFCNTRL again */ + mov DFCNTRL, DMAPARAMS; + } + ret; +} + +if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { +/* + * Calculate the trailing portion of this S/G segment that cannot + * be transferred using memory write and invalidate PCI transactions. + * XXX Can we optimize this for PCI writes only??? + */ +calc_mwi_residual: + /* + * If the ending address is on a cacheline boundary, + * there is no need for an extra segment. + */ + mov A, HCNT[0]; + add A, A, HADDR[0]; + and A, CACHESIZE_MASK; + test A, 0xFF jz return; + + /* + * If the transfer is less than a cachline, + * there is no need for an extra segment. + */ + test HCNT[1], 0xFF jnz calc_mwi_residual_final; + test HCNT[2], 0xFF jnz calc_mwi_residual_final; + add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; + jnc return; + +calc_mwi_residual_final: + mov MWI_RESIDUAL, A; + not A; + inc A; + add HCNT[0], A; + adc HCNT[1], -1; + adc HCNT[2], -1 ret; +} + /* * If we re-enter the data phase after going through another phase, the * STCNT may have been cleared, so restore it from the residual field. */ data_phase_reinit: - if ((p->features & AHC_ULTRA2) != 0) { + if ((ahc->features & AHC_ULTRA2) != 0) { + /* + * The preload circuitry requires us to + * reload the address too, so pull it from + * the shaddow address. + */ bmov HADDR, SHADDR, 4; - bmov HCNT, SCB_RESID_DCNT, 3; - } - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - bmov STCNT, SCB_RESID_DCNT, 3; - } - if ((p->features & AHC_CMD_CHAN) == 0) { + bmov HCNT, SCB_RESIDUAL_DATACNT, 3; + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT, SCB_RESIDUAL_DATACNT, 3; + } else { mvi DINDEX, STCNT; - mvi SCB_RESID_DCNT call bcopy_3; + mvi SCB_RESIDUAL_DATACNT call bcopy_3; } + and DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0]; jmp data_phase_loop; p_data: - if ((p->features & AHC_ULTRA2) != 0) { + if ((ahc->features & AHC_ULTRA2) != 0) { mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; } else { mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; @@ -362,8 +832,9 @@ * Ensure entering a data * phase is okay - seen identify, etc. */ - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi CCSGADDR, CCSGADDR_MAX; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* We don't have any valid S/G elements */ + mvi CCSGADDR, SG_PREFETCH_CNT; } test SEQ_FLAGS, DPHASE jnz data_phase_reinit; @@ -372,256 +843,471 @@ /* * Initialize the DMA address and counter from the SCB. - * Also set SG_COUNT and SG_NEXT in memory since we cannot - * modify the values in the SCB itself until we see a - * save data pointers message. + * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG + * flag in the highest byte of the data count. We cannot + * modify the saved values in the SCB until we see a save + * data pointers message. */ - if ((p->features & AHC_CMD_CHAN) != 0) { + if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov HADDR, SCB_DATAPTR, 7; - bmov STCNT, HCNT, 3; - bmov SG_COUNT, SCB_SGCOUNT, 5; + bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; } else { mvi DINDEX, HADDR; mvi SCB_DATAPTR call bcopy_7; - call set_stcnt_from_hcnt; - mvi DINDEX, SG_COUNT; - mvi SCB_SGCOUNT call bcopy_5; + mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; + mvi SCB_DATACNT + 3 call bcopy_5; + } + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { + call calc_mwi_residual; + } + and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; + and DATA_COUNT_ODD, 0x1, HCNT[0]; + + if ((ahc->features & AHC_ULTRA2) == 0) { + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT, HCNT, 3; + } else { + call set_stcnt_from_hcnt; + } } data_phase_loop: -/* Guard against overruns */ - test SG_COUNT, 0xff jnz data_phase_inbounds; -/* - * Turn on 'Bit Bucket' mode, set the transfer count to - * 16meg and let the target run until it changes phase. - * When the transfer completes, notify the host that we - * had an overrun. - */ + /* Guard against overruns */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; + + /* + * Turn on `Bit Bucket' mode, wait until the target takes + * us to another phase, and then notify the host. + */ + and DMAPARAMS, DIRECTION; + mov DFCNTRL, DMAPARAMS; or SXFRCTL1,BITBUCKET; - and DMAPARAMS, ~(HDMAEN|SDMAEN); - if ((p->features & AHC_CMD_CHAN) != 0) { - if ((p->features & AHC_ULTRA2) != 0) { - bmov HCNT, ALLONES, 3; - } - bmov STCNT, ALLONES, 3; - } else { - mvi STCNT[0], 0xFF; - mvi STCNT[1], 0xFF; - mvi STCNT[2], 0xFF; - } + test SSTAT1,PHASEMIS jz .; + and SXFRCTL1, ~BITBUCKET; + mvi DATA_OVERRUN call set_seqint; + jmp ITloop; + data_phase_inbounds: -/* If we are the last SG block, tell the hardware. */ - cmp SG_COUNT,0x01 jne data_phase_wideodd; - if ((p->features & AHC_ULTRA2) == 0) { - and DMAPARAMS, ~WIDEODD; - } else { - mvi SG_CACHEPTR, LAST_SEG; - } -data_phase_wideodd: - if ((p->features & AHC_ULTRA2) != 0) { - mov SINDEX, ALLONES; + if ((ahc->features & AHC_ULTRA2) != 0) { + mov SINDEX, SCB_RESIDUAL_SGPTR[0]; + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; + or SINDEX, LAST_SEG; + test DATA_COUNT_ODD, 0x1 jz . + 2; + or SINDEX, ODD_SEG; + mov SG_CACHE_PRE, SINDEX; mov DFCNTRL, DMAPARAMS; - test SSTAT0, SDONE jnz .; -data_phase_dma_loop: - test SSTAT0, SDONE jnz data_phase_dma_done; - test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ -data_phase_dma_phasemis: - test SSTAT0,SDONE jnz data_phase_dma_done; - clr SINDEX; /* Remember the phasemiss */ - } else { - mov DMAPARAMS call dma; - } +ultra2_dma_loop: + call idle_loop; + /* + * The transfer is complete if either the last segment + * completes or the target changes phase. + */ + test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; + if ((ahc->flags & AHC_TARGETROLE) != 0) { + /* + * As a target, we control the phases, + * so ignore PHASEMIS. + */ + test SSTAT0, TARGET jnz ultra2_dma_loop; + } + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT1,PHASEMIS jz ultra2_dma_loop; + } -data_phase_dma_done: -/* Go tell the host about any overruns */ - test SXFRCTL1,BITBUCKET jnz data_phase_overrun; +ultra2_dmafinish: + test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; + if ((ahc->features & AHC_DT) == 0) { + and DFCNTRL, ~SCSIEN; + test DFCNTRL, SCSIEN jnz .; + } +ultra2_dmafifoflush: + if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { + /* + * On Rev A of the aic7890, the autoflush + * features doesn't function correctly. + * Perform an explicit manual flush. During + * a manual flush, the FIFOEMP bit becomes + * true every time the PCI FIFO empties + * regardless of the state of the SCSI FIFO. + * It can take up to 4 clock cycles for the + * SCSI FIFO to get data into the PCI FIFO + * and for FIFOEMP to de-assert. Here we + * guard against this condition by making + * sure the FIFOEMP bit stays on for 5 full + * clock cycles. + */ + or DFCNTRL, FIFOFLUSH; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + } + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; +ultra2_dmafifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; +ultra2_dmahalt: + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, HDMAEN jnz .; -/* Exit if we had an underrun. dma clears SINDEX in this case. */ - test SINDEX,0xff jz data_phase_finish; + /* + * If, by chance, we stopped before being able + * to fetch additional segments for this transfer, + * yet the last S/G was completely exhausted, + * call our idle loop until it is able to load + * another segment. This will allow us to immediately + * pickup on the next segment on the next data phase. + * + * If we happened to stop on the last segment, then + * our residual information is still correct from + * the idle loop and there is no need to perform + * any fixups. Just jump to data_phase_finish. + */ +ultra2_ensure_sg: + test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; + /* Record if we've consumed all S/G entries */ + test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; + or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; + jmp data_phase_finish; + +ultra2_shvalid: + test SSTAT2, SHVALID jnz sgptr_fixup; + call idle_loop; + jmp ultra2_ensure_sg; -/* - * Advance the scatter-gather pointers if needed - */ -sg_advance: - dec SG_COUNT; /* one less segment to go */ +sgptr_fixup: + /* + * Fixup the residual next S/G pointer. The S/G preload + * feature of the chip allows us to load two elements + * in addition to the currently active element. We + * store the bottom byte of the next S/G pointer in + * the SG_CACEPTR register so we can restore the + * correct value when the DMA completes. If the next + * sg ptr value has advanced to the point where higher + * bytes in the address have been affected, fix them + * too. + */ + test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; + test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; + add SCB_RESIDUAL_SGPTR[1], -1; + adc SCB_RESIDUAL_SGPTR[2], -1; + adc SCB_RESIDUAL_SGPTR[3], -1; +sgptr_fixup_done: + and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; + clr DATA_COUNT_ODD; + test SG_CACHE_SHADOW, ODD_SEG jz . + 2; + or DATA_COUNT_ODD, 0x1; + clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ + } else { + /* If we are the last SG block, tell the hardware. */ + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 + && ahc->pci_cachesize != 0) { + test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; + } + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; + if ((ahc->flags & AHC_TARGETROLE) != 0) { + test SSTAT0, TARGET jz dma_last_sg; + if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { + test DMAPARAMS, DIRECTION jz dma_mid_sg; + } + } +dma_last_sg: + and DMAPARAMS, ~WIDEODD; +dma_mid_sg: + /* Start DMA data transfer. */ + mov DFCNTRL, DMAPARAMS; +dma_loop: + if ((ahc->features & AHC_CMD_CHAN) != 0) { + call idle_loop; + } + test SSTAT0,DMADONE jnz dma_dmadone; + test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ +dma_phasemis: + /* + * We will be "done" DMAing when the transfer count goes to + * zero, or the target changes the phase (in light of this, + * it makes sense that the DMA circuitry doesn't ACK when + * PHASEMIS is active). If we are doing a SCSI->Host transfer, + * the data FIFO should be flushed auto-magically on STCNT=0 + * or a phase change, so just wait for FIFO empty status. + */ +dma_checkfifo: + test DFCNTRL,DIRECTION jnz dma_fifoempty; +dma_fifoflush: + test DFSTATUS,FIFOEMP jz dma_fifoflush; +dma_fifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz dma_fifoempty; - test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ -/* - * Load a struct scatter and set up the data address and length. - * If the working value of the SG count is nonzero, then - * we need to load a new set of values. - * - * This, like all DMA's, assumes little-endian host data storage. - */ -sg_load: - if ((p->features & AHC_CMD_CHAN) != 0) { /* - * Do we have any prefetch left??? + * Now shut off the DMA and make sure that the DMA + * hardware has actually stopped. Touching the DMA + * counters, etc. while a DMA is active will result + * in an ILLSADDR exception. + */ +dma_dmadone: + and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); +dma_halt: + /* + * Some revisions of the aic78XX have a problem where, if the + * data fifo is full, but the PCI input latch is not empty, + * HDMAEN cannot be cleared. The fix used here is to drain + * the prefetched but unused data from the data fifo until + * there is space for the input latch to drain. */ - cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; + if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { + mov NONE, DFDAT; + } + test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; + + /* See if we have completed this last segment */ + test STCNT[0], 0xff jnz data_phase_finish; + test STCNT[1], 0xff jnz data_phase_finish; + test STCNT[2], 0xff jnz data_phase_finish; /* - * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. + * Advance the scatter-gather pointers if needed */ - add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; - mvi A, CCSGADDR_MAX; - jc . + 2; - shl A, 3, SG_COUNT; - mov CCHCNT, A; - bmov CCHADDR, SG_NEXT, 4; - mvi CCSGCTL, CCSGEN|CCSGRESET; - test CCSGCTL, CCSGDONE jz .; - and CCSGCTL, ~CCSGEN; - test CCSGCTL, CCSGEN jnz .; - mvi CCSGCTL, CCSGRESET; -prefetched_segs_avail: - bmov HADDR, CCSGRAM, 8; - if ((p->features & AHC_ULTRA2) == 0) { - bmov STCNT, HCNT, 3; + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 + && ahc->pci_cachesize != 0) { + test MWI_RESIDUAL, 0xFF jz no_mwi_resid; + /* + * Reload HADDR from SHADDR and setup the + * count to be the size of our residual. + */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov HADDR, SHADDR, 4; + mov HCNT, MWI_RESIDUAL; + bmov HCNT[1], ALLZEROS, 2; + } else { + mvi DINDEX, HADDR; + mvi SHADDR call bcopy_4; + mov MWI_RESIDUAL call set_hcnt; + } + clr MWI_RESIDUAL; + jmp sg_load_done; +no_mwi_resid: } - } else { - mvi DINDEX, HADDR; - mvi SG_NEXT call bcopy_4; + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; + or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; + jmp data_phase_finish; +sg_load: + /* + * Load the next SG element's data address and length + * into the DMA engine. If we don't have hardware + * to perform a prefetch, we'll have to fetch the + * segment from host memory first. + */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Wait for the idle loop to complete */ + test CCSGCTL, CCSGEN jz . + 3; + call idle_loop; + test CCSGCTL, CCSGEN jnz . - 1; + bmov HADDR, CCSGRAM, 7; + test CCSGRAM, SG_LAST_SEG jz . + 2; + or SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG; + } else { + mvi DINDEX, HADDR; + mvi SCB_RESIDUAL_SGPTR call bcopy_4; - mvi HCNT[0],SG_SIZEOF; - clr HCNT[1]; - clr HCNT[2]; + mvi SG_SIZEOF call set_hcnt; - or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; + or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - call dma_finish; + call dma_finish; - /* - * Copy data from FIFO into SCB data pointer and data count. - * This assumes that the SG segments are of the form: - * struct ahc_dma_seg { - * u_int32_t addr; four bytes, little-endian order - * u_int32_t len; four bytes, little endian order - * }; - */ - mvi HADDR call dfdat_in_7; - call set_stcnt_from_hcnt; - } + mvi DINDEX, HADDR; + call dfdat_in_7; + mov SCB_RESIDUAL_DATACNT[3], DFDAT; + } -/* Advance the SG pointer */ - clr A; /* add sizeof(struct scatter) */ - add SG_NEXT[0],SG_SIZEOF; - adc SG_NEXT[1],A; + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 + && ahc->pci_cachesize != 0) { + call calc_mwi_residual; + } - test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; + /* Point to the new next sg in memory */ + call sg_advance; -/* This drops the last SG segment down to the shadow layer for us */ - if ((p->features & AHC_ULTRA2) != 0) { - mov DFCNTRL, DMAPARAMS; - test SSTAT0, SDONE jnz .; - } +sg_load_done: + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT, HCNT, 3; + } else { + call set_stcnt_from_hcnt; + } + /* Track odd'ness */ + test HCNT[0], 0x1 jz . + 2; + xor DATA_COUNT_ODD, 0x1; + if ((ahc->flags & AHC_TARGETROLE) != 0) { + test SSTAT0, TARGET jnz data_phase_loop; + } + } data_phase_finish: -/* - * After a DMA finishes, save the SG and STCNT residuals back into the SCB - * We use STCNT instead of HCNT, since it's a reflection of how many bytes - * were transferred on the SCSI (as opposed to the host) bus. - */ - if ((p->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; - } - if ((p->features & AHC_ULTRA2) == 0) { - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - } else { - mov SCB_RESID_DCNT[0],STCNT[0]; - mov SCB_RESID_DCNT[1],STCNT[1]; - mov SCB_RESID_DCNT[2],STCNT[2]; - mov SCB_RESID_SGCNT, SG_COUNT; + /* + * If the target has left us in data phase, loop through + * the dma code again. In the case of ULTRA2 adapters, + * we should only loop if there is a data overrun. For + * all other adapters, we'll loop after each S/G element + * is loaded as well as if there is an overrun. + */ + if ((ahc->flags & AHC_TARGETROLE) != 0) { + test SSTAT0, TARGET jnz data_phase_done; + } + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT1, REQINIT jz .; + test SSTAT1,PHASEMIS jz data_phase_loop; + } + +data_phase_done: + /* + * After a DMA finishes, save the SG and STCNT residuals back into + * the SCB. We use STCNT instead of HCNT, since it's a reflection + * of how many bytes were transferred on the SCSI (as opposed to the + * host) bus. + */ + if ((ahc->features & AHC_CMD_CHAN) != 0) { + /* Kill off any pending prefetch */ + call disable_ccsgen; + } + + if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 + && ahc->pci_cachesize != 0) { + if ((ahc->features & AHC_CMD_CHAN) != 0) { + test MWI_RESIDUAL, 0xFF jz bmov_resid; + } + mov A, MWI_RESIDUAL; + add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; + clr A; + adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; + adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; + clr MWI_RESIDUAL; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + jmp . + 2; +bmov_resid: + bmov SCB_RESIDUAL_DATACNT, STCNT, 3; } + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESIDUAL_DATACNT, STCNT, 3; + } else { + mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; + mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; + mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; } - jmp ITloop; + /* + * Since we've been through a data phase, the SCB_RESID* fields + * are now initialized. Clear the full residual flag. + */ + and SCB_SGPTR[0], ~SG_FULL_RESID; -data_phase_overrun: - if ((p->features & AHC_ULTRA2) != 0) { - call ultra2_dmafinish; + if ((ahc->features & AHC_ULTRA2) != 0) { + /* Clear the channel in case we return to data phase later */ + or SXFRCTL0, CLRSTCNT|CLRCHN; + or SXFRCTL0, CLRSTCNT|CLRCHN; } -/* - * Turn off BITBUCKET mode and notify the host - */ - and SXFRCTL1, ~BITBUCKET; - mvi INTSTAT,DATA_OVERRUN; - jmp ITloop; -ultra2_dmafinish: - if ((p->features & AHC_ULTRA2) != 0) { - test DFCNTRL, DIRECTION jnz ultra2_dmahalt; - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; -ultra2_dmafifoflush: - or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz . - 1; + if ((ahc->flags & AHC_TARGETROLE) != 0) { + test SEQ_FLAGS, DPHASE_PENDING jz ITloop; + and SEQ_FLAGS, ~DPHASE_PENDING; /* - * hardware bug alert! This needless set of jumps is to - * protect against a FIFOEMP status bit glitch in the - * silicon. + * For data-in phases, wait for any pending acks from the + * initiator before changing phase. */ - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, MREQPEND jnz .; -ultra2_dmahalt: - test SCSIOFFSET, 0x7f jnz ultra2_shutdown; -ultra2_await_nreq: - test SCSISIGI, REQI jz ultra2_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz ultra2_await_nreq; -ultra2_shutdown: - and DFCNTRL, ~(HDMAEN|SCSIEN); - test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - or SXFRCTL0, CLRSTCNT|CLRCHN; - ret; + test DFCNTRL, DIRECTION jz target_ITloop; + test SSTAT1, REQINIT jnz .; + jmp target_ITloop; + } else { + jmp ITloop; } +if ((ahc->flags & AHC_INITIATORROLE) != 0) { /* * Command phase. Set up the DMA registers and let 'er rip. */ p_command: call assert; -/* - * Load HADDR and HCNT. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov HADDR, SCB_CMDPTR, 5; + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov HCNT[0], SCB_CDB_LEN, 1; bmov HCNT[1], ALLZEROS, 2; - if ((p->features & AHC_ULTRA2) == 0) { - bmov STCNT, HCNT, 3; - } + mvi SG_CACHE_PRE, LAST_SEG; + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov STCNT[0], SCB_CDB_LEN, 1; + bmov STCNT[1], ALLZEROS, 2; } else { - mvi DINDEX, HADDR; - mvi SCB_CMDPTR call bcopy_5; - clr HCNT[1]; - clr HCNT[2]; - call set_stcnt_from_hcnt; + mov STCNT[0], SCB_CDB_LEN; + clr STCNT[1]; + clr STCNT[2]; + } + add NONE, -13, SCB_CDB_LEN; + mvi SCB_CDB_STORE jnc p_command_embedded; +p_command_from_host: + if ((ahc->features & AHC_ULTRA2) != 0) { + bmov HADDR[0], SCB_CDB_PTR, 4; + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); + } else { + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov HADDR[0], SCB_CDB_PTR, 4; + bmov HCNT, STCNT, 3; + } else { + mvi DINDEX, HADDR; + mvi SCB_CDB_PTR call bcopy_4; + mov SCB_CDB_LEN call set_hcnt; + } + mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); } - - if ((p->features & AHC_ULTRA2) == 0) { - mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; + jmp p_command_loop; +p_command_embedded: + /* + * The data fifo seems to require 4 byte alligned + * transfers from the sequencer. Force this to + * be the case by clearing HADDR[0] even though + * we aren't going to touch host memeory. + */ + clr HADDR[0]; + if ((ahc->features & AHC_ULTRA2) != 0) { + mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); + bmov DFDAT, SCB_CDB_STORE, 12; + } else if ((ahc->features & AHC_CMD_CHAN) != 0) { + if ((ahc->flags & AHC_SCB_BTT) != 0) { + /* + * On the 7895 the data FIFO will + * get corrupted if you try to dump + * data from external SCB memory into + * the FIFO while it is enabled. So, + * fill the fifo and then enable SCSI + * transfers. + */ + mvi DFCNTRL, (DIRECTION|FIFORESET); + } else { + mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); + } + bmov DFDAT, SCB_CDB_STORE, 12; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); + } else { + or DFCNTRL, FIFOFLUSH; + } } else { - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); - test SSTAT0, SDONE jnz .; -p_command_dma_loop: - test SSTAT0, SDONE jnz p_command_ultra2_dma_done; - test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */ -p_command_ultra2_dma_done: - test SCSISIGI, REQI jz p_command_ultra2_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz p_command_ultra2_dma_done; -p_command_ultra2_shutdown: - and DFCNTRL, ~(HDMAEN|SCSIEN); - test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - or SXFRCTL0, CLRSTCNT|CLRCHN; + mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); + call copy_to_fifo_6; + call copy_to_fifo_6; + or DFCNTRL, FIFOFLUSH; + } +p_command_loop: + test SSTAT0, SDONE jnz . + 2; + test SSTAT1, PHASEMIS jz p_command_loop; + /* + * Wait for our ACK to go-away on it's own + * instead of being killed by SCSIEN getting cleared. + */ + test SCSISIGI, ACKI jnz .; + and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); + test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; + if ((ahc->features & AHC_ULTRA2) != 0) { + /* Drop any residual from the S/G Preload queue */ + or SXFRCTL0, CLRSTCNT; } jmp ITloop; @@ -632,21 +1318,26 @@ p_status: call assert; - mov SCB_TARGET_STATUS, SCSIDATL; + mov SCB_SCSI_STATUS, SCSIDATL; jmp ITloop; /* - * Message out phase. If MSG_OUT is 0x80, build I full indentify message - * sequence and send it to the target. In addition, if the MK_MESSAGE bit - * is set in the SCB_CONTROL byte, interrupt the host and allow it to send - * it's own message. + * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full + * indentify message sequence and send it to the target. The host may + * override this behavior by setting the MK_MESSAGE bit in the SCB + * control byte. This will cause us to interrupt the host and allow + * it to handle the message phase completely on its own. If the bit + * associated with this target is set, we will also interrupt the host, + * thereby allowing it to send a message on the next selection regardless + * of the transaction being sent. * * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. - * This is done to allow the hsot to send messages outside of an identify + * This is done to allow the host to send messages outside of an identify * sequence while protecting the seqencer from testing the MK_MESSAGE bit * on an SCB that might not be for the current nexus. (For example, a * BDR message in responce to a bad reselection would leave us pointed to * an SCB that doesn't have anything to do with the current target). + * * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, * bus device reset). * @@ -655,23 +1346,27 @@ * reason. */ p_mesgout_retry: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ + or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ p_mesgout: mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; -p_mesgout_identify: - if ((p->features & AHC_WIDE) != 0) { - and SINDEX,0xf,SCB_TCL; /* lun */ - } else { - and SINDEX,0x7,SCB_TCL; /* lun */ + test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; + mov FUNCTION1, SCB_SCSIID; + mov A, FUNCTION1; + mov SINDEX, TARGET_MSG_REQUEST[0]; + if ((ahc->features & AHC_TWIN) != 0) { + /* Second Channel uses high byte bits */ + test SCB_SCSIID, TWIN_CHNLB jz . + 2; + mov SINDEX, TARGET_MSG_REQUEST[1]; + } else if ((ahc->features & AHC_WIDE) != 0) { + test SCB_SCSIID, 0x80 jz . + 2; /* target > 7 */ + mov SINDEX, TARGET_MSG_REQUEST[1]; } - and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ - or SINDEX,A; /* or in disconnect privledge */ - or SINDEX,MSG_IDENTIFYFLAG; -p_mesgout_mk_message: - test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag; - mov SCSIDATL, SINDEX; /* Send the last byte */ - jmp p_mesgout_from_host + 1;/* Skip HOST_MSG test */ + test SINDEX, A jnz host_message_loop; +p_mesgout_identify: + or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; + test SCB_CONTROL, DISCENB jnz . + 2; + and SINDEX, ~DISCENB; /* * Send a tag message if TAG_ENB is set in the SCB control block. * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. @@ -686,34 +1381,27 @@ cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; mov SCB_TAG jmp p_mesgout_onebyte; /* - * Interrupt the driver, and allow it to send a message - * if it asks. + * Interrupt the driver, and allow it to handle this message + * phase and any required retries. */ p_mesgout_from_host: cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; - mvi INTSTAT,AWAITING_MSG; - nop; - /* - * Did the host detect a phase change? - */ - cmp RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done; + jmp host_message_loop; p_mesgout_onebyte: mvi CLRSINT1, CLRATNO; mov SCSIDATL, SINDEX; /* - * If the next bus phase after ATN drops is a message out, it means + * If the next bus phase after ATN drops is message out, it means * that the target is requesting that the last message(s) be resent. */ call phase_lock; - cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; + cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; p_mesgout_done: mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ mov LAST_MSG, MSG_OUT; - cmp MSG_OUT, MSG_IDENTIFYFLAG jne . + 2; - and SCB_CONTROL, ~MK_MESSAGE; mvi MSG_OUT, MSG_NOOP; /* No message left */ jmp ITloop; @@ -728,113 +1416,137 @@ cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; cmp ALLZEROS,A je mesgin_complete; cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; - cmp A,MSG_EXTENDED je mesgin_extended; - cmp A,MSG_MESSAGE_REJECT je mesgin_reject; + cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; cmp A,MSG_NOOP je mesgin_done; - cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_wide_residue; -rej_mesgin: /* - * We have no idea what this message in is, so we issue a message reject - * and hope for the best. In any case, rejection should be a rare - * occurrence - signal the driver when it happens. + * Pushed message loop to allow the kernel to + * run it's own message state engine. To avoid an + * extra nop instruction after signaling the kernel, + * we perform the phase_lock before checking to see + * if we should exit the loop and skip the phase_lock + * in the ITloop. Performing back to back phase_locks + * shouldn't hurt, but why do it twice... */ - mvi INTSTAT,SEND_REJECT; /* let driver know */ +host_message_loop: + mvi HOST_MSG_LOOP call set_seqint; + call phase_lock; + cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; + jmp host_message_loop; - mvi MSG_MESSAGE_REJECT call mk_mesg; +mesgin_ign_wide_residue: +if ((ahc->features & AHC_WIDE) != 0) { + test SCSIRATE, WIDEXFER jz mesgin_reject; + /* Pull the residue byte */ + mvi ARG_1 call inb_next; + cmp ARG_1, 0x01 jne mesgin_reject; + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; + test DATA_COUNT_ODD, 0x1 jz mesgin_done; + mvi IGN_WIDE_RES call set_seqint; + jmp mesgin_done; +} +mesgin_reject: + mvi MSG_MESSAGE_REJECT call mk_mesg; mesgin_done: mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ jmp ITloop; - mesgin_complete: /* - * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, + * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, * and trigger a completion interrupt. Before doing so, check to see if there * is a residual or the status byte is something other than STATUS_GOOD (0). * In either of these conditions, we upload the SCB back to the host so it can * process this information. In the case of a non zero status byte, we * additionally interrupt the kernel driver synchronously, allowing it to * decide if sense should be retrieved. If the kernel driver wishes to request - * sense, it will fill the kernel SCB with a request sense command and set - * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload - * the SCB, and process it as the next command by adding it to the waiting list. - * If the kernel driver does not wish to request sense, it need only clear - * RETURN_1, and the command is allowed to complete normally. We don't bother - * to post to the QOUTFIFO in the error cases since it would require extra - * work in the kernel driver to ensure that the entry was removed before the - * command complete code tried processing it. + * sense, it will fill the kernel SCB with a request sense command, requeue + * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting + * RETURN_1 to SEND_SENSE. + */ + +/* + * If ATN is raised, we still want to give the target a message. + * Perhaps there was a parity error on this last message byte. + * Either way, the target should take us to message out phase + * and then attempt to complete the command again. We should use a + * critical section here to guard against a timeout triggering + * for this command and setting ATN while we are still processing + * the completion. + test SCSISIGI, ATNI jnz mesgin_done; */ /* - * First check for residuals + * See if we attempted to deliver a message but the target ingnored us. */ - test SCB_RESID_SGCNT,0xff jnz upload_scb; - test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */ + test SCB_CONTROL, MK_MESSAGE jz . + 2; + mvi MKMSG_FAILED call set_seqint; + +/* + * Check for residuals + */ + test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ + test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ + test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; +check_status: + test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ upload_scb: + or SCB_SGPTR, SG_RESID_VALID; mvi DMAPARAMS, FIFORESET; mov SCB_TAG call dma_scb; -check_status: - test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ - mvi INTSTAT,BAD_STATUS; /* let driver know */ - nop; + test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ + mvi BAD_STATUS call set_seqint; /* let driver know */ cmp RETURN_1, SEND_SENSE jne complete; - /* This SCB becomes the next to execute as it will retrieve sense */ - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov SCB_TAG call dma_scb; -add_to_waiting_list: - mov SCB_NEXT,WAITING_SCBH; - mov WAITING_SCBH, SCBPTR; - /* - * Prepare our selection hardware before the busfree so we have a - * high probability of winning arbitration. - */ - call start_selection; + call add_scb_to_free_list; jmp await_busfree; - complete: - /* If we are untagged, clear our address up in host ram */ - test SCB_CONTROL, TAG_ENB jnz complete_post; - mov A, SAVED_TCL; - mvi UNTAGGEDSCB_OFFSET call post_byte_setup; - mvi SCB_LIST_NULL call post_byte; + mov SCB_TAG call complete_post; + jmp await_busfree; +} complete_post: - /* Post the SCB and issue an interrupt */ - if ((p->features & AHC_QUEUE_REGS) != 0) { + /* Post the SCBID in SINDEX and issue an interrupt */ + call add_scb_to_free_list; + mov ARG_1, SINDEX; + if ((ahc->features & AHC_QUEUE_REGS) != 0) { mov A, SDSCB_QOFF; } else { mov A, QOUTPOS; } mvi QOUTFIFO_OFFSET call post_byte_setup; - mov SCB_TAG call post_byte; - if ((p->features & AHC_QUEUE_REGS) == 0) { + mov ARG_1 call post_byte; + if ((ahc->features & AHC_QUEUE_REGS) == 0) { inc QOUTPOS; } - mvi INTSTAT,CMDCMPLT; - -add_to_free_list: - call add_scb_to_free_list; - jmp await_busfree; - -/* - * Is it an extended message? Copy the message to our message buffer and - * notify the host. The host will tell us whether to reject this message, - * respond to it with the message that the host placed in our message buffer, - * or simply to do nothing. - */ -mesgin_extended: - mvi INTSTAT,EXTENDED_MSG; /* let driver know */ - jmp ITloop; + mvi INTSTAT,CMDCMPLT ret; +if ((ahc->flags & AHC_INITIATORROLE) != 0) { /* * Is it a disconnect message? Set a flag in the SCB to remind us - * and await the bus going free. + * and await the bus going free. If this is an untagged transaction + * store the SCB id for it in our untagged target table for lookup on + * a reselction. */ mesgin_disconnect: + /* + * If ATN is raised, we still want to give the target a message. + * Perhaps there was a parity error on this last message byte + * or we want to abort this command. Either way, the target + * should take us to message out phase and then attempt to + * disconnect again. + * XXX - Wait for more testing. + test SCSISIGI, ATNI jnz mesgin_done; + */ + or SCB_CONTROL,DISCONNECTED; - call add_scb_to_disc_list; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + call add_scb_to_disc_list; + } + test SCB_CONTROL, TAG_ENB jnz await_busfree; + mov ARG_1, SCB_TAG; + mov SAVED_LUN, SCB_LUN; + mov SCB_SCSIID call set_busy_target; jmp await_busfree; /* @@ -846,22 +1558,20 @@ */ mesgin_sdptrs: test SEQ_FLAGS, DPHASE jz mesgin_done; + /* - * The SCB SGPTR becomes the next one we'll download, - * and the SCB DATAPTR becomes the current SHADDR. + * The SCB_SGPTR becomes the next one we'll download, + * and the SCB_DATAPTR becomes the current SHADDR. * Use the residual number since STCNT is corrupted by * any message transfer. */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_SGCOUNT, SG_COUNT, 5; - bmov SCB_DATAPTR, SHADDR, 4; - bmov SCB_DATACNT, SCB_RESID_DCNT, 3; + if ((ahc->features & AHC_CMD_CHAN) != 0) { + bmov SCB_DATAPTR, SHADDR, 4; + bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; } else { - mvi DINDEX, SCB_SGCOUNT; - mvi SG_COUNT call bcopy_5; mvi DINDEX, SCB_DATAPTR; - mvi SHADDR call bcopy_4; - mvi SCB_RESID_DCNT call bcopy_3; + mvi SHADDR call bcopy_4; + mvi SCB_RESIDUAL_DATACNT call bcopy_8; } jmp mesgin_done; @@ -880,109 +1590,166 @@ jmp mesgin_done; /* + * Index into our Busy Target table. SINDEX and DINDEX are modified + * upon return. SCBPTR may be modified by this action. + */ +set_busy_target: + shr DINDEX, 4, SINDEX; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mov SCBPTR, SAVED_LUN; + add DINDEX, SCB_64_BTT; + } else { + add DINDEX, BUSY_TARGETS; + } + mov DINDIR, ARG_1 ret; + +/* * Identify message? For a reconnecting target, this tells us the lun * that the reconnection is for - find the correct SCB and switch to it, * clearing the "disconnected" bit so we don't "find" it by accident later. */ mesgin_identify: - - if ((p->features & AHC_WIDE) != 0) { - and A,0x0f; /* lun in lower four bits */ + /* + * Determine whether a target is using tagged or non-tagged + * transactions by first looking at the transaction stored in + * the busy target array. If there is no untagged transaction + * for this target or the transaction is for a different lun, then + * this must be an untagged transaction. + */ + shr SINDEX, 4, SAVED_SCSIID; + and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + add SINDEX, SCB_64_BTT; + mov SCBPTR, SAVED_LUN; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + add NONE, -SCB_64_BTT, SINDEX; + jc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + nop; + add NONE, -(SCB_64_BTT + 16), SINDEX; + jnc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + nop; + } } else { - and A,0x07; /* lun in lower three bits */ + add SINDEX, BUSY_TARGETS; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + add NONE, -BUSY_TARGETS, SINDEX; + jc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + nop; + add NONE, -(BUSY_TARGETS + 16), SINDEX; + jnc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + nop; + } } - or SAVED_TCL,A; /* SAVED_TCL should be complete now */ - - mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ - call get_untagged_SCBID; + mov ARG_1, SINDIR; cmp ARG_1, SCB_LIST_NULL je snoop_tag; - if ((p->flags & AHC_PAGESCBS) != 0) { - test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov ARG_1 call findSCB; + } else { + mov SCBPTR, ARG_1; } - /* - * If the SCB was found in the disconnected list (as is - * always the case in non-paging scenarios), SCBPTR is already - * set to the correct SCB. So, simply setup the SCB and get - * on with things. - */ - mov SCBPTR call rem_scb_from_disc_list; - jmp setup_SCB; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + jmp setup_SCB_id_lun_okay; + } else { + /* + * We only allow one untagged command per-target + * at a time. So, if the lun doesn't match, look + * for a tag message. + */ + mov A, SCB_LUN; + cmp SAVED_LUN, A je setup_SCB_id_lun_okay; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + /* + * findSCB removes the SCB from the + * disconnected list, so we must replace + * it there should this SCB be for another + * lun. + */ + call cleanup_scb; + } + } + /* * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. * If we get one, we use the tag returned to find the proper - * SCB. With SCB paging, this requires using search for both tagged - * and non-tagged transactions since the SCB may exist in any slot. - * If we're not using SCB paging, we can use the tag as the direct - * index to the SCB. + * SCB. With SCB paging, we must search for non-tagged + * transactions since the SCB may exist in any slot. If we're not + * using SCB paging, we can use the tag as the direct index to the + * SCB. */ snoop_tag: + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x80; + } mov NONE,SCSIDATL; /* ACK Identify MSG */ -snoop_tag_loop: call phase_lock; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x1; + } cmp LASTPHASE, P_MESGIN jne not_found; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x2; + } cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; get_tag: - mvi ARG_1 call inb_next; /* tag value */ + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mvi ARG_1 call inb_next; /* tag value */ + mov ARG_1 call findSCB; + } else { + mvi ARG_1 call inb_next; /* tag value */ + mov SCBPTR, ARG_1; + } -use_retrieveSCB: - call retrieveSCB; +/* + * Ensure that the SCB the tag points to is for + * an SCB transaction to the reconnecting target. + */ setup_SCB: - mov A, SAVED_TCL; - cmp SCB_TCL, A jne not_found_cleanup_scb; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x4; + } + mov A, SCB_SCSIID; + cmp SAVED_SCSIID, A jne not_found_cleanup_scb; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x8; + } +setup_SCB_id_okay: + mov A, SCB_LUN; + cmp SAVED_LUN, A jne not_found_cleanup_scb; +setup_SCB_id_lun_okay: + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x10; + } test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; and SCB_CONTROL,~DISCONNECTED; - or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ + test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mov A, SCBPTR; + } + mvi ARG_1, SCB_LIST_NULL; + mov SAVED_SCSIID call set_busy_target; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mov SCBPTR, A; + } +setup_SCB_tagged: + mvi SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ + call set_transfer_settings; /* See if the host wants to send a message upon reconnection */ test SCB_CONTROL, MK_MESSAGE jz mesgin_done; - and SCB_CONTROL, ~MK_MESSAGE; mvi HOST_MSG call mk_mesg; jmp mesgin_done; not_found_cleanup_scb: - test SCB_CONTROL, DISCONNECTED jz . + 3; - call add_scb_to_disc_list; - jmp not_found; - call add_scb_to_free_list; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + call cleanup_scb; + } not_found: - mvi INTSTAT, NO_MATCH; - mvi MSG_BUS_DEV_RESET call mk_mesg; - jmp mesgin_done; - -/* - * Message reject? Let the kernel driver handle this. If we have an - * outstanding WDTR or SDTR negotiation, assume that it's a response from - * the target selecting 8bit or asynchronous transfer, otherwise just ignore - * it since we have no clue what it pertains to. - */ -mesgin_reject: - mvi INTSTAT, REJECT_MSG; - jmp mesgin_done; - -/* - * Wide Residue. We handle the simple cases, but pass of the one hard case - * to the kernel (when the residue byte happened to cause us to advance our - * sg element array, so we know have to back that advance out). - */ -mesgin_wide_residue: - mvi ARG_1 call inb_next; /* ACK the wide_residue and get */ - /* the size byte */ -/* - * In order for this to be reliable, we have to do all sorts of horrible - * magic in terms of resetting the datafifo and reloading the shadow layer - * with the correct new values (so that a subsequent save data pointers - * message will do the right thing). We let the kernel do that work. - */ - mvi INTSTAT, WIDE_RESIDUE; + mvi NO_MATCH call set_seqint; jmp mesgin_done; - -/* - * [ ADD MORE MESSAGE HANDLING HERE ] - */ -/* - * Locking the driver out, build a one-byte message passed in SINDEX - * if there is no active message already. SINDEX is returned intact. - */ mk_mesg: or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ mov MSG_OUT,SINDEX ret; @@ -1002,7 +1769,9 @@ * and that REQ is already set when inb_first is called. inb_{first,next} * use the same calling convention as inb. */ - +inb_next_wait_perr: + mvi PERR_DETECTED call set_seqint; + jmp inb_next_wait; inb_next: mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ inb_next_wait: @@ -1012,7 +1781,8 @@ * before continuing. */ test SSTAT1, REQINIT jz inb_next_wait; - test SSTAT1, SCSIPERR jnz .; + test SSTAT1, SCSIPERR jnz inb_next_wait_perr; +inb_next_check_phase: and LASTPHASE, PHASE_MASK, SCSISIGI; cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; inb_first: @@ -1020,71 +1790,48 @@ mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ inb_last: mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ +} -mesgin_phasemis: +if ((ahc->flags & AHC_TARGETROLE) != 0) { /* - * We expected to receive another byte, but the target changed phase + * Change to a new phase. If we are changing the state of the I/O signal, + * from out to in, wait an additional data release delay before continuing. */ - mvi INTSTAT, MSGIN_PHASEMIS; - jmp ITloop; - -/* - * DMA data transfer. HADDR and HCNT must be loaded first, and - * SINDEX should contain the value to load DFCNTRL with - 0x3d for - * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared - * during initialization. - */ -if ((p->features & AHC_ULTRA2) == 0) { -dma: - mov DFCNTRL,SINDEX; -dma_loop: - test SSTAT0,DMADONE jnz dma_dmadone; - test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ -dma_phasemis: - test SSTAT0,SDONE jnz dma_checkfifo; - mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ +change_phase: + /* Wait for preceeding I/O session to complete. */ + test SCSISIGI, ACKI jnz .; + + /* Change the phase */ + and DINDEX, IOI, SCSISIGI; + mov SCSISIGO, SINDEX; + and A, IOI, SINDEX; -/* - * We will be "done" DMAing when the transfer count goes to zero, or - * the target changes the phase (in light of this, it makes sense that - * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are - * doing a SCSI->Host transfer, the data FIFO should be flushed auto- - * magically on STCNT=0 or a phase change, so just wait for FIFO empty - * status. - */ -dma_checkfifo: - test DFCNTRL,DIRECTION jnz dma_fifoempty; -dma_fifoflush: - test DFSTATUS,FIFOEMP jz dma_fifoflush; + /* + * If the data direction has changed, from + * out (initiator driving) to in (target driving), + * we must wait at least a data release delay plus + * the normal bus settle delay. [SCSI III SPI 10.11.0] + */ + cmp DINDEX, A je change_phase_wait; + test SINDEX, IOI jz change_phase_wait; + call change_phase_wait; +change_phase_wait: + nop; + nop; + nop; + nop ret; -dma_fifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz dma_fifoempty; /* - * Now shut the DMA enables off and make sure that the DMA enables are - * actually off first lest we get an ILLSADDR. + * Send a byte to an initiator in Automatic PIO mode. */ -dma_dmadone: - cmp LASTPHASE, P_COMMAND je dma_await_nreq; - test SCSIRATE, 0x0f jnz dma_shutdown; -dma_await_nreq: - test SCSISIGI, REQI jz dma_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz dma_await_nreq; -dma_shutdown: - and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); -dma_halt: - /* - * Some revisions of the aic7880 have a problem where, if the - * data fifo is full, but the PCI input latch is not empty, - * HDMAEN cannot be cleared. The fix used here is to attempt - * to drain the data fifo until there is space for the input - * latch to drain and HDMAEN de-asserts. - */ - mov NONE, DFDAT; - test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; +target_outb: + or SXFRCTL0, SPIOEN; + test SSTAT0, SPIORDY jz .; + mov SCSIDATL, SINDEX; + test SSTAT0, SPIORDY jz .; + and SXFRCTL0, ~SPIOEN ret; } -return: - ret; + /* * Assert that if we've been reselected, then we've seen an IDENTIFY @@ -1093,138 +1840,69 @@ assert: test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ - mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ + mvi NO_IDENT jmp set_seqint; /* no - tell the kernel */ /* - * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) - * or by the SCBID ARG_1. The search begins at the SCB index passed in - * via SINDEX which is an SCB that must be on the disconnected list. If - * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR - * is set to the proper SCB. + * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will + * be set to the position of the SCB. If the SCB cannot be found locally, + * it will be paged in from host memory. RETURN_2 stores the address of the + * preceding SCB in the disconnected list which can be used to speed up + * removal of the found SCB from the disconnected list. */ +if ((ahc->flags & AHC_PAGESCBS) != 0) { +BEGIN_CRITICAL findSCB: - mov SCBPTR,SINDEX; /* Initialize SCBPTR */ - cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; - mov A, SAVED_TCL; - mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */ -findSCB_by_SCBID: - mov A, ARG_1; /* Tag passed in ARG_1 */ - mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ + mov A, SINDEX; /* Tag passed in SINDEX */ + cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; + mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ + mvi ARG_2, SCB_LIST_NULL; /* Head of list */ + jmp findSCB_loop; findSCB_next: - mov ARG_2, SCBPTR; - cmp SCB_NEXT, SCB_LIST_NULL je notFound; + cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; + mov ARG_2, SCBPTR; mov SCBPTR,SCB_NEXT; - dec SINDEX; /* Last comparison moved us too far */ findSCB_loop: - cmp SINDIR, A jne findSCB_next; - mov SINDEX, SCBPTR ret; -notFound: - mvi SINDEX, SCB_LIST_NULL ret; - -/* - * Retrieve an SCB by SCBID first searching the disconnected list falling - * back to DMA'ing the SCB down from the host. This routine assumes that - * ARG_1 is the SCBID of interrest and that SINDEX is the position in the - * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, - * we go directly to the host for the SCB. - */ -retrieveSCB: - test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; - mov SCBPTR call findSCB; /* Continue the search */ - cmp SINDEX, SCB_LIST_NULL je retrieve_from_host; - -/* - * This routine expects SINDEX to contain the index of the SCB to be - * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the - * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL - * if it is at the head. - */ + cmp SCB_TAG, A jne findSCB_next; rem_scb_from_disc_list: -/* Remove this SCB from the disconnection list */ - cmp ARG_2, SCB_LIST_NULL je rHead; + cmp ARG_2, SCB_LIST_NULL je rHead; mov DINDEX, SCB_NEXT; + mov SINDEX, SCBPTR; mov SCBPTR, ARG_2; mov SCB_NEXT, DINDEX; mov SCBPTR, SINDEX ret; rHead: mov DISCONNECTED_SCBH,SCB_NEXT ret; - -retrieve_from_host: -/* - * We didn't find it. Pull an SCB and DMA down the one we want. - * We should never get here in the non-paging case. - */ - mov ALLZEROS call get_free_or_disc_scb; +END_CRITICAL +findSCB_notFound: + /* + * We didn't find it. Page in the SCB. + */ + mov ARG_1, A; /* Save tag */ + mov ALLZEROS call get_free_or_disc_scb; mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - /* Jump instead of call as we want to return anyway */ mov ARG_1 jmp dma_scb; - -/* - * Determine whether a target is using tagged or non-tagged transactions - * by first looking for a matching transaction based on the TCL and if - * that fails, looking up this device in the host's untagged SCB array. - * The TCL to search for is assumed to be in SAVED_TCL. The value is - * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). - * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information - * in an SCB instead of having to go to the host. - */ -get_untagged_SCBID: - cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; - mvi ARG_1, SCB_LIST_NULL; - mov DISCONNECTED_SCBH call findSCB; - cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; - or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ - test SCB_CONTROL, TAG_ENB jnz . + 2; - mov ARG_1, SCB_TAG ret; - mvi ARG_1, SCB_LIST_NULL ret; - -/* - * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) - * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. - */ -fetch_byte: - mov ARG_2, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi CCHCNT, 1; - mvi CCSGCTL, CCSGEN|CCSGRESET; - test CCSGCTL, CCSGDONE jz .; - mvi CCSGCTL, CCSGRESET; - bmov RETURN_2, CCSGRAM, 1 ret; - } else { - mvi DINDEX, HADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi HCNT[0], 1; - clr HCNT[1]; - clr HCNT[2]; - mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - call dma_finish; - mov RETURN_2, DFDAT ret; - } +} /* * Prepare the hardware to post a byte to host memory given an - * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. + * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. */ post_byte_setup: mov ARG_2, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { + if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; - mvi SCBID_ADDR call set_1byte_addr; + mvi SHARED_DATA_ADDR call set_1byte_addr; mvi CCHCNT, 1; mvi CCSCBCTL, CCSCBRESET ret; } else { mvi DINDEX, HADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi HCNT[0], 1; - clr HCNT[1]; - clr HCNT[2]; + mvi SHARED_DATA_ADDR call set_1byte_addr; + mvi 1 call set_hcnt; mvi DFCNTRL, FIFORESET ret; } post_byte: - if ((p->features & AHC_CMD_CHAN) != 0) { + if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov CCSCBRAM, SINDEX, 1; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; @@ -1235,23 +1913,34 @@ jmp dma_finish; } -get_SCBID_from_host: - mov A, SAVED_TCL; - mvi UNTAGGEDSCB_OFFSET call fetch_byte; - mov RETURN_1, RETURN_2 ret; - +phase_lock_perr: + mvi PERR_DETECTED call set_seqint; phase_lock: + /* + * If there is a parity error, wait for the kernel to + * see the interrupt and prepare our message response + * before continuing. + */ test SSTAT1, REQINIT jz phase_lock; - test SSTAT1, SCSIPERR jnz phase_lock; + test SSTAT1, SCSIPERR jnz phase_lock_perr; +phase_lock_latch_phase: and SCSISIGO, PHASE_MASK, SCSISIGI; and LASTPHASE, PHASE_MASK, SCSISIGI ret; -if ((p->features & AHC_CMD_CHAN) == 0) { +if ((ahc->features & AHC_CMD_CHAN) == 0) { +set_hcnt: + mov HCNT[0], SINDEX; +clear_hcnt: + clr HCNT[1]; + clr HCNT[2] ret; + set_stcnt_from_hcnt: mov STCNT[0], HCNT[0]; mov STCNT[1], HCNT[1]; mov STCNT[2], HCNT[2] ret; +bcopy_8: + mov DINDIR, SINDIR; bcopy_7: mov DINDIR, SINDIR; mov DINDIR, SINDIR; @@ -1265,6 +1954,7 @@ mov DINDIR, SINDIR ret; } +if ((ahc->flags & AHC_TARGETROLE) != 0) { /* * Setup addr assuming that A is an index into * an array of 32byte objects, SINDEX contains @@ -1275,16 +1965,30 @@ set_32byte_addr: shr ARG_2, 3, A; shl A, 5; + jmp set_1byte_addr; +} + +/* + * Setup addr assuming that A is an index into + * an array of 64byte objects, SINDEX contains + * the base address of that array, and DINDEX + * contains the base address of the location + * to store the indexed address. + */ +set_64byte_addr: + shr ARG_2, 2, A; + shl A, 6; + /* - * Setup addr assuming that A + (ARG_1 * 256) is an + * Setup addr assuming that A + (ARG_2 * 256) is an * index into an array of 1byte objects, SINDEX contains * the base address of that array, and DINDEX contains * the base address of the location to store the computed * address. */ set_1byte_addr: - add DINDIR, A, SINDIR; - mov A, ARG_2; + add DINDIR, A, SINDIR; + mov A, ARG_2; adc DINDIR, A, SINDIR; clr A; adc DINDIR, A, SINDIR; @@ -1296,21 +2000,32 @@ */ dma_scb: mov A, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { + if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; - mvi HSCB_ADDR call set_32byte_addr; + mvi HSCB_ADDR call set_64byte_addr; mov CCSCBPTR, SCBPTR; - mvi CCHCNT, 32; test DMAPARAMS, DIRECTION jz dma_scb_tohost; + if ((ahc->flags & AHC_SCB_BTT) != 0) { + mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; + } else { + mvi CCHCNT, SCB_DOWNLOAD_SIZE; + } mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; jmp dma_scb_finish; dma_scb_tohost: - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + mvi CCHCNT, SCB_UPLOAD_SIZE; + if ((ahc->features & AHC_ULTRA2) == 0) { mvi CCSCBCTL, CCSCBRESET; - bmov CCSCBRAM, SCB_CONTROL, 32; + bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; + } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { + mvi CCSCBCTL, CCARREN|CCSCBRESET; + cmp CCSCBCTL, ARRDONE|CCARREN jne .; + mvi CCHCNT, SCB_UPLOAD_SIZE; + mvi CCSCBCTL, CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; } else { mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; @@ -1321,85 +2036,161 @@ ret; } else { mvi DINDEX, HADDR; - mvi HSCB_ADDR call set_32byte_addr; - mvi HCNT[0], 32; - clr HCNT[1]; - clr HCNT[2]; + mvi HSCB_ADDR call set_64byte_addr; + mvi SCB_DOWNLOAD_SIZE call set_hcnt; mov DFCNTRL, DMAPARAMS; test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; /* Fill it with the SCB data */ copy_scb_tofifo: - mvi SINDEX, SCB_CONTROL; - add A, 32, SINDEX; + mvi SINDEX, SCB_BASE; + add A, SCB_DOWNLOAD_SIZE, SINDEX; copy_scb_tofifo_loop: - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; + call copy_to_fifo_8; cmp SINDEX, A jne copy_scb_tofifo_loop; or DFCNTRL, HDMAEN|FIFOFLUSH; + jmp dma_finish; dma_scb_fromhost: - call dma_finish; + mvi DINDEX, SCB_BASE; + if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { + /* + * The PCI module will only issue a PCI + * retry if the data FIFO is empty. If the + * host disconnects in the middle of a + * transfer, we must empty the fifo of all + * available data to force the chip to + * continue the transfer. This does not + * happen for SCSI transfers as the SCSI module + * will drain the FIFO as data is made available. + * When the hang occurs, we know that a multiple + * of 8 bytes are in the FIFO because the PCI + * module has an 8 byte input latch that only + * dumps to the FIFO when HCNT == 0 or the + * latch is full. + */ + clr A; + /* Wait for some data to arrive. */ +dma_scb_hang_fifo: + test DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo; +dma_scb_hang_wait: + test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; + /* + * The PCI module no longer intends to perform + * a PCI transaction and HDONE has not come true. + * We are hung. Drain the fifo. + */ +dma_scb_hang_empty_fifo: + /* + * Skip lines not yet transfered into the FIFO. + */ + add SINDEX, 7, HCNT; + shr SINDEX, 3; + + /* + * Skip lines already copied out of the FIFO. + */ + add A, A, SINDEX; + + call dma_scb_hang_dma_drain_fifo; + + /* + * Set the lines transferred to all but + * those yet to reach the FIFO. + */ + not SINDEX; + add A, 5, SINDEX; + jmp dma_scb_hang_fifo; +dma_scb_hang_dma_done: + and DFCNTRL, ~HDMAEN; + test DFCNTRL, HDMAEN jnz .; +dma_scb_hang_dma_drain_fifo: + add SEQADDR0, A; + } else { + call dma_finish; + } /* If we were putting the SCB, we are done */ - test DMAPARAMS, DIRECTION jz return; - mvi SCB_CONTROL call dfdat_in_7; - call dfdat_in_7_continued; - call dfdat_in_7_continued; - jmp dfdat_in_7_continued; + call dfdat_in_8; + call dfdat_in_8; + call dfdat_in_8; +dfdat_in_8: + mov DINDIR,DFDAT; dfdat_in_7: - mov DINDEX,SINDEX; -dfdat_in_7_continued: mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; +dfdat_in_2: mov DINDIR,DFDAT; mov DINDIR,DFDAT ret; } +copy_to_fifo_8: + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; +copy_to_fifo_6: + mov DFDAT,SINDIR; +copy_to_fifo_5: + mov DFDAT,SINDIR; +copy_to_fifo_4: + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR ret; /* * Wait for DMA from host memory to data FIFO to complete, then disable * DMA and wait for it to acknowledge that it's off. */ -if ((p->features & AHC_CMD_CHAN) == 0) { dma_finish: test DFSTATUS,HDONE jz dma_finish; /* Turn off DMA */ and DFCNTRL, ~HDMAEN; test DFCNTRL, HDMAEN jnz .; ret; -} +/* + * Restore an SCB that failed to match an incoming reselection + * to the correct/safe state. If the SCB is for a disconnected + * transaction, it must be returned to the disconnected list. + * If it is not in the disconnected state, it must be free. + */ +cleanup_scb: + if ((ahc->flags & AHC_PAGESCBS) != 0) { + test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list; + } add_scb_to_free_list: - if ((p->flags & AHC_PAGESCBS) != 0) { + if ((ahc->flags & AHC_PAGESCBS) != 0) { +BEGIN_CRITICAL mov SCB_NEXT, FREE_SCBH; - mov FREE_SCBH, SCBPTR; + mvi SCB_TAG, SCB_LIST_NULL; + mov FREE_SCBH, SCBPTR ret; +END_CRITICAL + } else { + mvi SCB_TAG, SCB_LIST_NULL ret; } - mvi SCB_TAG, SCB_LIST_NULL ret; -if ((p->flags & AHC_PAGESCBS) != 0) { +if ((ahc->flags & AHC_PAGESCBS) != 0) { get_free_or_disc_scb: +BEGIN_CRITICAL cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; return_error: + mvi NO_FREE_SCB call set_seqint; mvi SINDEX, SCB_LIST_NULL ret; dequeue_disc_scb: mov SCBPTR, DISCONNECTED_SCBH; -dma_up_scb: + mov DISCONNECTED_SCBH, SCB_NEXT; +END_CRITICAL mvi DMAPARAMS, FIFORESET; - mov SCB_TAG call dma_scb; -unlink_disc_scb: - mov DISCONNECTED_SCBH, SCB_NEXT ret; + mov SCB_TAG jmp dma_scb; +BEGIN_CRITICAL dequeue_free_scb: mov SCBPTR, FREE_SCBH; mov FREE_SCBH, SCB_NEXT ret; -} +END_CRITICAL add_scb_to_disc_list: /* @@ -1407,5 +2198,13 @@ * candidates for paging out an SCB if one is needed for a new command. * Modifying the disconnected list is a critical(pause dissabled) section. */ +BEGIN_CRITICAL mov SCB_NEXT, DISCONNECTED_SCBH; mov DISCONNECTED_SCBH, SCBPTR ret; +END_CRITICAL +} +set_seqint: + mov INTSTAT, SINDEX; + nop; +return: + ret; diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,205 @@ +/* + * Interface for the 93C66/56/46/26/06 serial eeprom parts. + * + * Copyright (c) 1995, 1996 Daniel M. Eischen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aic7xxx_93cx6.c#7 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.c,v 1.9 2000/11/10 20:13:41 gibbs Exp $ + */ + +/* + * The instruction set of the 93C66/56/46/26/06 chips are as follows: + * + * Start OP * + * Function Bit Code Address** Data Description + * ------------------------------------------------------------------- + * READ 1 10 A5 - A0 Reads data stored in memory, + * starting at specified address + * EWEN 1 00 11XXXX Write enable must preceed + * all programming modes + * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 + * WRITE 1 01 A5 - A0 D15 - D0 Writes register + * ERAL 1 00 10XXXX Erase all registers + * WRAL 1 00 01XXXX D15 - D0 Writes to all registers + * EWDS 1 00 00XXXX Disables all programming + * instructions + * *Note: A value of X for address is a don't care condition. + * **Note: There are 8 address bits for the 93C56/66 chips unlike + * the 93C46/26/06 chips which have 6 address bits. + * + * The 93C46 has a four wire interface: clock, chip select, data in, and + * data out. In order to perform one of the above functions, you need + * to enable the chip select for a clock period (typically a minimum of + * 1 usec, with the clock high and low a minimum of 750 and 250 nsec + * respectively). While the chip select remains high, you can clock in + * the instructions (above) starting with the start bit, followed by the + * OP code, Address, and Data (if needed). For the READ instruction, the + * requested 16-bit register contents is read from the data out line but + * is preceded by an initial zero (leading 0, followed by 16-bits, MSB + * first). The clock cycling from low to high initiates the next data + * bit to be sent from the chip. + * + */ + +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" +#include "aic7xxx_93cx6.h" + +/* + * Right now, we only have to read the SEEPROM. But we make it easier to + * add other 93Cx6 functions. + */ +static struct seeprom_cmd { + uint8_t len; + uint8_t bits[3]; +} seeprom_read = {3, {1, 1, 0}}; + +/* + * Wait for the SEERDY to go high; about 800 ns. + */ +#define CLOCK_PULSE(sd, rdy) \ + while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) { \ + ; /* Do nothing */ \ + } \ + (void)SEEPROM_INB(sd); /* Clear clock */ + +/* + * Read the serial EEPROM and returns 1 if successful and 0 if + * not successful. + */ +int +read_seeprom(sd, buf, start_addr, count) + struct seeprom_descriptor *sd; + uint16_t *buf; + u_int start_addr; + u_int count; +{ + int i = 0; + u_int k = 0; + uint16_t v; + uint8_t temp; + + /* + * Read the requested registers of the seeprom. The loop + * will range from 0 to count-1. + */ + for (k = start_addr; k < count + start_addr; k++) { + /* Send chip select for one clock cycle. */ + temp = sd->sd_MS ^ sd->sd_CS; + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + + /* + * Now we're ready to send the read command followed by the + * address of the 16-bit register we want to read. + */ + for (i = 0; i < seeprom_read.len; i++) { + if (seeprom_read.bits[i] != 0) + temp ^= sd->sd_DO; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + if (seeprom_read.bits[i] != 0) + temp ^= sd->sd_DO; + } + /* Send the 6 or 8 bit address (MSB first, LSB last). */ + for (i = (sd->sd_chip - 1); i >= 0; i--) { + if ((k & (1 << i)) != 0) + temp ^= sd->sd_DO; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + if ((k & (1 << i)) != 0) + temp ^= sd->sd_DO; + } + + /* + * Now read the 16 bit register. An initial 0 precedes the + * register contents which begins with bit 15 (MSB) and ends + * with bit 0 (LSB). The initial 0 will be shifted off the + * top of our word as we let the loop run from 0 to 16. + */ + v = 0; + for (i = 16; i >= 0; i--) { + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + v <<= 1; + if (SEEPROM_DATA_INB(sd) & sd->sd_DI) + v |= 1; + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + } + + buf[k - start_addr] = v; + + /* Reset the chip select for the next command cycle. */ + temp = sd->sd_MS; + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp ^ sd->sd_CK); + CLOCK_PULSE(sd, sd->sd_RDY); + SEEPROM_OUTB(sd, temp); + CLOCK_PULSE(sd, sd->sd_RDY); + } +#ifdef AHC_DUMP_EEPROM + printf("\nSerial EEPROM:\n\t"); + for (k = 0; k < count; k = k + 1) { + if (((k % 8) == 0) && (k != 0)) { + printf ("\n\t"); + } + printf (" 0x%x", buf[k]); + } + printf ("\n"); +#endif + return (1); +} + +int +verify_cksum(struct seeprom_config *sc) +{ + int i; + int maxaddr; + uint32_t checksum; + uint16_t *scarray; + + maxaddr = (sizeof(*sc)/2) - 1; + checksum = 0; + scarray = (uint16_t *)sc; + + for (i = 0; i < maxaddr; i++) + checksum = checksum + scarray[i]; + if (checksum == 0 + || (checksum & 0xFFFF) != sc->checksum) { + return (0); + } else { + return(1); + } +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.h linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,92 @@ +/* + * Interface to the 93C46/56 serial EEPROM that is used to store BIOS + * settings for the aic7xxx based adaptec SCSI controllers. It can + * also be used for 93C26 and 93C06 serial EEPROMS. + * + * Copyright (c) 1994, 1995, 2000 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aic7xxx_93cx6.h#5 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.h,v 1.8 2000/11/10 20:13:41 gibbs Exp $ + */ +#ifndef _AIC7XXX_93CX6_H_ +#define _AIC7XXX_93CX6_H_ + +typedef enum { + C46 = 6, + C56_66 = 8 +} seeprom_chip_t; + +struct seeprom_descriptor { + struct ahc_softc *sd_ahc; + u_int sd_control_offset; + u_int sd_status_offset; + u_int sd_dataout_offset; + seeprom_chip_t sd_chip; + uint16_t sd_MS; + uint16_t sd_RDY; + uint16_t sd_CS; + uint16_t sd_CK; + uint16_t sd_DO; + uint16_t sd_DI; +}; + +/* + * This function will read count 16-bit words from the serial EEPROM and + * return their value in buf. The port address of the aic7xxx serial EEPROM + * control register is passed in as offset. The following parameters are + * also passed in: + * + * CS - Chip select + * CK - Clock + * DO - Data out + * DI - Data in + * RDY - SEEPROM ready + * MS - Memory port mode select + * + * A failed read attempt returns 0, and a successful read returns 1. + */ + +#define SEEPROM_INB(sd) \ + ahc_inb(sd->sd_ahc, sd->sd_control_offset) +#define SEEPROM_OUTB(sd, value) \ +do { \ + ahc_outb(sd->sd_ahc, sd->sd_control_offset, value); \ + ahc_flush_device_writes(sd->sd_ahc); \ +} while(0) + +#define SEEPROM_STATUS_INB(sd) \ + ahc_inb(sd->sd_ahc, sd->sd_status_offset) +#define SEEPROM_DATA_INB(sd) \ + ahc_inb(sd->sd_ahc, sd->sd_dataout_offset) + +int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, + u_int start_addr, u_int count); +int verify_cksum(struct seeprom_config *sc); + +#endif /* _AIC7XXX_93CX6_H_ */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_inline.h linux/drivers/scsi/aic7xxx/aic7xxx_inline.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_inline.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_inline.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,478 @@ +/* + * Inline routines shareable across OS platforms. + * + * Copyright (c) 1994-2001 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#15 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $ + */ + +#ifndef _AIC7XXX_INLINE_H_ +#define _AIC7XXX_INLINE_H_ + +/************************* Sequencer Execution Control ************************/ +static __inline int sequencer_paused(struct ahc_softc *ahc); +static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc); +static __inline void pause_sequencer(struct ahc_softc *ahc); +static __inline void unpause_sequencer(struct ahc_softc *ahc); + +/* + * Work around any chip bugs related to halting sequencer execution. + * On Ultra2 controllers, we must clear the CIOBUS stretch signal by + * reading a register that will set this signal and deassert it. + * Without this workaround, if the chip is paused, by an interrupt or + * manual pause while accessing scb ram, accesses to certain registers + * will hang the system (infinite pci retries). + */ +static __inline void +ahc_pause_bug_fix(struct ahc_softc *ahc) +{ + if ((ahc->features & AHC_ULTRA2) != 0) + (void)ahc_inb(ahc, CCSCBCTL); +} + +/* + * Determine whether the sequencer has halted code execution. + * Returns non-zero status if the sequencer is stopped. + */ +static __inline int +sequencer_paused(struct ahc_softc *ahc) +{ + return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); +} + +/* + * Request that the sequencer stop and wait, indefinitely, for it + * to stop. The sequencer will only acknowledge that it is paused + * once it has reached an instruction boundary and PAUSEDIS is + * cleared in the SEQCTL register. The sequencer may use PAUSEDIS + * for critical sections. + */ +static __inline void +pause_sequencer(struct ahc_softc *ahc) +{ + ahc_outb(ahc, HCNTRL, ahc->pause); + + /* + * Since the sequencer can disable pausing in a critical section, we + * must loop until it actually stops. + */ + while (sequencer_paused(ahc) == 0) + ; + + ahc_pause_bug_fix(ahc); +} + +/* + * Allow the sequencer to continue program execution. + * We check here to ensure that no additional interrupt + * sources that would cause the sequencer to halt have been + * asserted. If, for example, a SCSI bus reset is detected + * while we are fielding a different, pausing, interrupt type, + * we don't want to release the sequencer before going back + * into our interrupt handler and dealing with this new + * condition. + */ +static __inline void +unpause_sequencer(struct ahc_softc *ahc) +{ + if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) + ahc_outb(ahc, HCNTRL, ahc->unpause); +} + +/*********************** Untagged Transaction Routines ************************/ +static __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc); +static __inline void ahc_release_untagged_queues(struct ahc_softc *ahc); + +/* + * Block our completion routine from starting the next untagged + * transaction for this target or target lun. + */ +static __inline void +ahc_freeze_untagged_queues(struct ahc_softc *ahc) +{ + if ((ahc->flags & AHC_SCB_BTT) == 0) + ahc->untagged_queue_lock++; +} + +/* + * Allow the next untagged transaction for this target or target lun + * to be executed. We use a counting semaphore to allow the lock + * to be acquired recursively. Once the count drops to zero, the + * transaction queues will be run. + */ +static __inline void +ahc_release_untagged_queues(struct ahc_softc *ahc) +{ + if ((ahc->flags & AHC_SCB_BTT) == 0) { + ahc->untagged_queue_lock--; + if (ahc->untagged_queue_lock == 0) + ahc_run_untagged_queues(ahc); + } +} + +/************************** Memory mapping routines ***************************/ +static __inline struct ahc_dma_seg * + ahc_sg_bus_to_virt(struct scb *scb, + uint32_t sg_busaddr); +static __inline uint32_t + ahc_sg_virt_to_bus(struct scb *scb, + struct ahc_dma_seg *sg); +static __inline uint32_t + ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index); + +static __inline struct ahc_dma_seg * +ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr) +{ + int sg_index; + + sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg); + /* sg_list_phys points to entry 1, not 0 */ + sg_index++; + + return (&scb->sg_list[sg_index]); +} + +static __inline uint32_t +ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg) +{ + int sg_index; + + /* sg_list_phys points to entry 1, not 0 */ + sg_index = sg - &scb->sg_list[1]; + + return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list))); +} + +static __inline uint32_t +ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index) +{ + return (ahc->scb_data->hscb_busaddr + + (sizeof(struct hardware_scb) * index)); +} + +/******************************** Debugging ***********************************/ +static __inline char *ahc_name(struct ahc_softc *ahc); + +static __inline char * +ahc_name(struct ahc_softc *ahc) +{ + return (ahc->name); +} + +/*********************** Miscelaneous Support Functions ***********************/ + +static __inline int ahc_check_residual(struct scb *scb); +static __inline struct ahc_initiator_tinfo * + ahc_fetch_transinfo(struct ahc_softc *ahc, + char channel, u_int our_id, + u_int remote_id, + struct tmode_tstate **tstate); +static __inline struct scb* + ahc_get_scb(struct ahc_softc *ahc); +static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); +static __inline void ahc_swap_with_next_hscb(struct ahc_softc *ahc, + struct scb *scb); +static __inline void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb); +static __inline struct scsi_sense_data * + ahc_get_sense_buf(struct ahc_softc *ahc, + struct scb *scb); +static __inline uint32_t + ahc_get_sense_bufaddr(struct ahc_softc *ahc, + struct scb *scb); + +/* + * Determine whether the sequencer reported a residual + * for this SCB/transaction. + */ +static __inline int +ahc_check_residual(struct scb *scb) +{ + struct status_pkt *sp; + + sp = &scb->hscb->shared_data.status; + if ((scb->hscb->sgptr & SG_RESID_VALID) != 0) + return (1); + return (0); +} + +/* + * Return pointers to the transfer negotiation information + * for the specified our_id/remote_id pair. + */ +static __inline struct ahc_initiator_tinfo * +ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, + u_int remote_id, struct tmode_tstate **tstate) +{ + /* + * Transfer data structures are stored from the perspective + * of the target role. Since the parameters for a connection + * in the initiator role to a given target are the same as + * when the roles are reversed, we pretend we are the target. + */ + if (channel == 'B') + our_id += 8; + *tstate = ahc->enabled_targets[our_id]; + return (&(*tstate)->transinfo[remote_id]); +} + +/* + * Get a free scb. If there are none, see if we can allocate a new SCB. + */ +static __inline struct scb * +ahc_get_scb(struct ahc_softc *ahc) +{ + struct scb *scb; + + if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) { + ahc_alloc_scbs(ahc); + scb = SLIST_FIRST(&ahc->scb_data->free_scbs); + if (scb == NULL) + return (NULL); + } + SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle); + return (scb); +} + +/* + * Return an SCB resource to the free list. + */ +static __inline void +ahc_free_scb(struct ahc_softc *ahc, struct scb *scb) +{ + struct hardware_scb *hscb; + + hscb = scb->hscb; + /* Clean up for the next user */ + ahc->scb_data->scbindex[hscb->tag] = NULL; + scb->flags = SCB_FREE; + hscb->control = 0; + + SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle); + + /* Notify the OSM that a resource is now available. */ + ahc_platform_scb_free(ahc, scb); +} + +static __inline struct scb * +ahc_lookup_scb(struct ahc_softc *ahc, u_int tag) +{ + return (ahc->scb_data->scbindex[tag]); + +} + +static __inline void +ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb) +{ + struct hardware_scb *q_hscb; + u_int saved_tag; + + /* + * Our queuing method is a bit tricky. The card + * knows in advance which HSCB to download, and we + * can't disappoint it. To achieve this, the next + * SCB to download is saved off in ahc->next_queued_scb. + * When we are called to queue "an arbitrary scb", + * we copy the contents of the incoming HSCB to the one + * the sequencer knows about, swap HSCB pointers and + * finally assign the SCB to the tag indexed location + * in the scb_array. This makes sure that we can still + * locate the correct SCB by SCB_TAG. + */ + q_hscb = ahc->next_queued_scb->hscb; + saved_tag = q_hscb->tag; + memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); + if ((scb->flags & SCB_CDB32_PTR) != 0) { + q_hscb->shared_data.cdb_ptr = + ahc_hscb_busaddr(ahc, q_hscb->tag) + + offsetof(struct hardware_scb, cdb32); + } + q_hscb->tag = saved_tag; + q_hscb->next = scb->hscb->tag; + + /* Now swap HSCB pointers. */ + ahc->next_queued_scb->hscb = scb->hscb; + scb->hscb = q_hscb; + + /* Now define the mapping from tag to SCB in the scbindex */ + ahc->scb_data->scbindex[scb->hscb->tag] = scb; +} + +/* + * Tell the sequencer about a new transaction to execute. + */ +static __inline void +ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb) +{ + ahc_swap_with_next_hscb(ahc, scb); + + if (scb->hscb->tag == SCB_LIST_NULL + || scb->hscb->next == SCB_LIST_NULL) + panic("Attempt to queue invalid SCB tag %x:%x\n", + scb->hscb->tag, scb->hscb->next); + + /* + * Keep a history of SCBs we've downloaded in the qinfifo. + */ + ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); + } else { + if ((ahc->features & AHC_AUTOPAUSE) == 0) + pause_sequencer(ahc); + ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); + if ((ahc->features & AHC_AUTOPAUSE) == 0) + unpause_sequencer(ahc); + } +} + +static __inline struct scsi_sense_data * +ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb) +{ + int offset; + + offset = scb - ahc->scb_data->scbarray; + return (&ahc->scb_data->sense[offset]); +} + +static __inline uint32_t +ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb) +{ + int offset; + + offset = scb - ahc->scb_data->scbarray; + return (ahc->scb_data->sense_busaddr + + (offset * sizeof(struct scsi_sense_data))); +} + +/************************** Interrupt Processing ******************************/ +static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc); +static __inline void ahc_intr(struct ahc_softc *ahc); + +/* + * See if the firmware has posted any completed commands + * into our in-core command complete fifos. + */ +#define AHC_RUN_QOUTFIFO 0x1 +#define AHC_RUN_TQINFIFO 0x2 +static __inline u_int +ahc_check_cmdcmpltqueues(struct ahc_softc *ahc) +{ + u_int retval; + + retval = 0; + if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) + retval |= AHC_RUN_QOUTFIFO; +#ifdef AHC_TARGET_MODE + if ((ahc->flags & AHC_TARGETROLE) != 0 + && ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0) + retval |= AHC_RUN_TQINFIFO; +#endif + return (retval); +} + +/* + * Catch an interrupt from the adapter + */ +static __inline void +ahc_intr(struct ahc_softc *ahc) +{ + u_int intstat; + u_int queuestat; + + /* + * Instead of directly reading the interrupt status register, + * infer the cause of the interrupt by checking our in-core + * completion queues. This avoids a costly PCI bus read in + * most cases. + */ + intstat = 0; + if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0) + intstat = CMDCMPLT; + + if ((intstat & INT_PEND) == 0 + || (ahc->flags & AHC_ALL_INTERRUPTS) != 0) { + + intstat = ahc_inb(ahc, INTSTAT); +#if AHC_PCI_CONFIG > 0 + if (ahc->unsolicited_ints > 500 + && (ahc->chip & AHC_PCI) != 0 + && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0) + ahc_pci_intr(ahc); +#endif + } + + if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) + /* Hot eject */ + return; + + if ((intstat & INT_PEND) == 0) { + ahc->unsolicited_ints++; + return; + } + ahc->unsolicited_ints = 0; + + if (intstat & CMDCMPLT) { + ahc_outb(ahc, CLRINT, CLRCMDINT); + + /* + * Ensure that the chip sees that we've cleared + * this interrupt before we walk the output fifo. + * Otherwise, we may, due to posted bus writes, + * clear the interrupt after we finish the scan, + * and after the sequencer has added new entries + * and asserted the interrupt again. + */ + ahc_flush_device_writes(ahc); +#ifdef AHC_TARGET_MODE + if ((queuestat & AHC_RUN_QOUTFIFO) != 0) +#endif + ahc_run_qoutfifo(ahc); +#ifdef AHC_TARGET_MODE + if ((queuestat & AHC_RUN_TQINFIFO) != 0) + ahc_run_tqinfifo(ahc, /*paused*/FALSE); +#endif + } + if (intstat & BRKADRINT) { + ahc_handle_brkadrint(ahc); + /* Fatal error, no more interrupts to handle. */ + return; + } + + if ((intstat & (SEQINT|SCSIINT)) != 0) + ahc_pause_bug_fix(ahc); + + if ((intstat & SEQINT) != 0) + ahc_handle_seqint(ahc, intstat); + + if ((intstat & SCSIINT) != 0) + ahc_handle_scsiint(ahc, intstat); +} + +#endif /* _AIC7XXX_INLINE_H_ */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,2650 @@ +/* + * Adaptec AIC7xxx device driver for Linux. + * + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#54 $ + * + * Copyright (c) 1994 John Aycock + * The University of Calgary Department of Computer Science. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F + * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA + * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide, + * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux, + * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file + * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual, + * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the + * ANSI SCSI-2 specification (draft 10c), ... + * + * -------------------------------------------------------------------------- + * + * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org): + * + * Substantially modified to include support for wide and twin bus + * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, + * SCB paging, and other rework of the code. + * + * -------------------------------------------------------------------------- + * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. Gibbs. + * Copyright (c) 2000 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *--------------------------------------------------------------------------- + * + * Thanks also go to (in alphabetical order) the following: + * + * Rory Bolt - Sequencer bug fixes + * Jay Estabrook - Initial DEC Alpha support + * Doug Ledford - Much needed abort/reset bug fixes + * Kai Makisara - DMAing of SCBs + * + * A Boot time option was also added for not resetting the scsi bus. + * + * Form: aic7xxx=extended + * aic7xxx=no_reset + * aic7xxx=ultra + * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level + * aic7xxx=verbose + * + * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97 + * + * Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp + */ + +/* + * Further driver modifications made by Doug Ledford + * + * Copyright (c) 1997-1999 Doug Ledford + * + * These changes are released under the same licensing terms as the FreeBSD + * driver written by Justin Gibbs. Please see his Copyright notice above + * for the exact terms and conditions covering my changes as well as the + * warranty statement. + * + * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include + * but are not limited to: + * + * 1: Import of the latest FreeBSD sequencer code for this driver + * 2: Modification of kernel code to accomodate different sequencer semantics + * 3: Extensive changes throughout kernel portion of driver to improve + * abort/reset processing and error hanndling + * 4: Other work contributed by various people on the Internet + * 5: Changes to printk information and verbosity selection code + * 6: General reliability related changes, especially in IRQ management + * 7: Modifications to the default probe/attach order for supported cards + * 8: SMP friendliness has been improved + * + */ + +/* + * The next three defines are user configurable. These should be the only + * defines a user might need to get in here and change. There are other + * defines buried deeper in the code, but those really shouldn't need touched + * under normal conditions. + */ + +#if defined(MODULE) || defined(PCMCIA) +#include +#endif + +#if defined(PCMCIA) +#undef MODULE +#endif + +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +#include /* __setup */ +#endif + +#include "../sd.h" /* For geometry detection */ + +/* + * To generate the correct addresses for the controller to issue + * on the bus. Originally added for DEC Alpha support. + */ +#define VIRT_TO_BUS(a) (uint32_t)virt_to_bus((void *)(a)) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +struct proc_dir_entry proc_scsi_aic7xxx = { + PROC_SCSI_AIC7XXX, 7, "aic7xxx", + S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; +#endif + +/* + * Set this to the delay in seconds after SCSI bus reset. + * Note, we honor this only for the initial bus reset. + * The scsi error recovery code performs its own bus settle + * delay handling for error recovery actions. + */ +#ifdef CONFIG_AIC7XXX_RESET_DELAY +#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY +#else +#define AIC7XXX_RESET_DELAY 5000 +#endif + +/* + * Control collection of SCSI transfer statistics for the /proc filesystem. + * + * NOTE: Do NOT enable this when running on kernels version 1.2.x and below. + * NOTE: This does affect performance since it has to maintain statistics. + */ +#ifdef CONFIG_AIC7XXX_PROC_STATS +#define AIC7XXX_PROC_STATS +#endif + +/* + * To change the default number of tagged transactions allowed per-device, + * add a line to the lilo.conf file like: + * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}" + * which will result in the first four devices on the first two + * controllers being set to a tagged queue depth of 32. + * + * The tag_commands is an array of 16 to allow for wide and twin adapters. + * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15 + * for channel 1. + */ +typedef struct { + uint8_t tag_commands[16]; /* Allow for wide/twin adapters. */ +} adapter_tag_info_t; + +/* + * Modify this as you see fit for your system. + * + * 0 tagged queuing disabled + * 1 <= n <= 253 n == max tags ever dispatched. + * + * The driver will throttle the number of commands dispatched to a + * device if it returns queue full. For devices with a fixed maximum + * queue depth, the driver will eventually determine this depth and + * lock it in (a console message is printed to indicate that a lock + * has occurred). On some devices, queue full is returned for a temporary + * resource shortage. These devices will return queue full at varying + * depths. The driver will throttle back when the queue fulls occur and + * attempt to slowly increase the depth over time as the device recovers + * from the resource shortage. + * + * In this example, the first line will disable tagged queueing for all + * the devices on the first probed aic7xxx adapter. + * + * The second line enables tagged queueing with 4 commands/LUN for IDs + * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the + * driver to attempt to use up to 64 tags for ID 1. + * + * The third line is the same as the first line. + * + * The fourth line disables tagged queueing for devices 0 and 3. It + * enables tagged queueing for the other IDs, with 16 commands/LUN + * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for + * IDs 2, 5-7, and 9-15. + */ + +/* + * NOTE: The below structure is for reference only, the actual structure + * to modify in order to change things is just below this comment block. +adapter_tag_info_t aic7xxx_tag_info[] = +{ + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}}, + {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, + {{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} +}; +*/ + +#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE +#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE +#else +#define AIC7XXX_CMDS_PER_DEVICE AHC_MAX_QUEUE +#endif + +#define AIC7XXX_CONFIGED_TAG_COMMANDS { \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ + AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE \ +} + +/* + * By default, use the number of commands specified by + * the users kernel configuration. + */ +static adapter_tag_info_t aic7xxx_tag_info[] = +{ + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS}, + {AIC7XXX_CONFIGED_TAG_COMMANDS} +}; + +/* + * There should be a specific return value for this in scsi.h, but + * it seems that most drivers ignore it. + */ +#define DID_UNDERFLOW DID_ERROR + +void +ahc_print_path(struct ahc_softc *ahc, struct scb *scb) +{ + printk("(scsi%d:%c:%d:%d): ", + ahc->platform_data->host->host_no, + scb != NULL ? SCB_GET_CHANNEL(ahc, scb) : 'X', + scb != NULL ? SCB_GET_TARGET(ahc, scb) : -1, + scb != NULL ? SCB_GET_LUN(scb) : -1); +} + +/* + * XXX - these options apply unilaterally to _all_ 274x/284x/294x + * cards in the system. This should be fixed. Exceptions to this + * rule are noted in the comments. + */ + +/* + * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This + * has no effect on any later resets that might occur due to things like + * SCSI bus timeouts. + */ +static uint32_t aic7xxx_no_reset; + +/* + * Certain PCI motherboards will scan PCI devices from highest to lowest, + * others scan from lowest to highest, and they tend to do all kinds of + * strange things when they come into contact with PCI bridge chips. The + * net result of all this is that the PCI card that is actually used to boot + * the machine is very hard to detect. Most motherboards go from lowest + * PCI slot number to highest, and the first SCSI controller found is the + * one you boot from. The only exceptions to this are when a controller + * has its BIOS disabled. So, we by default sort all of our SCSI controllers + * from lowest PCI slot number to highest PCI slot number. We also force + * all controllers with their BIOS disabled to the end of the list. This + * works on *almost* all computers. Where it doesn't work, we have this + * option. Setting this option to non-0 will reverse the order of the sort + * to highest first, then lowest, but will still leave cards with their BIOS + * disabled at the very end. That should fix everyone up unless there are + * really strange cirumstances. + */ +static int aic7xxx_reverse_scan = 0; + +/* + * Should we force EXTENDED translation on a controller. + * 0 == Use whatever is in the SEEPROM or default to off + * 1 == Use whatever is in the SEEPROM or default to on + */ +static uint32_t aic7xxx_extended = 0; + +/* + * The IRQ trigger method used on EISA controllers. Does not effect PCI cards. + * -1 = Use detected settings. + * 0 = Force Edge triggered mode. + * 1 = Force Level triggered mode. + */ +static int aic7xxx_irq_trigger = -1; + +/* + * This variable is used to override the termination settings on a controller. + * This should not be used under normal conditions. However, in the case + * that a controller does not have a readable SEEPROM (so that we can't + * read the SEEPROM settings directly) and that a controller has a buggered + * version of the cable detection logic, this can be used to force the + * correct termination. It is preferable to use the manual termination + * settings in the BIOS if possible, but some motherboard controllers store + * those settings in a format we can't read. In other cases, auto term + * should also work, but the chipset was put together with no auto term + * logic (common on motherboard controllers). In those cases, we have + * 32 bits here to work with. That's good for 8 controllers/channels. The + * bits are organized as 4 bits per channel, with scsi0 getting the lowest + * 4 bits in the int. A 1 in a bit position indicates the termination setting + * that corresponds to that bit should be enabled, a 0 is disabled. + * It looks something like this: + * + * 0x0f = 1111-Single Ended Low Byte Termination on/off + * ||\-Single Ended High Byte Termination on/off + * |\-LVD Low Byte Termination on/off + * \-LVD High Byte Termination on/off + * + * For non-Ultra2 controllers, the upper 2 bits are not important. So, to + * enable both high byte and low byte termination on scsi0, I would need to + * make sure that the override_term variable was set to 0x03 (bits 0011). + * To make sure that all termination is enabled on an Ultra2 controller at + * scsi2 and only high byte termination on scsi1 and high and low byte + * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011) + * + * For the most part, users should never have to use this, that's why I + * left it fairly cryptic instead of easy to understand. If you need it, + * most likely someone will be telling you what your's needs to be set to. + */ +static int aic7xxx_override_term = -1; + +/* + * Certain motherboard chipset controllers tend to screw + * up the polarity of the term enable output pin. Use this variable + * to force the correct polarity for your system. This is a bitfield variable + * similar to the previous one, but this one has one bit per channel instead + * of four. + * 0 = Force the setting to active low. + * 1 = Force setting to active high. + * Most Adaptec cards are active high, several motherboards are active low. + * To force a 2940 card at SCSI 0 to active high and a motherboard 7895 + * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3 + * to active high, you would need to set stpwlev=0x9 (bits 1001). + * + * People shouldn't need to use this, but if you are experiencing lots of + * SCSI timeout problems, this may help. There is one sure way to test what + * this option needs to be. Using a boot floppy to boot the system, configure + * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and + * if needed then also pass a value to override_term to make sure that the + * driver is enabling SCSI termination, then set this variable to either 0 + * or 1. When the driver boots, make sure there are *NO* SCSI cables + * connected to your controller. If it finds and inits the controller + * without problem, then the setting you passed to stpwlev was correct. If + * the driver goes into a reset loop and hangs the system, then you need the + * other setting for this variable. If neither setting lets the machine + * boot then you have definite termination problems that may not be fixable. + */ +static int aic7xxx_stpwlev = -1; + +/* + * Set this to non-0 in order to force the driver to panic the kernel + * and print out debugging info on a SCSI abort or reset cycle. + */ +static int aic7xxx_panic_on_abort = 0; + +/* + * PCI bus parity checking of the Adaptec controllers. This is somewhat + * dubious at best. To my knowledge, this option has never actually + * solved a PCI parity problem, but on certain machines with broken PCI + * chipset configurations, it can generate tons of false error messages. + * It's included in the driver for completeness. + * 0 = Shut off PCI parity check + * -1 = Normal polarity pci parity checking + * 1 = reverse polarity pci parity checking + * + * NOTE: you can't actually pass -1 on the lilo prompt. So, to set this + * variable to -1 you would actually want to simply pass the variable + * name without a number. That will invert the 0 which will result in + * -1. + */ +static int aic7xxx_pci_parity = 0; + +/* + * Set this to a non-0 value to make us dump out the 32 bit instruction + * registers on the card after completing the sequencer download. This + * allows the actual sequencer download to be verified. It is possible + * to use this option and still boot up and run your system. This is + * only intended for debugging purposes. + */ +static int aic7xxx_dump_sequencer = 0; + +/* + * Certain newer motherboards have put new PCI based devices into the + * IO spaces that used to typically be occupied by VLB or EISA cards. + * This overlap can cause these newer motherboards to lock up when scanned + * for older EISA and VLB devices. Setting this option to non-0 will + * cause the driver to skip scanning for any VLB or EISA controllers and + * only support the PCI controllers. NOTE: this means that if the kernel + * os compiled with PCI support disabled, then setting this to non-0 + * would result in never finding any devices :) + */ +int aic7xxx_no_probe; + +/* + * aic7xxx_detect() has been run, so register all device arrivals + * immediately with the system rather than deferring to the sorted + * attachment performed by aic7xxx_detect(). + */ +int aic7xxx_detect_complete; + +/* + * So that we can set how long each device is given as a selection timeout. + * The table of values goes like this: + * 0 - 256ms + * 1 - 128ms + * 2 - 64ms + * 3 - 32ms + * We default to 256ms because some older devices need a longer time + * to respond to initial selection. + */ +static int aic7xxx_seltime = 0x00; + +/* + * So that insmod can find the variable and make it point to something + */ +#ifdef MODULE +static char *aic7xxx = NULL; + +MODULE_PARM(aic7xxx, "s"); + +/* + * Just in case someone uses commas to separate items on the insmod + * command line, we define a dummy buffer here to avoid having insmod + * write wild stuff into our code segment + */ +static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n"; + +#endif + +static void ahc_handle_scsi_status(struct ahc_softc *, + struct ahc_linux_device *, struct scb *); +static void ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); +static void ahc_sem_timeout(u_long arg); +static void ahc_release_sim_queue(u_long arg); +static int aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); +static void aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc); +static void aic7xxx_select_queue_depth(struct Scsi_Host *host, + Scsi_Device *scsi_devs); +static void aic7xxx_device_queue_depth(struct ahc_softc *ahc, + Scsi_Device *device); +static struct ahc_linux_target* ahc_alloc_target(struct ahc_softc *, + u_int, u_int); +static void ahc_free_target(struct ahc_softc *ahc, + struct ahc_linux_target *targ); +static struct ahc_linux_device* ahc_alloc_device(struct ahc_softc *, + struct ahc_linux_target *, + u_int); +static void ahc_free_device(struct ahc_softc *ahc, + struct ahc_linux_device *dev); +static void ahc_run_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev); +static void ahc_setup_tag_info(char *p, char *end); +static int ahc_next_unit(void); + +static __inline struct ahc_linux_device* + ahc_get_device(struct ahc_softc *ahc, u_int channel, + u_int target, u_int lun, int /*alloc*/); +static __inline void ahc_queue_cmd_complete(struct ahc_softc *ahc, + Scsi_Cmnd *cmd); +static __inline void ahc_run_complete_queue(struct ahc_softc *ahc, + struct ahc_cmd *acmd); +static __inline void ahc_check_device_queue(struct ahc_softc *ahc, + struct ahc_linux_device *dev); +static __inline void ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd); +static __inline void ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb); + +static __inline struct ahc_linux_device* +ahc_get_device(struct ahc_softc *ahc, u_int channel, u_int target, + u_int lun, int alloc) +{ + struct ahc_linux_target *targ; + struct ahc_linux_device *dev; + u_int target_offset; + + target_offset = target; + if (channel != 0) + target_offset += 8; + targ = ahc->platform_data->targets[target_offset]; + if (targ == NULL) { + if (alloc != 0) { + targ = ahc_alloc_target(ahc, channel, target); + if (targ == NULL) + return (NULL); + } else + return (NULL); + } + dev = targ->devices[lun]; + if (dev == NULL && alloc != 0) + dev = ahc_alloc_device(ahc, targ, lun); + return (dev); +} + +static __inline void +ahc_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +{ + /* + * Typically, the complete queue has very few entries + * queued to it before the queue is emptied by + * ahc_run_complete_queue, so sorting the entries + * by generation number should be inexpensive. + * We perform the sort so that commands that complete + * with an error are retuned in the order origionally + * queued to the controller so that any subsequent retries + * are performed in order. The underlying ahc routines do + * not guarantee the order that aborted commands will be + * returned to us. + */ + struct ahc_completeq *completeq; + struct ahc_cmd *list_cmd; + struct ahc_cmd *acmd; + + /* + * If we want the request requeued, make sure there + * are sufficent retries. In the old scsi error code, + * we used to be able to specify a result code that + * bypassed the retry count. Now we must use this + * hack. + */ + if (cmd->result == (CAM_REQUEUE_REQ << 16)) + cmd->retries--; + completeq = &ahc->platform_data->completeq; + list_cmd = TAILQ_FIRST(completeq); + acmd = (struct ahc_cmd *)cmd; + while (list_cmd != NULL + && acmd_scsi_cmd(list_cmd).serial_number + < acmd_scsi_cmd(acmd).serial_number) + list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe); + if (list_cmd != NULL) + TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe); + else + TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe); +} + +static __inline void +ahc_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) +{ + u_long done_flags; + + ahc_done_lock(ahc, &done_flags); + while (acmd != NULL) { + Scsi_Cmnd *cmd; + + cmd = &acmd_scsi_cmd(acmd); + acmd = TAILQ_NEXT(acmd, acmd_links.tqe); + cmd->host_scribble = NULL; + cmd->scsi_done(cmd); + } + ahc_done_unlock(ahc, &done_flags); +} + +static __inline void +ahc_check_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +{ + if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 + && dev->active == 0) { + dev->flags &= ~AHC_DEV_FREEZE_TIL_EMPTY; + dev->qfrozen--; + } + + if (TAILQ_FIRST(&dev->busyq) == NULL + || dev->openings == 0 || dev->qfrozen != 0) + return; + + ahc_run_device_queue(ahc, dev); +} + +static __inline void +ahc_run_device_queues(struct ahc_softc *ahc) +{ + struct ahc_linux_device *dev; + + while ((ahc->flags & AHC_RESOURCE_SHORTAGE) == 0 + && ahc->platform_data->qfrozen == 0 + && (dev = LIST_FIRST(&ahc->platform_data->device_runq)) != NULL) { + LIST_REMOVE(dev, links); + dev->flags &= ~AHC_DEV_ON_RUN_LIST; + ahc_check_device_queue(ahc, dev); + } +} + +static __inline void +ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +{ + /* + * Determine whether we care to filter + * information out of this command. If so, + * pass it on to ahc_filter_command() for more + * heavy weight processing. + */ + if (cmd->cmnd[0] == INQUIRY) + ahc_filter_command(ahc, cmd); +} + +static __inline void +ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb) +{ + Scsi_Cmnd *cmd; + + cmd = scb->io_ctx; + if (cmd->use_sg != 0) { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } else if (cmd->request_bufflen != 0) + pci_unmap_single(ahc->dev_softc, + ahc_le32toh(scb->sg_list[0].addr), + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); +} + +/******************************** Macros **************************************/ +#define BUILD_SCSIID(ahc, cmd) \ + ((((cmd)->target << TID_SHIFT) & TID) \ + | (((cmd)->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \ + | (((cmd)->channel == 0) ? 0 : TWIN_CHNLB)) + +/******************************** Bus DMA *************************************/ +int +ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, + bus_size_t alignment, bus_size_t boundary, + bus_addr_t lowaddr, bus_addr_t highaddr, + bus_dma_filter_t *filter, void *filterarg, + bus_size_t maxsize, int nsegments, + bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) +{ + bus_dma_tag_t dmat; + + dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); + if (dmat == NULL) + return (ENOMEM); + + /* + * Linux is very simplistic about DMA memory. For now don't + * maintain all specification information. Once Linux supplies + * better facilities for doing these operations, or the + * needs of this particular driver change, we might need to do + * more here. + */ + dmat->alignment = alignment; + dmat->boundary = boundary; + dmat->maxsize = maxsize; + *ret_tag = dmat; + return (0); +} + +void +ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat) +{ + free(dmat, M_DEVBUF); +} + +int +ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr, + int flags, bus_dmamap_t *mapp) +{ + bus_dmamap_t map; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); + if (map == NULL) + return (ENOMEM); + *vaddr = pci_alloc_consistent(ahc->dev_softc, + dmat->maxsize, &map->bus_addr); +#else + /* + * At least in 2.2.14, malloc is a slab allocator so all + * allocations are aligned. We assume, for these kernel versions + * that all allocations will be bellow 4Gig, physically contiguous, + * and accessable via DMA by the controller. + */ + map = NULL; /* No additional information to store */ + *vaddr = malloc(dmat->maxsize, M_DEVBUF, M_NOWAIT); +#endif + if (*vaddr == NULL) + return (ENOMEM); + *mapp = map; + return(0); +} + +void +ahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat, + void* vaddr, bus_dmamap_t map) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + pci_free_consistent(ahc->dev_softc, dmat->maxsize, + vaddr, map->bus_addr); +#else + free(vaddr, M_DEVBUF); +#endif +} + +int +ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map, + void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, + void *cb_arg, int flags) +{ + /* + * Assume for now that this will only be used during + * initialization and not for per-transaction buffer mapping. + */ + bus_dma_segment_t stack_sg; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + stack_sg.ds_addr = map->bus_addr; +#else + stack_sg.ds_addr = VIRT_TO_BUS(buf); +#endif + stack_sg.ds_len = dmat->maxsize; + cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); + return (0); +} + +void +ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) +{ + /* + * The map may is NULL in our < 2.3.X implementation. + */ + if (map != NULL) + free(map, M_DEVBUF); +} + +int +ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) +{ + /* Nothing to do */ + return (0); +} + +/********************* Platform Dependent Functions ***************************/ +int +ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) +{ + int value; + int rvalue; + int lvalue; + + /* + * Under Linux, cards are ordered as follows: + * 1) VLB/EISA BIOS enabled devices sorted by BIOS address. + * 2) PCI devices with BIOS enabled sorted by bus/slot/func. + * 3) All remaining VLB/EISA devices sorted by ioport. + * 4) All remaining PCI devices sorted by bus/slot/func. + */ + value = (lahc->flags & AHC_BIOS_ENABLED) + - (rahc->flags & AHC_BIOS_ENABLED); + if (value != 0) + /* Controllers with BIOS enabled have a *higher* priority */ + return (-value); + + /* + * Same BIOS setting, now sort based on bus type. + * EISA and VL controllers sort together. EISA/VL + * have higher priority than PCI. + */ + rvalue = (rahc->chip & AHC_BUS_MASK); + if (rvalue == AHC_VL) + rvalue = AHC_EISA; + lvalue = (lahc->chip & AHC_BUS_MASK); + if (lvalue == AHC_VL) + lvalue = AHC_EISA; + value = lvalue - rvalue; + if (value != 0) + return (value); + + /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ + switch (rvalue) { + case AHC_PCI: + value = ahc_get_pci_bus(lahc->dev_softc) + - ahc_get_pci_bus(rahc->dev_softc); + if (value != 0) + break; + value = ahc_get_pci_slot(lahc->dev_softc) + - ahc_get_pci_slot(rahc->dev_softc); + if (value != 0) + break; + value = ahc_get_pci_function(lahc->dev_softc) + - ahc_get_pci_function(rahc->dev_softc); + /* + * On multi-function devices, the user can choose + * to have function 1 probed before function 0. + * Function 0 is the only one that will have + * CHANNEL_B_PRIMARY set. + */ + if (value < 0 + && (lahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) + /* Swap the two */ + value = -value; + break; + case AHC_EISA: + if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { + value = lahc->platform_data->bios_address + - rahc->platform_data->bios_address; + } else { + value = lahc->bsh.ioport + - rahc->bsh.ioport; + } + break; + default: + panic("ahc_softc_sort: invalid bus type"); + } + return (value); +} + +static void +ahc_setup_tag_info(char *p, char *end) +{ + char *base; + char *tok; + char *tok_end; + char *tok_end2; + int i; + int instance; + int device; + int done; + char tok_list[] = {'.', ',', '{', '}', '\0'}; + + if (*p != ':') + return; + + instance = -1; + device = -1; + done = FALSE; + base = p; + /* Forward us just past the ':' */ + tok = base + 1; + tok_end = strchr(tok, '\0'); + if (tok_end < end) + *tok_end = ','; + while (!done) { + switch (*tok) { + case '{': + if (instance == -1) + instance = 0; + else if (device == -1) + device = 0; + tok++; + break; + case '}': + if (device != -1) + device = -1; + else if (instance != -1) + instance = -1; + tok++; + break; + case ',': + case '.': + if (instance == -1) + done = TRUE; + else if (device >= 0) + device++; + else if (instance >= 0) + instance++; + if ((device >= AHC_NUM_TARGETS) || + (instance >= NUM_ELEMENTS(aic7xxx_tag_info))) + done = TRUE; + tok++; + if (!done) { + base = tok; + } + break; + case '\0': + done = TRUE; + break; + default: + done = TRUE; + tok_end = strchr(tok, '\0'); + for (i = 0; tok_list[i]; i++) { + tok_end2 = strchr(tok, tok_list[i]); + if ((tok_end2) && (tok_end2 < tok_end)) { + tok_end = tok_end2; + done = FALSE; + } + } + if ((instance >= 0) && (device >= 0) && + (instance < NUM_ELEMENTS(aic7xxx_tag_info)) && + (device < AHC_NUM_TARGETS)) + aic7xxx_tag_info[instance].tag_commands[device] = + simple_strtoul(tok, NULL, 0) & 0xff; + tok = tok_end; + break; + } + } + while ((p != base) && (p != NULL)) + p = strtok(NULL, ",."); +} + +/* + * Handle Linux boot parameters. This routine allows for assigning a value + * to a parameter with a ':' between the parameter and the value. + * ie. aic7xxx=unpause:0x0A,extended + */ +int +aic7xxx_setup(char *s) +{ + int i, n; + char *p; + char *end; + + static struct { + const char *name; + uint32_t *flag; + } options[] = { + { "extended", &aic7xxx_extended }, + { "no_reset", &aic7xxx_no_reset }, + { "irq_trigger", &aic7xxx_irq_trigger }, + { "verbose", &aic7xxx_verbose }, + { "reverse_scan", &aic7xxx_reverse_scan }, + { "override_term", &aic7xxx_override_term }, + { "stpwlev", &aic7xxx_stpwlev }, + { "no_probe", &aic7xxx_no_probe }, + { "panic_on_abort", &aic7xxx_panic_on_abort }, + { "pci_parity", &aic7xxx_pci_parity }, + { "dump_sequencer", &aic7xxx_dump_sequencer }, + { "seltime", &aic7xxx_seltime }, + { "tag_info", NULL } + }; + + end = strchr(s, '\0'); + + for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) { + for (i = 0; i < NUM_ELEMENTS(options); i++) { + n = strlen(options[i].name); + + if (strncmp(options[i].name, p, n) != 0) + continue; + + if (strncmp(p, "tag_info", n) == 0) { + ahc_setup_tag_info(p + n, end); + } else if (p[n] == ':') { + *(options[i].flag) = + simple_strtoul(p + n + 1, NULL, 0); + } else if (!strncmp(p, "verbose", n)) { + *(options[i].flag) = 1; + } else { + *(options[i].flag) = ~(*(options[i].flag)); + } + } + } + return 1; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) +__setup("aic7xxx=", aic7xxx_setup); +#endif + +int aic7xxx_verbose; + +/* + * Try to detect an Adaptec 7XXX controller. + */ +int +aic7xxx_detect(Scsi_Host_Template *template) +{ + struct ahc_softc *ahc; + int found; + + /* + * Sanity checking of Linux SCSI data structures so + * that some of our hacks^H^H^H^H^Hassumptions aren't + * violated. + */ + if (offsetof(struct ahc_cmd_internal, end) + > offsetof(struct scsi_cmnd, host_scribble)) { + printf("aic7xxx_detect: SCSI data structures changed.\n"); + printf("aic7xxx_detect: Unable to attach\n"); + return (0); + } +#ifdef MODULE + /* + * If we've been passed any parameters, process them now. + */ + if (aic7xxx) + aic7xxx_setup(aic7xxx); + if (dummy_buffer[0] != 'P') + printk(KERN_WARNING +"aic7xxx: Please read the file /usr/src/linux/drivers/scsi/README.aic7xxx\n" +"aic7xxx: to see the proper way to specify options to the aic7xxx module\n" +"aic7xxx: Specifically, don't use any commas when passing arguments to\n" +"aic7xxx: insmod or else it might trash certain memory areas.\n"); +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) + template->proc_name = "aic7xxx"; +#else + template->proc_dir = &proc_scsi_aic7xxx; +#endif + template->sg_tablesize = AHC_NSEG; + +#ifdef CONFIG_PCI + ahc_linux_pci_probe(template); +#endif + + aic7770_linux_probe(template); + + /* + * Register with the SCSI layer all + * controllers we've found. + */ + found = 0; + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + + if (aic7xxx_register_host(ahc, template) == 0) + found++; + } + aic7xxx_detect_complete++; + return (found); +} + +int +aic7xxx_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) +{ + char buf[80]; + struct Scsi_Host *host; + char *new_name; + u_long s; + + + template->name = ahc->description; + host = scsi_register(template, sizeof(struct ahc_softc *)); + if (host == NULL) + return (ENOMEM); + + ahc_lock(ahc, &s); + *((struct ahc_softc **)host->hostdata) = ahc; + ahc->platform_data->host = host; + host->can_queue = AHC_MAX_QUEUE; + host->cmd_per_lun = 2; + host->sg_tablesize = AHC_NSEG; + host->select_queue_depths = aic7xxx_select_queue_depth; + host->this_id = ahc->our_id; + host->irq = ahc->platform_data->irq; + host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; + host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; + ahc_set_unit(ahc, ahc_next_unit()); + sprintf(buf, "scsi%d", host->host_no); + new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (new_name != NULL) { + strcpy(new_name, buf); + ahc_set_name(ahc, new_name); + } + host->unique_id = ahc->unit; + aic7xxx_initialize_scsi_bus(ahc); + ahc_unlock(ahc, &s); + return (0); +} + +/* + * Find the smallest available unit number to use + * for a new device. We don't just use a static + * count to handle the "repeated hot-(un)plug" + * scenario. + */ +static int +ahc_next_unit() +{ + struct ahc_softc *ahc; + int unit; + + unit = 0; +retry: + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + if (ahc->unit == unit) { + unit++; + goto retry; + } + } + return (unit); +} + +/* + * Place the SCSI bus into a known state by either resetting it, + * or forcing transfer negotiations on the next command to any + * target. + */ +void +aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc) +{ + int i; + int numtarg; + + i = 0; + numtarg = 0; + + if (aic7xxx_no_reset != 0) + ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B); + + if ((ahc->flags & AHC_RESET_BUS_A) != 0) + ahc_reset_channel(ahc, 'A', /*initiate_reset*/TRUE); + else + numtarg = (ahc->features & AHC_WIDE) ? 16 : 8; + + if ((ahc->features & AHC_TWIN) != 0) { + + if ((ahc->flags & AHC_RESET_BUS_B) != 0) { + ahc_reset_channel(ahc, 'B', /*initiate_reset*/TRUE); + } else { + if (numtarg == 0) + i = 8; + numtarg += 8; + } + } + + for (; i < numtarg; i++) { + struct ahc_devinfo devinfo; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + u_int our_id; + u_int target_id; + char channel; + + channel = 'A'; + our_id = ahc->our_id; + target_id = i; + if (i > 7 && (ahc->features & AHC_TWIN) != 0) { + channel = 'B'; + our_id = ahc->our_id_b; + target_id = i % 8; + } + tinfo = ahc_fetch_transinfo(ahc, channel, our_id, + target_id, &tstate); + tinfo->goal = tinfo->user; + ahc_compile_devinfo(&devinfo, our_id, target_id, + CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); + ahc_update_target_msg_request(ahc, &devinfo, tinfo, + /*force*/FALSE, /*paused*/FALSE); + } + /* Give the bus some time to recover */ + if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { + ahc->platform_data->qfrozen++; + init_timer(&ahc->platform_data->reset_timer); + ahc->platform_data->reset_timer.data = (u_long)ahc; + ahc->platform_data->reset_timer.expires = + jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; + ahc->platform_data->reset_timer.function = + ahc_release_sim_queue; + add_timer(&ahc->platform_data->reset_timer); + } +} + +int +ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) +{ + ahc->platform_data = + malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT); + if (ahc->platform_data == NULL) + return (ENOMEM); + memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); + TAILQ_INIT(&ahc->platform_data->completeq); + LIST_INIT(&ahc->platform_data->device_runq); + ahc_lockinit(ahc); + ahc_done_lockinit(ahc); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + init_MUTEX_LOCKED(&ahc->platform_data->eh_sem); +#else + ahc->platform_data->eh_sem = MUTEX_LOCKED; +#endif + ahc->seltime = (aic7xxx_seltime & 0x3) << 4; + ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; + return (0); +} + +void +ahc_platform_free(struct ahc_softc *ahc) +{ + if (ahc->platform_data != NULL) { + if (ahc->platform_data->host != NULL) + scsi_unregister(ahc->platform_data->host); + if (ahc->platform_data->irq) + free_irq(ahc->platform_data->irq, ahc); + if (ahc->tag == BUS_SPACE_PIO + && ahc->bsh.ioport != 0) + release_region(ahc->bsh.ioport, 256); + if (ahc->tag == BUS_SPACE_MEMIO + && ahc->bsh.maddr != NULL) { + u_long base_addr; + + base_addr = (u_long)ahc->bsh.maddr; + base_addr &= PAGE_MASK; + iounmap((void *)base_addr); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + release_mem_region(ahc->platform_data->mem_busaddr, + 0x1000); +#endif + } + free(ahc->platform_data, M_DEVBUF); + } +} + +void +ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb) +{ + ahc_platform_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), SCB_LIST_NULL, + ROLE_UNKNOWN, CAM_REQUEUE_REQ); +} + +void +ahc_platform_set_tags(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, int enable) +{ + struct ahc_linux_device *dev; + + dev = ahc_get_device(ahc, devinfo->channel - 'A', + devinfo->target, + devinfo->lun, /*alloc*/FALSE); + if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 + && (dev->active != 0)) { + dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; + dev->qfrozen++; + } + + if (enable) { + /* + * Start out agressively and allow our + * dynamic queue depth algorithm take + * care of the rest. + */ + dev->maxtags = AHC_MAX_QUEUE; + dev->openings = dev->maxtags - dev->active; + } else { + /* We can only have one opening */ + dev->maxtags = 0; + dev->openings = 1 - dev->active; + } +} + +int +ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, + int lun, u_int tag, role_t role, uint32_t status) +{ + int chan; + int maxchan; + int targ; + int maxtarg; + int clun; + int maxlun; + int count; + + if (tag != SCB_LIST_NULL) + return (0); + + chan = 0; + if (channel != ALL_CHANNELS) { + chan = channel - 'A'; + maxchan = chan + 1; + } else { + maxchan = (ahc->features & AHC_TWIN) ? 2 : 1; + } + targ = 0; + if (target != CAM_TARGET_WILDCARD) { + targ = target; + maxtarg = targ + 1; + } else { + maxtarg = (ahc->features & AHC_WIDE) ? 16 : 8; + } + clun = 0; + if (lun != CAM_LUN_WILDCARD) { + clun = lun; + maxlun = clun + 1; + } else { + maxlun = 16; + } + + count = 0; + for (; chan < maxchan; chan++) { + for (; targ < maxtarg; targ++) { + for (; clun < maxlun; clun++) { + struct ahc_linux_device *dev; + struct ahc_busyq *busyq; + struct ahc_cmd *acmd; + + dev = ahc_get_device(ahc, chan, targ, + clun, /*alloc*/FALSE); + + if (dev == NULL) + continue; + + busyq = &dev->busyq; + while ((acmd = TAILQ_FIRST(busyq)) != NULL) { + Scsi_Cmnd *cmd; + + cmd = &acmd_scsi_cmd(acmd); + TAILQ_REMOVE(busyq, acmd, + acmd_links.tqe); + count++; + cmd->result = status << 16; + ahc_queue_cmd_complete(ahc, cmd); + } + } + } + } + + return (count); +} + +/* + * Sets the queue depth for each SCSI device hanging + * off the input host adapter. + */ +static void +aic7xxx_select_queue_depth(struct Scsi_Host * host, + Scsi_Device * scsi_devs) +{ + Scsi_Device *device; + struct ahc_softc *ahc; + u_long flags; + int scbnum; + + ahc = *((struct ahc_softc **)host->hostdata); + ahc_lock(ahc, &flags); + scbnum = 0; + for (device = scsi_devs; device != NULL; device = device->next) { + if (device->host == host) { + aic7xxx_device_queue_depth(ahc, device); + scbnum += device->queue_depth; + } + } + ahc_unlock(ahc, &flags); +} + +/* + * Determines the queue depth for a given device. + */ +static void +aic7xxx_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device) +{ + struct ahc_devinfo devinfo; + struct ahc_initiator_tinfo *targ_info; + struct tmode_tstate *tstate; + uint8_t tags; + + ahc_compile_devinfo(&devinfo, + device->channel == 0 ? ahc->our_id : ahc->our_id_b, + device->id, device->lun, + device->channel == 0 ? 'A' : 'B', + ROLE_INITIATOR); + targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, + devinfo.our_scsiid, + devinfo.target, &tstate); + + tags = 0; + if (device->tagged_supported != 0 + && (tstate->discenable & devinfo.target_mask) != 0) { + if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { + + printf("aic7xxx: WARNING, insufficient " + "tag_info instances for installed " + "controllers. Using defaults\n"); + printf("aic7xxx: Please update the " + "aic7xxx_tag_info array in the " + "aic7xxx.c source file.\n"); + tags = AHC_MAX_QUEUE; + } else { + adapter_tag_info_t *tag_info; + + tag_info = &aic7xxx_tag_info[ahc->unit]; + tags = tag_info->tag_commands[devinfo.target_offset]; + if (tags > AHC_MAX_QUEUE) + tags = AHC_MAX_QUEUE; + } + } + if (tags != 0) { + device->queue_depth = tags; + ahc_set_tags(ahc, &devinfo, TRUE); + printf("scsi%d:%d:%d:%d: Tagged Queuing enabled. Depth %d\n", + ahc->platform_data->host->host_no, device->channel, + device->id, device->lun, tags); + } else { + /* + * We allow the OS to queue 2 untagged transactions to + * us at any time even though we can only execute them + * serially on the controller/device. This should remove + * some latency. + */ + device->queue_depth = 2; + } +} + +/* + * Queue an SCB to the controller. + */ +int +aic7xxx_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +{ + struct ahc_softc *ahc; + struct ahc_linux_device *dev; + u_long flags; + + ahc = *(struct ahc_softc **)cmd->host->hostdata; + + /* + * Save the callback on completion function. + */ + cmd->scsi_done = scsi_done; + + ahc_lock(ahc, &flags); + dev = ahc_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/TRUE); + if (dev == NULL) { + ahc_unlock(ahc, &flags); + printf("aic7xxx_queue: Unable to allocate device!\n"); + return (-ENOMEM); + } + cmd->result = CAM_REQ_INPROG << 16; + TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); + ahc_run_device_queue(ahc, dev); + ahc_unlock(ahc, &flags); + return (0); +} + +static void +ahc_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +{ + struct ahc_cmd *acmd; + struct scsi_cmnd *cmd; + struct scb *scb; + struct hardware_scb *hscb; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + uint16_t mask; + + while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL + && dev->openings > 0 && dev->qfrozen == 0) { + + /* + * Schedule us to run later. The only reason we are not + * running is because the whole controller Q is frozen. + */ + if (ahc->platform_data->qfrozen != 0) { + if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0) + return; + + LIST_INSERT_HEAD(&ahc->platform_data->device_runq, + dev, links); + dev->flags |= AHC_DEV_ON_RUN_LIST; + return; + } + /* + * Get an scb to use. + */ + if ((scb = ahc_get_scb(ahc)) == NULL) { + if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0) + panic("running device on run list"); + LIST_INSERT_HEAD(&ahc->platform_data->device_runq, + dev, links); + dev->flags |= AHC_DEV_ON_RUN_LIST; + ahc->flags |= AHC_RESOURCE_SHORTAGE; + printf("%s: Temporary Resource Shortage\n", + ahc_name(ahc)); + return; + } + TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe); + cmd = &acmd_scsi_cmd(acmd); + scb->io_ctx = cmd; + scb->platform_data->dev = dev; + hscb = scb->hscb; + cmd->host_scribble = (char *)scb; + + /* + * Fill out basics of the HSCB. + */ + hscb->control = 0; + hscb->scsiid = BUILD_SCSIID(ahc, cmd); + hscb->lun = cmd->lun; + mask = SCB_GET_TARGET_MASK(ahc, scb); + tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb), + SCB_GET_OUR_ID(scb), + SCB_GET_TARGET(ahc, scb), &tstate); + hscb->scsirate = tinfo->scsirate; + hscb->scsioffset = tinfo->current.offset; + if ((tstate->ultraenb & mask) != 0) + hscb->control |= ULTRAENB; + + if ((tstate->discenable & mask) != 0) + hscb->control |= DISCENB; + + if ((tstate->tagenable & mask) != 0) { + /* XXX What about devices that dislike ordered tags? */ + if ((dev->num_commands % 256) == 0) + hscb->control |= MSG_ORDERED_Q_TAG; + else + hscb->control |= MSG_SIMPLE_Q_TAG; + } + + hscb->cdb_len = cmd->cmd_len; + if (hscb->cdb_len <= 12) { + memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len); + } else { + memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len); + scb->flags |= SCB_CDB32_PTR; + } + + scb->platform_data->xfer_len = 0; + if (cmd->use_sg != 0) { + struct ahc_dma_seg *sg; + struct scatterlist *cur_seg; + struct scatterlist *end_seg; + int nseg; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg, + scsi_to_pci_dma_dir(cmd ->sc_data_direction)); + end_seg = cur_seg + nseg; + /* Copy the segments into the SG list. */ + sg = scb->sg_list; + while(cur_seg < end_seg) { + sg->addr = ahc_htole32(sg_dma_address(cur_seg)); +/* XXX Add in the 5th byte of the address later.*/ + sg->len = ahc_htole32(sg_dma_len(cur_seg)); + scb->platform_data->xfer_len += + sg_dma_len(cur_seg); + sg++; + cur_seg++; + } + sg--; + sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); + + /* + * Reset the sg list pointer. + */ + scb->hscb->sgptr = + ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + + /* + * Copy the first SG into the "current" + * data pointer area. + */ + scb->hscb->dataptr = scb->sg_list->addr; + scb->hscb->datacnt = scb->sg_list->len; + + /* + * Remember the number of segments for later + * residual calculations. + */ + scb->sg_count = nseg; + } else if (cmd->request_bufflen != 0) { + struct ahc_dma_seg *sg; + uint32_t baddr; + + sg = scb->sg_list; + baddr = pci_map_single(ahc->dev_softc, + cmd->request_buffer, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + sg->addr = ahc_htole32(baddr); + sg->len = ahc_htole32(cmd->request_bufflen + | AHC_DMA_LAST_SEG); + + /* + * Reset the sg list pointer. + */ + scb->hscb->sgptr = + ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + + /* + * Copy the first SG into the "current" + * data pointer area. + */ + scb->hscb->dataptr = sg->addr; + scb->hscb->datacnt = sg->len; + scb->platform_data->xfer_len = cmd->request_bufflen; + + /* + * Remember the number of segments for later + * residual calculations. + */ + scb->sg_count = 1; + } else { + scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL); + scb->hscb->dataptr = 0; + scb->hscb->datacnt = 0; + scb->sg_count = 0; + } + + LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); + dev->openings--; + dev->active++; + dev->num_commands++; + + /* + * We only allow one untagged transaction + * per target in the initiator role unless + * we are storing a full busy target *lun* + * table in SCB space. + */ + if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0 + && (ahc->features & AHC_SCB_BTT) == 0) { + struct scb_tailq *untagged_q; + int target_offset; + + target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); + untagged_q = &(ahc->untagged_queues[target_offset]); + TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); + scb->flags |= SCB_UNTAGGEDQ; + if (TAILQ_FIRST(untagged_q) != scb) + continue; + } + scb->flags |= SCB_ACTIVE; + ahc_queue_scb(ahc, scb); + } +} + +/* + * SCSI controller interrupt handler. + */ +void +aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs) +{ + struct ahc_softc *ahc; + struct ahc_cmd *acmd; + u_long flags; + + ahc = (struct ahc_softc *) dev_id; + ahc_lock(ahc, &flags); + ahc_intr(ahc); + /* + * It would be nice to run the device queues from a + * bottom half handler, but as there is no way to + * dynamically register one, we'll have to postpone + * that until we get integrated into the kernel. + */ + ahc_run_device_queues(ahc); + acmd = TAILQ_FIRST(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->completeq); + ahc_unlock(ahc, &flags); + if (acmd != NULL) + ahc_run_complete_queue(ahc, acmd); +} + +void +ahc_platform_flushwork(struct ahc_softc *ahc) +{ + struct ahc_cmd *acmd; + + acmd = TAILQ_FIRST(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->completeq); + if (acmd != NULL) + ahc_run_complete_queue(ahc, acmd); +} + +static struct ahc_linux_target* +ahc_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) +{ + struct ahc_linux_target *targ; + u_int target_offset; + + targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT); + if (targ == NULL) + return (NULL); + memset(targ, 0, sizeof(*targ)); + targ->channel = channel; + targ->target = target; + target_offset = target; + if (channel != 0) + target_offset += 8; + ahc->platform_data->targets[target_offset] = targ; + return (targ); +} + +static void +ahc_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) +{ + u_int target_offset; + + target_offset = targ->target; + if (targ->channel != 0) + target_offset += 8; + ahc->platform_data->targets[target_offset] = NULL; + free(targ, M_DEVBUF); +} + +static struct ahc_linux_device* +ahc_alloc_device(struct ahc_softc *ahc, + struct ahc_linux_target *targ, u_int lun) +{ + struct ahc_linux_device *dev; + + dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT); + if (dev == NULL) + return (NULL); + memset(dev, 0, sizeof(*dev)); + TAILQ_INIT(&dev->busyq); + dev->flags = AHC_DEV_UNCONFIGURED; + dev->lun = lun; + dev->target = targ; + + /* + * We start out life using untagged + * transactions of which we allow one. + */ + dev->openings = 1; + + /* + * Set maxtags to 0. This will be changed if we + * later determine that we are dealing with + * a tagged queuing capable device. + */ + dev->maxtags = 0; + + targ->refcount++; + targ->devices[lun] = dev; + return (dev); +} + +static void +ahc_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +{ + struct ahc_linux_target *targ; + + targ = dev->target; + targ->devices[dev->lun] = NULL; + free(dev, M_DEVBUF); + targ->refcount--; + if (targ->refcount == 0) + ahc_free_target(ahc, targ); +} + +/* + * Return a string describing the driver. + */ +const char * +aic7xxx_info(struct Scsi_Host *host) +{ + static char buffer[512]; + char ahc_info[256]; + char *bp; + struct ahc_softc *ahc; + + bp = &buffer[0]; + ahc = *(struct ahc_softc **)host->hostdata; + memset(bp, 0, sizeof(buffer)); + strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev "); + strcat(bp, AIC7XXX_DRIVER_VERSION); + strcat(bp, "\n"); + strcat(bp, " <"); + strcat(bp, ahc->description); + strcat(bp, ">\n"); + strcat(bp, " "); + ahc_controller_info(ahc, ahc_info); + strcat(bp, ahc_info); + strcat(bp, "\n"); + + return (bp); +} + +void +ahc_send_async(struct ahc_softc *ahc, char channel, + u_int target, u_int lun, ac_code code) +{ + switch (code) { + case AC_TRANSFER_NEG: + { + char buf[80]; + struct ahc_linux_target *targ; + struct info_str info; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + int target_offset; + + info.buffer = buf; + info.length = sizeof(buf); + info.offset = 0; + info.pos = 0; + tinfo = ahc_fetch_transinfo(ahc, channel, + channel == 'A' ? ahc->our_id + : ahc->our_id_b, + target, &tstate); + + /* + * Don't bother reporting results while + * negotiations are still pending. + */ + if (tinfo->current.period != tinfo->goal.period + || tinfo->current.width != tinfo->goal.width + || tinfo->current.offset != tinfo->goal.offset + || tinfo->current.ppr_options != tinfo->goal.ppr_options) + if (bootverbose == 0) + break; + + /* + * Don't bother reporting results that + * are identical to those last reported. + */ + target_offset = target; + if (channel == 'B') + target_offset += 8; + targ = ahc->platform_data->targets[target_offset]; + if (targ != NULL + && tinfo->current.period == targ->last_tinfo.period + && tinfo->current.width == targ->last_tinfo.width + && tinfo->current.offset == targ->last_tinfo.offset + && tinfo->current.ppr_options == targ->last_tinfo.ppr_options) + if (bootverbose == 0) + break; + + targ->last_tinfo.period = tinfo->current.period; + targ->last_tinfo.width = tinfo->current.width; + targ->last_tinfo.offset = tinfo->current.offset; + targ->last_tinfo.ppr_options = tinfo->current.ppr_options; + + printf("(%s:%c:", ahc_name(ahc), channel); + if (target == CAM_TARGET_WILDCARD) + printf("*): "); + else + printf("%d): ", target); + ahc_format_transinfo(&info, &tinfo->current); + if (info.pos < info.length) + *info.buffer = '\0'; + else + buf[info.length - 1] = '\0'; + printf("%s", buf); + break; + } + case AC_SENT_BDR: + break; + case AC_BUS_RESET: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + scsi_report_bus_reset(ahc->platform_data->host, channel - 'A'); +#endif + break; + default: + panic("ahc_send_async: Unexpected async event"); + } +} + +/* + * Calls the higher level scsi done function and frees the scb. + */ +void +ahc_done(struct ahc_softc *ahc, struct scb * scb) +{ + Scsi_Cmnd *cmd; + struct ahc_linux_device *dev; + + LIST_REMOVE(scb, pending_links); + if ((scb->flags & SCB_UNTAGGEDQ) != 0) { + struct scb_tailq *untagged_q; + int target_offset; + + target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); + untagged_q = &(ahc->untagged_queues[target_offset]); + TAILQ_REMOVE(untagged_q, scb, links.tqe); + ahc_run_untagged_queue(ahc, untagged_q); + } + + if ((scb->flags & SCB_ACTIVE) == 0) { + printf("SCB %d done'd twice\n", scb->hscb->tag); + ahc_dump_card_state(ahc); + panic("Stopping for safety"); + } + cmd = scb->io_ctx; + dev = scb->platform_data->dev; + dev->active--; + dev->openings++; + ahc_unmap_scb(ahc, scb); + if (scb->flags & SCB_SENSE) { + memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), + MIN(sizeof(struct scsi_sense_data), + sizeof(cmd->sense_buffer))); + } + if (ahc_get_transaction_status(scb) == CAM_REQ_INPROG) { + uint32_t amount_xferred; + + amount_xferred = + ahc_get_transfer_length(scb) - ahc_get_residual(scb); + if (amount_xferred < scb->io_ctx->underflow) { + printf("Saw underflow (%ld of %ld bytes). " + "Treated as error\n", + ahc_get_residual(scb), + ahc_get_transfer_length(scb)); + ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + } else { + ahc_set_transaction_status(scb, CAM_REQ_CMP); + ahc_sniff_command(ahc, cmd); + } + } else if (ahc_get_transaction_status(scb) == DID_OK) { + ahc_handle_scsi_status(ahc, dev, scb); + } + + if (dev->openings == 1 + && ahc_get_transaction_status(scb) == CAM_REQ_CMP + && ahc_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) + dev->tag_success_count++; + /* + * Some devices deal with temporary internal resource + * shortages by returning queue full. When the queue + * full occurrs, we throttle back. Slowly try to get + * back to our previous queue depth. + */ + if ((dev->openings + dev->active) < dev->maxtags + && dev->tag_success_count > AHC_TAG_SUCCESS_INTERVAL) { + dev->tag_success_count = 0; + dev->openings++; + } + + if (dev->active == 0 + && (dev->flags & AHC_DEV_UNCONFIGURED) != 0) + ahc_free_device(ahc, dev); + else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + LIST_INSERT_HEAD(&ahc->platform_data->device_runq, dev, links); + dev->flags |= AHC_DEV_ON_RUN_LIST; + } + + if ((scb->flags & SCB_RECOVERY_SCB) != 0) { + printf("Recovery SCB completes\n"); + up(&ahc->platform_data->eh_sem); + } + + ahc_free_scb(ahc, scb); + ahc_queue_cmd_complete(ahc, cmd); +} + +static void +ahc_handle_scsi_status(struct ahc_softc *ahc, + struct ahc_linux_device *dev, struct scb *scb) +{ + /* + * We don't currently trust the mid-layer to + * properly deal with queue full or busy. So, + * when one occurs, we tell the mid-layer to + * unconditionally requeue the command to us + * so that we can retry it ourselves. We also + * implement our own throttling mechanism so + * we don't clobber the device with too many + * commands. + */ + switch (ahc_get_scsi_status(scb)) { + default: + break; + case SCSI_STATUS_QUEUE_FULL: + { + /* + * By the time the core driver has returned this + * command, all other commands that were queued + * to us but not the device have been returned. + * This ensures that dev->active is equal to + * the number of commands actually queued to + * the device. + */ + dev->tag_success_count = 0; + if (dev->active != 0) { + /* + * Drop our opening count to the number + * of commands currently outstanding. + */ + dev->openings = 0; +/* + ahc_print_path(ahc, scb); + printf("Dropping tag count to %d\n", dev->active); + */ + if (dev->active == dev->tags_on_last_queuefull) { + + dev->last_queuefull_same_count++; + /* + * If we repeatedly see a queue full + * at the same queue depth, this + * device has a fixed number of tag + * slots. Lock in this tag depth + * so we stop seeing queue fulls from + * this device. + */ + if (dev->last_queuefull_same_count + == AHC_LOCK_TAGS_COUNT) { + dev->maxtags = dev->active; + ahc_print_path(ahc, scb); + printf("Locking max tag count at %d\n", + dev->active); + } + } else { + dev->tags_on_last_queuefull = dev->active; + dev->last_queuefull_same_count = 0; + } + ahc_set_transaction_status(scb, CAM_REQUEUE_REQ); + ahc_set_scsi_status(scb, SCSI_STATUS_OK); + break; + } + /* + * Drop down to a single opening, and treat this + * as if the target return BUSY SCSI status. + */ + dev->openings = 1; + /* FALLTHROUGH */ + } + case SCSI_STATUS_BUSY: + /* + * XXX Set a timer and handle ourselves???? + * For now we pray that the mid-layer does something + * sane for devices that are busy. + */ + ahc_set_scsi_status(scb, SCSI_STATUS_BUSY); + break; + } +} + +static void +ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd) +{ + switch (cmd->cmnd[0]) { + case INQUIRY: + { + struct ahc_devinfo devinfo; + struct scsi_inquiry_data *sid; + struct ahc_initiator_tinfo *targ_info; + struct tmode_tstate *tstate; + struct ahc_syncrate *syncrate; + u_int scsiid; + u_int maxsync; + int minlen; + u_int width; + u_int period; + u_int offset; + u_int ppr_options; + + if (cmd->use_sg != 0) { + printf("%s: SG Inquiry response ignored\n", + ahc_name(ahc)); + break; + } + sid = (struct scsi_inquiry_data *)cmd->request_buffer; + + /* + * Determine if this lun actually exists. If so, + * hold on to its corresponding device structure. + */ + if (cmd->request_bufflen >= 1 + && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { + struct ahc_linux_device *dev; + + dev = ahc_get_device(ahc, cmd->channel, + cmd->target, cmd->lun, + /*alloc*/FALSE); + dev->flags &= ~AHC_DEV_UNCONFIGURED; + } + + /* + * Update our notion of this device's transfer + * negotiation capabilities. + */ + scsiid = BUILD_SCSIID(ahc, cmd); + ahc_compile_devinfo(&devinfo, SCSIID_OUR_ID(scsiid), + cmd->target, cmd->lun, + SCSIID_CHANNEL(ahc, scsiid), + ROLE_INITIATOR); + targ_info = ahc_fetch_transinfo(ahc, devinfo.channel, + devinfo.our_scsiid, + devinfo.target, &tstate); + /* Structure copy */ + width = targ_info->user.width; + period = targ_info->user.period; + offset = targ_info->user.offset; + ppr_options = targ_info->user.ppr_options; + minlen = offsetof(struct scsi_inquiry_data, version) + 1; + if (cmd->request_bufflen >= minlen) { + targ_info->current.protocol_version = SID_ANSI_REV(sid); + + /* + * Only attempt SPI3 once we've verified that + * the device claims to support SPI3 features. + */ + if (targ_info->current.protocol_version < SCSI_REV_2) + targ_info->current.transport_version = + SID_ANSI_REV(sid); + else + targ_info->current.transport_version = + SCSI_REV_2; + } + + minlen = offsetof(struct scsi_inquiry_data, flags) + 1; + if (cmd->request_bufflen >= minlen + && (sid->additional_length + 4) >= minlen) { + if ((sid->flags & SID_WBus16) == 0) + width = MSG_EXT_WDTR_BUS_8_BIT; + if ((sid->flags & SID_Sync) == 0) { + period = 0; + offset = 0; + ppr_options = 0; + } + } else { + /* Keep current settings */ + break; + } + minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1; + if (cmd->request_bufflen >= minlen + && (sid->additional_length + 4) >= minlen) { + if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0) + ppr_options = 0; + + if ((sid->spi3data & SID_SPI_MASK) != 0 + && targ_info->current.protocol_version > SCSI_REV_2) + targ_info->current.transport_version = 3; + } else { + ppr_options = 0; + } + + ahc_validate_width(ahc, /*tinfo limit*/NULL, &width, + ROLE_UNKNOWN); + if ((ahc->features & AHC_ULTRA2) != 0) + maxsync = AHC_SYNCRATE_DT; + else if ((ahc->features & AHC_ULTRA) != 0) + maxsync = AHC_SYNCRATE_ULTRA; + else + maxsync = AHC_SYNCRATE_FAST; + + syncrate = ahc_find_syncrate(ahc, &period, + &ppr_options, maxsync); + ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate, + &offset, width, ROLE_UNKNOWN); + /* Apply our filtered user settings. */ + ahc_set_width(ahc, &devinfo, width, + AHC_TRANS_GOAL, /*paused*/FALSE); + ahc_set_syncrate(ahc, &devinfo, syncrate, period, + offset, ppr_options, AHC_TRANS_GOAL, + /*paused*/FALSE); + break; + } + default: + panic("ahc_filter_command: Unexpected Command type %x\n", + cmd->cmnd[0]); + break; + } +} + +static void +ahc_sem_timeout(u_long arg) +{ + struct semaphore *sem; + + sem = (struct semaphore *)arg; + up(sem); +} + +static void +ahc_release_sim_queue(u_long arg) +{ + struct ahc_softc *ahc; + u_long s; + + ahc = (struct ahc_softc *)arg; + ahc_lock(ahc, &s); + if (ahc->platform_data->qfrozen > 0) + ahc->platform_data->qfrozen--; + if (ahc->platform_data->qfrozen == 0) + ahc_run_device_queues(ahc); + ahc_unlock(ahc, &s); +} + +static int +aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) +{ + struct ahc_softc *ahc; + struct ahc_cmd *acmd; + struct ahc_cmd *list_acmd; + struct ahc_linux_device *dev; + struct scb *pending_scb; + u_long s; + u_int saved_scbptr; + u_int active_scb_index; + u_int last_phase; + int retval; + int paused; + int wait; + int disconnected; + + paused = FALSE; + wait = FALSE; + ahc = *(struct ahc_softc **)cmd->host->hostdata; + acmd = (struct ahc_cmd *)cmd; + + printf("%s:%d:%d:%d: Attempting to queue a%s message\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun, + flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); + + /* + * It is a bug that the upper layer takes + * this lock just prior to calling us. + */ + spin_unlock_irq(&io_request_lock); + + ahc_lock(ahc, &s); + + /* + * First determine if we currently own this command. + * Start by searching the device queue. If not found + * there, check the pending_scb list. If not found + * at all, and the system wanted us to just abort the + * command return success. + */ + dev = ahc_get_device(ahc, cmd->channel, cmd->target, + cmd->lun, /*alloc*/FALSE); + + if (dev == NULL) { + /* + * No target device for this command exists, + * so we must not still own the command. + */ + printf("%s:%d:%d:%d: Is not an active device\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + retval = SUCCESS; + goto no_cmd; + } + + TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) { + if (list_acmd == acmd) + break; + } + + if (list_acmd != NULL) { + printf("%s:%d:%d:%d: Command found on device queue\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + if (flag == SCB_ABORT) { + TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); + cmd->result = DID_ABORT << 16; + ahc_queue_cmd_complete(ahc, cmd); + retval = SUCCESS; + goto done; + } + } + + /* + * See if we can find a matching cmd in the pending list. + */ + LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { + if (pending_scb->io_ctx == cmd) + break; + } + + if (pending_scb == NULL && flag == SCB_DEVICE_RESET) { + + /* Any SCB for this device will do for a target reset */ + LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { + if (ahc_match_scb(ahc, pending_scb, cmd->target, + cmd->channel, CAM_LUN_WILDCARD, + SCB_LIST_NULL, ROLE_INITIATOR) == 0) + break; + } + } + + if (pending_scb == NULL) { + printf("%s:%d:%d:%d: Command not found\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + goto no_cmd; + } + + if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { + /* + * We can't queue two recovery actions using the same SCB + */ + retval = FAILED; + goto done; + } + + /* + * Ensure that the card doesn't do anything + * behind our back. Also make sure that we + * didn't "just" miss an interrupt that would + * affect this cmd. + */ + ahc->flags |= AHC_ALL_INTERRUPTS; + do { + ahc_intr(ahc); + pause_sequencer(ahc); + ahc_clear_critical_section(ahc); + } while (ahc_inb(ahc, INTSTAT) & INT_PEND); + ahc->flags &= ~AHC_ALL_INTERRUPTS; + paused = TRUE; + + if (bootverbose) + ahc_dump_card_state(ahc); + + if ((pending_scb->flags & SCB_ACTIVE) == 0) { + printf("%s:%d:%d:%d: Command already completed\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + goto no_cmd; + } + + disconnected = TRUE; + if (flag == SCB_ABORT) { + if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', + cmd->lun, pending_scb->hscb->tag, + ROLE_INITIATOR, CAM_REQ_ABORTED, + SEARCH_COMPLETE) > 0) { + printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", + ahc_name(ahc), cmd->channel, cmd->target, + cmd->lun); + retval = SUCCESS; + goto done; + } + } else if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', + cmd->lun, pending_scb->hscb->tag, + ROLE_INITIATOR, /*status*/0, + SEARCH_COUNT) > 0) { + disconnected = FALSE; + } + + /* + * At this point, pending_scb is the scb associated with the + * passed in command. That command is currently active on the + * bus, is in the disconnected state, or we're hoping to find + * a command for the same target active on the bus to abuse to + * send a BDR. Queue the appropriate message based on which of + * these states we are in. + */ + last_phase = ahc_inb(ahc, LASTPHASE); + saved_scbptr = ahc_inb(ahc, SCBPTR); + active_scb_index = ahc_inb(ahc, SCB_TAG); + if (last_phase != P_BUSFREE + && (pending_scb->hscb->tag == active_scb_index + || (flag == SCB_DEVICE_RESET + && SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)) == cmd->target))) { + + /* + * We're active on the bus, so assert ATN + * and hope that the target responds. + */ + pending_scb = ahc_lookup_scb(ahc, active_scb_index); + pending_scb->flags |= SCB_RECOVERY_SCB|flag; + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, last_phase|ATNO); + printf("%s:%d:%d:%d: Device is active, asserting ATN\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + wait = TRUE; + } else if (disconnected) { + + /* + * Actually re-queue this SCB in an attempt + * to select the device before it reconnects. + * In either case (selection or reselection), + * we will now issue a the approprate message + * to the timed-out device. + * + * Set the MK_MESSAGE control bit indicating + * that we desire to send a message. We + * also set the disconnected flag since + * in the paging case there is no guarantee + * that our SCB control byte matches the + * version on the card. We don't want the + * sequencer to abort the command thinking + * an unsolicited reselection occurred. + */ + pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; + pending_scb->flags |= SCB_RECOVERY_SCB|flag; + + /* + * Remove any cached copy of this SCB in the + * disconnected list in preparation for the + * queuing of our abort SCB. We use the + * same element in the SCB, SCB_NEXT, for + * both the qinfifo and the disconnected list. + */ + ahc_search_disc_list(ahc, cmd->target, cmd->channel + 'A', + cmd->lun, pending_scb->hscb->tag, + /*stop_on_first*/TRUE, + /*remove*/TRUE, + /*save_state*/FALSE); + + /* + * In the non-paging case, the sequencer will + * never re-reference the in-core SCB. + * To make sure we are notified during + * reslection, set the MK_MESSAGE flag in + * the card's copy of the SCB. + */ + if ((ahc->flags & AHC_PAGESCBS) == 0) { + ahc_outb(ahc, SCBPTR, pending_scb->hscb->tag); + ahc_outb(ahc, SCB_CONTROL, + ahc_inb(ahc, SCB_CONTROL)|MK_MESSAGE); + } + + /* + * Clear out any entries in the QINFIFO first + * so we are the next SCB for this target + * to run. + */ + ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A', + cmd->lun, SCB_LIST_NULL, ROLE_INITIATOR, + CAM_REQUEUE_REQ, SEARCH_COMPLETE); + ahc_print_path(ahc, pending_scb); + printf("Queuing a recovery SCB\n"); + ahc_qinfifo_requeue_tail(ahc, pending_scb); + ahc_outb(ahc, SCBPTR, saved_scbptr); + printf("%s:%d:%d:%d: Device is disconnected, re-queuing SCB\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + wait = TRUE; + } else { + printf("%s:%d:%d:%d: Unable to deliver message\n", + ahc_name(ahc), cmd->channel, cmd->target, cmd->lun); + retval = FAILED; + goto done; + } + +no_cmd: + /* + * Our assumption is that if we don't have the command, no + * recovery action was required, so we return success. Again, + * the semantics of the mid-layer recovery engine are not + * well defined, so this may change in time. + */ + retval = SUCCESS; +done: + if (paused) + unpause_sequencer(ahc); + if (wait) { + struct timer_list timer; + int ret; + + ahc_unlock(ahc, &s); + init_timer(&timer); + timer.data = (u_long)&ahc->platform_data->eh_sem; + timer.expires = jiffies + (5 * HZ); + timer.function = ahc_sem_timeout; + add_timer(&timer); + printf("Recovery code sleeping\n"); + down(&ahc->platform_data->eh_sem); + printf("Recovery code awake\n"); + ret = del_timer(&timer); + if (ret == 0) { + printf("Timer Expired\n"); + retval = FAILED; + } + ahc_lock(ahc, &s); + } + ahc_run_device_queues(ahc); + acmd = TAILQ_FIRST(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->completeq); + ahc_unlock(ahc, &s); + if (acmd != NULL) + ahc_run_complete_queue(ahc, acmd); + spin_lock_irq(&io_request_lock); + return (retval); +} + +/* + * Abort the current SCSI command(s). + */ +int +aic7xxx_abort(Scsi_Cmnd *cmd) +{ + int error; + + error = aic7xxx_queue_recovery_cmd(cmd, SCB_ABORT); + if (error != 0) + printf("aic7xxx_abort returns %d\n", error); + return (error); +} + +/* + * Attempt to send a target reset message to the device that timed out. + */ +int +aic7xxx_dev_reset(Scsi_Cmnd *cmd) +{ + int error; + + error = aic7xxx_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + if (error != 0) + printf("aic7xxx_dev_reset returns %d\n", error); + return (error); +} + +/* + * Reset the SCSI bus. + */ +int +aic7xxx_bus_reset(Scsi_Cmnd *cmd) +{ + struct ahc_softc *ahc; + struct ahc_cmd *acmd; + u_long s; + int found; + + /* + * It is a bug that the upper layer takes + * this lock just prior to calling us. + */ + spin_unlock_irq(&io_request_lock); + + ahc = *(struct ahc_softc **)cmd->host->hostdata; + ahc_lock(ahc, &s); + found = ahc_reset_channel(ahc, cmd->channel + 'A', + /*initiate reset*/TRUE); + acmd = TAILQ_FIRST(&ahc->platform_data->completeq); + TAILQ_INIT(&ahc->platform_data->completeq); + ahc_unlock(ahc, &s); + if (bootverbose) + printf("%s: SCSI bus reset delivered. " + "%d SCBs aborted.\n", ahc_name(ahc), found); + + if (acmd != NULL) + ahc_run_complete_queue(ahc, acmd); + + spin_lock_irq(&io_request_lock); + return SUCCESS; +} + +/* + * Return the disk geometry for the given SCSI device. + */ +int +aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) +{ + int heads; + int sectors; + int cylinders; + int ret; + int extended; + struct ahc_softc *ahc; + struct buffer_head *bh; + + ahc = *((struct ahc_softc **)disk->device->host->hostdata); + bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024); + + if (bh) { + ret = scsi_partsize(bh, disk->capacity, + &geom[2], &geom[0], &geom[1]); + brelse(bh); + if (ret != -1) + return (ret); + } + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + + if (disk->device->channel == 0) + extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0; + else + extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0; + if (extended && cylinders >= 1024) { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + return (0); +} + +/* + * Free the passed in Scsi_Host memory structures prior to unloading the + * module. + */ +int +aic7xxx_release(struct Scsi_Host * host) +{ + struct ahc_softc *ahc; + + if (host != NULL) { + ahc = *(struct ahc_softc **)host->hostdata; + ahc_free(ahc); + } + return (0); +} + +void +ahc_platform_dump_card_state(struct ahc_softc *ahc) +{ + struct ahc_linux_device *dev; + int channel; + int maxchannel; + int target; + int maxtarget; + int lun; + int i; + + maxchannel = (ahc->features & AHC_TWIN) ? 1 : 0; + maxtarget = (ahc->features & AHC_WIDE) ? 15 : 7; + for (channel = 0; channel <= maxchannel; channel++) { + for (target = 0; target <=maxtarget; target++) { + for (lun = 0; lun < AHC_NUM_LUNS; lun++) { + struct ahc_cmd *acmd; + + dev = ahc_get_device(ahc, channel, target, + lun, /*alloc*/FALSE); + if (dev == NULL) + continue; + + printf("DevQ(%d:%d:%d): ", + channel, target, lun); + i = 0; + TAILQ_FOREACH(acmd, &dev->busyq, + acmd_links.tqe) { + if (i++ > 256) + break; + } + printf("%d waiting\n", i); + } + } + } +} + +#if defined(MODULE) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +static Scsi_Host_Template driver_template = AIC7XXX; +Scsi_Host_Template *aic7xxx_driver_template = &driver_template; +#include "../scsi_module.c" +#endif diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,87 @@ +/* + * Adaptec AIC7xxx device driver host template for Linux. + * + * Copyright (c) 2000 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#2 $ + */ + +#ifndef _AIC7XXX_LINUX_HOST_H_ +#define _AIC7XXX_LINUX_HOST_H_ + +int aic7xxx_proc_info(char *, char **, off_t, int, int, int); +int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +int aic7xxx_detect(Scsi_Host_Template *); +int aic7xxx_release(struct Scsi_Host *); +const char *aic7xxx_info(struct Scsi_Host *); +int aic7xxx_biosparam(Disk *, kdev_t, int[]); +int aic7xxx_bus_reset(Scsi_Cmnd *); +int aic7xxx_dev_reset(Scsi_Cmnd *); +int aic7xxx_abort(Scsi_Cmnd *); + +#if defined(__i386__) +# define AIC7XXX_BIOSPARAM aic7xxx_biosparam +#else +# define AIC7XXX_BIOSPARAM NULL +#endif + +/* + * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields + * to do with card config are filled in after the card is detected. + */ +#define AIC7XXX { \ + next: NULL, \ + module: NULL, \ + proc_dir: NULL, \ + proc_info: aic7xxx_proc_info, \ + name: NULL, \ + detect: aic7xxx_detect, \ + release: aic7xxx_release, \ + info: aic7xxx_info, \ + command: NULL, \ + queuecommand: aic7xxx_queue, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: aic7xxx_abort, \ + eh_device_reset_handler: aic7xxx_dev_reset, \ + eh_bus_reset_handler: aic7xxx_bus_reset, \ + eh_host_reset_handler: NULL, \ + abort: NULL, \ + reset: NULL, \ + slave_attach: NULL, \ + bios_param: AIC7XXX_BIOSPARAM, \ + can_queue: 254, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: 0, /* max scatter-gather cmds */\ + cmd_per_lun: 2, /* cmds per lun */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 1 \ +} + +#endif /* _AIC7XXX_LINUX_HOST_H_ */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c Tue Mar 6 22:44:16 2001 @@ -0,0 +1,316 @@ +/* + * Linux driver attachment glue for PCI based controllers. + * + * Copyright (c) 2000 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#15 $ + */ + +#include "aic7xxx_osm.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +struct pci_device_id +{ +}; +#endif + +static int ahc_linux_pci_dev_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +static void ahc_linux_pci_dev_remove(struct pci_dev *pdev); + +/* We do our own ID filtering. So, grab all SCSI storage class devices. */ +static struct pci_device_id ahc_linux_pci_id_table[] = { + { + 0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0 + }, + { + 0x9005, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0 + }, + { 0 } +}; + +static struct pci_driver aic7xxx_pci_driver = { + name: "aic7xxx", + probe: ahc_linux_pci_dev_probe, + remove: ahc_linux_pci_dev_remove, + id_table: ahc_linux_pci_id_table +}; + +static void +ahc_linux_pci_dev_remove(struct pci_dev *pdev) +{ + struct ahc_softc *ahc; + struct ahc_softc *list_ahc; + + /* + * We should be able to just perform + * the free directly, but check our + * list for extra sanity. + */ + ahc = (struct ahc_softc *)pdev->driver_data; + TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { + if (list_ahc == ahc) { + ahc_free(ahc); + break; + } + } +} +#endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */ + +static int +ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + char buf[80]; + struct ahc_softc *ahc; + ahc_dev_softc_t pci; + struct ahc_pci_identity *entry; + char *name; + int error; + + pci = pdev; + entry = ahc_find_pci_device(pci); + if (entry == NULL) + return (-ENODEV); + + /* + * Allocate a softc for this card and + * set it up for attachment by our + * common detect routine. + */ + sprintf(buf, "ahc_pci:%d:%d:%d", + ahc_get_pci_bus(pci), + ahc_get_pci_slot(pci), + ahc_get_pci_function(pci)); + name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (name == NULL) + return (-ENOMEM); + strcpy(name, buf); + ahc = ahc_alloc(NULL, name); + if (ahc == NULL) + return (-ENOMEM); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if (pci_enable_device(pdev)) { + ahc_free(ahc); + return (-ENODEV); + } + pci_set_master(pdev); +#endif + ahc->dev_softc = pci; + ahc->platform_data->irq = pdev->irq; + error = ahc_pci_config(ahc, entry); + if (error != 0) { + ahc_free(ahc); + return (-error); + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pdev->driver_data = ahc; + if (aic7xxx_detect_complete) + aic7xxx_register_host(ahc, aic7xxx_driver_template); +#endif + return (0); +} + +int +ahc_linux_pci_probe(Scsi_Host_Template *template) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + return (pci_module_init(&aic7xxx_pci_driver)); +#else + struct pci_dev *pdev; + u_int class; + int found; + + /* If we don't have a PCI bus, we can't find any adapters. */ + if (pci_present() == 0) + return (0); + + found = 0; + pdev = NULL; + class = PCI_CLASS_STORAGE_SCSI << 8; + while ((pdev = pci_find_class(class, pdev)) != NULL) { + struct ahc_softc *ahc; + ahc_dev_softc_t pci; + int error; + + pci = pdev; + + /* + * Some BIOSen report the same device multiple times. + */ + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + struct pci_dev *probed_pdev; + + probed_pdev = ahc->dev_softc; + if (probed_pdev->bus->number == pdev->bus->number + && probed_pdev->devfn == pdev->devfn) + break; + } + if (ahc != NULL) { + /* Skip duplicate. */ + continue; + } + + error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL); + if (error == 0) + found++; + } + return (found); +#endif +} + +int +ahc_pci_map_registers(struct ahc_softc *ahc) +{ + uint32_t command; + u_long base; +#ifdef MMAPIO + u_long start; + u_long base_page; + u_long base_offset; +#endif + uint8_t *maddr; + + command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); + base = 0; + maddr = NULL; +#ifdef MMAPIO +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + start = pci_resource_start(ahc->dev_softc, 1); + base_page = start & PAGE_MASK; + base_offset = start - base_page; +#else + start = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS+4, 4); + base_offset = start & PCI_BASE_ADDRESS_MEM_MASK; + base_page = base_offset & PAGE_MASK; + base_offset -= base_page; +#endif + if (start != 0) { + ahc->platform_data->mem_busaddr = start; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if (request_mem_region(start, 0x1000, "aic7xxx") == 0) { + printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx " + "in use. Cannot map device.\n", + ahc_get_pci_bus(ahc->dev_softc), + ahc_get_pci_slot(ahc->dev_softc), + ahc_get_pci_function(ahc->dev_softc), + start); + } else +#endif + maddr = ioremap_nocache(base_page, base_offset + 256); + if (maddr != NULL) { + ahc->tag = BUS_SPACE_MEMIO; + ahc->bsh.maddr = maddr + base_offset; + command |= PCIM_CMD_MEMEN; + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, + command, 4); + + /* + * Do a quick test to see if memory mapped + * I/O is functioning correctly. + */ + if (ahc_inb(ahc, HCNTRL) == 0xFF) { + printf("aic7xxx: PCI Device %d:%d:%d " + "failed memory mapped test\n", + ahc_get_pci_bus(ahc->dev_softc), + ahc_get_pci_slot(ahc->dev_softc), + ahc_get_pci_function(ahc->dev_softc)); + iounmap((void *)base_page); + maddr = NULL; + } else { + command &= ~PCIM_CMD_PORTEN; + ahc_pci_write_config(ahc->dev_softc, + PCIR_COMMAND, command, 4); + } + } + } +#endif + + /* + * We always prefer memory mapped access. Only + * complain about our ioport conflicting with + * another device if we are going to use it. + */ + if (maddr == NULL) { + ahc->tag = BUS_SPACE_PIO; + command &= ~(PCIM_CMD_MEMEN|PCIM_CMD_PORTEN); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + base = pci_resource_start(ahc->dev_softc, 0); +#else + base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4); + base &= PCI_BASE_ADDRESS_IO_MASK; +#endif + if (base == 0) { + printf("aic7xxx: PCI%d:%d:%d No mapping available. " + "Cannot map device.\n", + ahc_get_pci_bus(ahc->dev_softc), + ahc_get_pci_slot(ahc->dev_softc), + ahc_get_pci_function(ahc->dev_softc)); + return (ENXIO); + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + if (check_region(base, 256) != 0) { +#else + if (request_region(base, 256, "aic7xxx") == 0) { +#endif + printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] " + "in use. Cannot map device.\n", + ahc_get_pci_bus(ahc->dev_softc), + ahc_get_pci_slot(ahc->dev_softc), + ahc_get_pci_function(ahc->dev_softc), + base); + base = 0; + return (EBUSY); + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + request_region(base, 256, "aic7xxx"); +#endif + ahc->bsh.ioport = base; + command |= PCIM_CMD_PORTEN; + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4); + } + return (0); +} + +int +ahc_pci_map_int(struct ahc_softc *ahc) +{ + int error; + + ahc->platform_data->irq = ahc->dev_softc->irq; + error = request_irq(ahc->platform_data->irq, aic7xxx_isr, + SA_INTERRUPT|SA_SHIRQ, "aic7xxx", ahc); + if (error < 0) + error = request_irq(ahc->platform_data->irq, aic7xxx_isr, + SA_SHIRQ, "aic7xxx", ahc); + + return (-error); +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h linux/drivers/scsi/aic7xxx/aic7xxx_osm.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_osm.h Tue Mar 6 22:44:16 2001 @@ -0,0 +1,1074 @@ +/* + * Adaptec AIC7xxx device driver for Linux. + * + * Copyright (c) 1994 John Aycock + * The University of Calgary Department of Computer Science. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * + * Copyright (c) 2000, 2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $ + * + */ +#ifndef _AIC7XXX_LINUX_H_ +#define _AIC7XXX_LINUX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include +#endif + +/* Core SCSI definitions */ +#include "../scsi.h" +#include "../hosts.h" + +/* Name space conflict with BSD queue macros */ +#ifdef LIST_HEAD +#undef LIST_HEAD +#endif + +#include "cam.h" +#include "queue.h" +#include "scsi_message.h" + +/* + * We never have to reference the current task, and the driver core + * makes ample use of this "name". + */ +#ifdef current +#undef current +#endif + +/************************* Forward Declarations *******************************/ +struct ahc_softc; +typedef struct pci_dev *ahc_dev_softc_t; +typedef Scsi_Cmnd *ahc_io_ctx_t; + +/******************************* Byte Order ***********************************/ +#define ahc_htobe16(x) cpu_to_be16(x) +#define ahc_htobe32(x) cpu_to_be32(x) +#define ahc_htobe64(x) cpu_to_be64(x) +#define ahc_htole16(x) cpu_to_le16(x) +#define ahc_htole32(x) cpu_to_le32(x) +#define ahc_htole64(x) cpu_to_le64(x) + +#define ahc_be16toh(x) be16_to_cpu(x) +#define ahc_be32toh(x) be32_to_cpu(x) +#define ahc_be64toh(x) be64_to_cpu(x) +#define ahc_le16toh(x) le16_to_cpu(x) +#define ahc_le32toh(x) le32_to_cpu(x) +#define ahc_le64toh(x) le64_to_cpu(x) + +/************************* Configuration Data *********************************/ +extern int aic7xxx_no_probe; +extern int aic7xxx_detect_complete; +extern Scsi_Host_Template* aic7xxx_driver_template; + +/***************************** Bus Space/DMA **********************************/ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16) +typedef dma_addr_t bus_addr_t; +#else +typedef uint32_t bus_addr_t; +#endif +typedef uint32_t bus_size_t; + +typedef enum { + BUS_SPACE_MEMIO, + BUS_SPACE_PIO +} bus_space_tag_t; + +typedef union { + u_long ioport; + volatile uint8_t *maddr; +} bus_space_handle_t; + +typedef struct bus_dma_segment +{ + bus_addr_t ds_addr; + bus_size_t ds_len; +} bus_dma_segment_t; + +struct ahc_linux_dma_tag +{ + bus_size_t alignment; + bus_size_t boundary; + bus_size_t maxsize; +}; +typedef struct ahc_linux_dma_tag* bus_dma_tag_t; + +struct ahc_linux_dmamap +{ + bus_addr_t bus_addr; +}; +typedef struct ahc_linux_dmamap* bus_dmamap_t; + +typedef int bus_dma_filter_t(void*, bus_addr_t); +typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); + +#define BUS_DMA_WAITOK 0x0 +#define BUS_DMA_NOWAIT 0x1 +#define BUS_DMA_ALLOCNOW 0x2 +#define BUS_DMA_LOAD_SEGS 0x4 /* + * Argument is an S/G list not + * a single buffer. + */ + +#define BUS_SPACE_MAXADDR 0xFFFFFFFF +#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF + +int ahc_dma_tag_create(struct ahc_softc *, bus_dma_tag_t /*parent*/, + bus_size_t /*alignment*/, bus_size_t /*boundary*/, + bus_addr_t /*lowaddr*/, bus_addr_t /*highaddr*/, + bus_dma_filter_t*/*filter*/, void */*filterarg*/, + bus_size_t /*maxsize*/, int /*nsegments*/, + bus_size_t /*maxsegsz*/, int /*flags*/, + bus_dma_tag_t */*dma_tagp*/); + +void ahc_dma_tag_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/); + +int ahc_dmamem_alloc(struct ahc_softc *, bus_dma_tag_t /*dmat*/, + void** /*vaddr*/, int /*flags*/, + bus_dmamap_t* /*mapp*/); + +void ahc_dmamem_free(struct ahc_softc *, bus_dma_tag_t /*dmat*/, + void* /*vaddr*/, bus_dmamap_t /*map*/); + +void ahc_dmamap_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/, + bus_dmamap_t /*map*/); + +int ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t /*dmat*/, + bus_dmamap_t /*map*/, void * /*buf*/, + bus_size_t /*buflen*/, bus_dmamap_callback_t *, + void */*callback_arg*/, int /*flags*/); + +int ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t); + +/* XXX May do selective memory barrier operations on certain platforms */ +#define ahc_dmamap_sync(ahc, dma_tag, dmamap, op) + +/************************** SCSI Constants/Structures *************************/ +#define SCSI_REV_2 2 +#define SCSI_STATUS_OK 0x00 +#define SCSI_STATUS_CHECK_COND 0x02 +#define SCSI_STATUS_COND_MET 0x04 +#define SCSI_STATUS_BUSY 0x08 +#define SCSI_STATUS_INTERMED 0x10 +#define SCSI_STATUS_INTERMED_COND_MET 0x14 +#define SCSI_STATUS_RESERV_CONFLICT 0x18 +#define SCSI_STATUS_CMD_TERMINATED 0x22 +#define SCSI_STATUS_QUEUE_FULL 0x28 + +/* + * 6 byte request sense CDB format. + */ +struct scsi_sense +{ + uint8_t opcode; + uint8_t byte2; + uint8_t unused[2]; + uint8_t length; + uint8_t control; +}; + +struct scsi_sense_data +{ + uint8_t error_code; + uint8_t segment; + uint8_t flags; + uint8_t info[4]; + uint8_t extra_len; + uint8_t cmd_spec_info[4]; + uint8_t add_sense_code; + uint8_t add_sense_code_qual; + uint8_t fru; + uint8_t sense_key_spec[3]; + uint8_t extra_bytes[14]; +}; + +struct scsi_inquiry_data +{ + uint8_t device; +#define SID_TYPE(inq_data) ((inq_data)->device & 0x1f) +#define SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5) +#define SID_QUAL_LU_CONNECTED 0x00 /* + * The specified peripheral device + * type is currently connected to + * logical unit. If the target cannot + * determine whether or not a physical + * device is currently connected, it + * shall also use this peripheral + * qualifier when returning the INQUIRY + * data. This peripheral qualifier + * does not mean that the device is + * ready for access by the initiator. + */ +#define SID_QUAL_LU_OFFLINE 0x01 /* + * The target is capable of supporting + * the specified peripheral device type + * on this logical unit; however, the + * physical device is not currently + * connected to this logical unit. + */ +#define SID_QUAL_RSVD 0x02 +#define SID_QUAL_BAD_LU 0x03 /* + * The target is not capable of + * supporting a physical device on + * this logical unit. For this + * peripheral qualifier the peripheral + * device type shall be set to 1Fh to + * provide compatibility with previous + * versions of SCSI. All other + * peripheral device type values are + * reserved for this peripheral + * qualifier. + */ +#define SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0) + uint8_t dev_qual2; +#define SID_QUAL2 0x7F +#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0) + uint8_t version; +#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07) +#define SCSI_REV_0 0 +#define SCSI_REV_CCS 1 +#define SCSI_REV_2 2 +#define SCSI_REV_SPC 3 +#define SCSI_REV_SPC2 4 + +#define SID_ECMA 0x38 +#define SID_ISO 0xC0 + uint8_t response_format; +#define SID_AENC 0x80 +#define SID_TrmIOP 0x40 + uint8_t additional_length; + uint8_t reserved[2]; + uint8_t flags; +#define SID_SftRe 0x01 +#define SID_CmdQue 0x02 +#define SID_Linked 0x08 +#define SID_Sync 0x10 +#define SID_WBus16 0x20 +#define SID_WBus32 0x40 +#define SID_RelAdr 0x80 +#define SID_VENDOR_SIZE 8 + char vendor[SID_VENDOR_SIZE]; +#define SID_PRODUCT_SIZE 16 + char product[SID_PRODUCT_SIZE]; +#define SID_REVISION_SIZE 4 + char revision[SID_REVISION_SIZE]; + /* + * The following fields were taken from SCSI Primary Commands - 2 + * (SPC-2) Revision 14, Dated 11 November 1999 + */ +#define SID_VENDOR_SPECIFIC_0_SIZE 20 + u_int8_t vendor_specific0[SID_VENDOR_SPECIFIC_0_SIZE]; + /* + * An extension of SCSI Parallel Specific Values + */ +#define SID_SPI_IUS 0x01 +#define SID_SPI_QAS 0x02 +#define SID_SPI_CLOCK_ST 0x00 +#define SID_SPI_CLOCK_DT 0x04 +#define SID_SPI_CLOCK_DT_ST 0x0C +#define SID_SPI_MASK 0x0F + uint8_t spi3data; + uint8_t reserved2; + /* + * Version Descriptors, stored 2 byte values. + */ + uint8_t version1[2]; + uint8_t version2[2]; + uint8_t version3[2]; + uint8_t version4[2]; + uint8_t version5[2]; + uint8_t version6[2]; + uint8_t version7[2]; + uint8_t version8[2]; + + uint8_t reserved3[22]; + +#define SID_VENDOR_SPECIFIC_1_SIZE 160 + uint8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE]; +}; + +/********************************** Includes **********************************/ +/* Host template and function declarations referenced by the template. */ +#include "aic7xxx_linux_host.h" + +/* Core driver definitions */ +#include "aic7xxx.h" + +/* SMP support */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17) +#include +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) +#include +#endif + +#define AIC7XXX_DRIVER_VERSION "6.1.5" + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +/**************************** Front End Queues ********************************/ +/* + * Data structure used to cast the Linux struct scsi_cmnd to something + * that allows us to use the queue macros. The linux structure has + * plenty of space to hold the links fields as required by the queue + * macros, but the queue macors require them to have the correct type. + */ +struct ahc_cmd_internal { + /* Area owned by the Linux scsi layer. */ + uint8_t private[offsetof(struct scsi_cmnd, SCp.Status)]; + union { + STAILQ_ENTRY(ahc_cmd) ste; + LIST_ENTRY(ahc_cmd) le; + TAILQ_ENTRY(ahc_cmd) tqe; + } links; + uint32_t end; +}; + +struct ahc_cmd { + union { + struct ahc_cmd_internal icmd; + struct scsi_cmnd scsi_cmd; + } un; +}; + +#define acmd_icmd(cmd) ((cmd)->un.icmd) +#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd) +#define acmd_links un.icmd.links + +/*************************** Device Data Structures ***************************/ +/* + * A per probed device structure used to deal with some error recovery + * scenarios that the Linux mid-layer code just doesn't know how to + * handle. The structure allocated for a device only becomes persistant + * after a successfully completed inquiry command to the target when + * that inquiry data indicates a lun is present. + */ +TAILQ_HEAD(ahc_busyq, ahc_cmd); +typedef enum { + AHC_DEV_UNCONFIGURED = 0x01, + AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ + AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ + AHC_DEV_ON_RUN_LIST = 0x08 /* Queued to be run later */ +} ahc_dev_flags; + +struct ahc_linux_target; +struct ahc_linux_device { + LIST_ENTRY(ahc_linux_device) links; + struct ahc_busyq busyq; + + /* + * The number of transactions currently + * queued to the device. + */ + int active; + + /* + * The currently allowed number of + * transactions that can be queued to + * the device. Must be signed for + * conversion from tagged to untagged + * mode where the device may have more + * than one outstanding active transaction. + */ + int openings; + + /* + * A positive count indicates that this + * device's queue is halted. + */ + u_int qfrozen; + + /* + * Cumulative command counter. + */ + u_int num_commands; + + /* + * The number of tagged transactions when + * running at our current opening level + * that have been successfully received by + * this device since the last QUEUE FULL. + */ + u_int tag_success_count; +#define AHC_TAG_SUCCESS_INTERVAL 50 + + ahc_dev_flags flags; + + /* + * The high limit for the tags variable. + */ + u_int maxtags; + + /* + * The computed number of tags outstanding + * at the time of the last QUEUE FULL event. + */ + u_int tags_on_last_queuefull; + + /* + * How many times we have seen a queue full + * with the same number of tags. This is used + * to stop our adaptive queue depth algorithm + * on devices with a fixed number of tags. + */ + u_int last_queuefull_same_count; + +#define AHC_LOCK_TAGS_COUNT 50 + int lun; + struct ahc_linux_target *target; +}; + +struct ahc_linux_target { + struct ahc_linux_device *devices[AHC_NUM_LUNS]; + int channel; + int target; + int refcount; + struct ahc_transinfo last_tinfo; +}; + +/********************* Definitions Required by the Core ***********************/ +/* + * Number of SG segments we require. So long as the S/G segments for + * a particular transaction are allocated in a physically contiguous + * manner and are allocated below 4GB, the number of S/G segments is + * unrestricted. + */ +#define AHC_NSEG 128 + +/* + * Per-SCB OSM storage. + */ +struct scb_platform_data { + struct ahc_linux_device *dev; + uint32_t xfer_len; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + uint32_t resid; /* Transfer residual */ +#endif +}; + +/* + * Define a structure used for each host adapter. All members are + * aligned on a boundary >= the size of the member to honor the + * alignment restrictions of the various platforms supported by + * this driver. + */ +TAILQ_HEAD(ahc_completeq, ahc_cmd); +struct ahc_platform_data { + /* + * Fields accessed from interrupt context. + */ + struct ahc_linux_target *targets[AHC_NUM_TARGETS]; + LIST_HEAD(, ahc_linux_device) device_runq; + struct ahc_completeq completeq; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) + spinlock_t spin_lock; +#endif + u_int qfrozen; + struct timer_list reset_timer; + struct semaphore eh_sem; + struct Scsi_Host *host; /* pointer to scsi host */ + uint32_t irq; /* IRQ for this adapter */ + uint32_t bios_address; + uint32_t mem_busaddr; /* Mem Base Addr */ +}; + +/************************** OS Utility Wrappers *******************************/ +#define printf printk +#define M_NOWAIT GFP_ATOMIC +#define M_WAITOK 0 +#define malloc(size, type, flags) kmalloc(size, flags) +#define free(ptr, type) kfree(ptr) + +static __inline void ahc_delay(long); +static __inline void +ahc_delay(long usec) +{ + /* + * udelay on Linux can have problems for + * multi-millisecond waits. Wait at most + * 1024us per call. + */ + while (usec > 0) { + udelay(usec % 1024); + usec -= 1024; + } +} + + +/***************************** Low Level I/O **********************************/ +#if defined(__powerpc__) +#define MMAPIO +#ifdef mb +#undef mb +#endif +#define mb() \ + __asm__ __volatile__("eieio" ::: "memory") +#elif defined(__i386__) +#define MMAPIO +#ifdef mb +#undef mb +#endif +#define mb() \ + do { ; } while(0) +#elif defined(__alpha__) +#ifdef mb +#undef mb +#endif +#define mb() \ + __asm__ __volatile__("mb": : :"memory") +#elif defined(__sparc__) +#define MMAPIO +/* The default mb() define does what this driver wants. -DaveM */ +#endif + +static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port); +static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val); +static __inline void ahc_outsb(struct ahc_softc * ahc, long port, + uint8_t *, int count); +static __inline void ahc_insb(struct ahc_softc * ahc, long port, + uint8_t *, int count); + +static __inline uint8_t +ahc_inb(struct ahc_softc * ahc, long port) +{ +#ifdef MMAPIO + uint8_t x; + + if (ahc->tag == BUS_SPACE_MEMIO) { + x = readb(ahc->bsh.maddr + port); + } else { + x = inb(ahc->bsh.ioport + port); + } + mb(); + return (x); +#else + return (inb(ahc->bsh.ioport + port)); +#endif +} + +static __inline void +ahc_outb(struct ahc_softc * ahc, long port, uint8_t val) +{ +#ifdef MMAPIO + if (ahc->tag == BUS_SPACE_MEMIO) { + writeb(val, ahc->bsh.maddr + port); + } else { + outb(val, ahc->bsh.ioport + port); + } + mb(); +#else + outb(val, ahc->bsh.ioport + port); +#endif +} + +static __inline void +ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count) +{ + int i; + + /* + * There is probably a more efficient way to do this on Linux + * but we don't use this for anything speed critical and this + * should work. + */ + for (i = 0; i < count; i++) + ahc_outb(ahc, port, *array++); +} + +static __inline void +ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count) +{ + int i; + + /* + * There is probably a more efficient way to do this on Linux + * but we don't use this for anything speed critical and this + * should work. + */ + for (i = 0; i < count; i++) + *array++ = ahc_inb(ahc, port); +} + +/**************************** Initialization **********************************/ +int aic7xxx_register_host(struct ahc_softc *ahc, + Scsi_Host_Template *template); + +/*************************** Pretty Printing **********************************/ +struct info_str { + char *buffer; + int length; + off_t offset; + int pos; +}; + +void ahc_format_transinfo(struct info_str *info, + struct ahc_transinfo *tinfo); + +/******************************** Locking *************************************/ +/* Lock protecting internal data structures */ +static __inline void ahc_lockinit(struct ahc_softc *); +static __inline void ahc_lock(struct ahc_softc *, unsigned long *flags); +static __inline void ahc_unlock(struct ahc_softc *, unsigned long *flags); + +/* Lock held during command compeletion to the upper layer */ +static __inline void ahc_done_lockinit(struct ahc_softc *); +static __inline void ahc_done_lock(struct ahc_softc *, unsigned long *flags); +static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) +static __inline void +ahc_lockinit(struct ahc_softc *ahc) +{ + spin_lock_init(&ahc->platform_data->spin_lock); +} + +static __inline void +ahc_lock(struct ahc_softc *ahc, unsigned long *flags) +{ + *flags = 0; + spin_lock_irqsave(&ahc->platform_data->spin_lock, *flags); +} + +static __inline void +ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) +{ + spin_unlock_irqrestore(&ahc->platform_data->spin_lock, *flags); +} + +static __inline void +ahc_done_lockinit(struct ahc_softc *ahc) +{ + /* We don't own the iorequest lock, so we don't initialize it. */ +} + +static __inline void +ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags) +{ + *flags = 0; + spin_lock_irqsave(&io_request_lock, *flags); +} + +static __inline void +ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags) +{ + spin_unlock_irqrestore(&io_request_lock, *flags); +} + +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */ + +ahc_lockinit(struct ahc_softc *ahc) +{ +} + +static __inline void +ahc_lock(struct ahc_softc *ahc, unsigned long *flags) +{ + *flags = 0; + save_flags(*flags); + cli(); +} + +static __inline void +ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) +{ + restore_flags(*flags); +} + +ahc_done_lockinit(struct ahc_softc *ahc) +{ +} + +static __inline void +ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags) +{ + /* + * The done lock is always held while + * the ahc lock is held so blocking + * interrupts again would have no effect. + */ +} + +static __inline void +ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags) +{ +} +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */ + +/******************************* PCI Definitions ******************************/ +/* + * PCIM_xxx: mask to locate subfield in register + * PCIR_xxx: config register offset + * PCIC_xxx: device class + * PCIS_xxx: device subclass + * PCIP_xxx: device programming interface + * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) + * PCID_xxx: device ID + */ +#define PCIR_DEVVENDOR 0x00 +#define PCIR_VENDOR 0x00 +#define PCIR_DEVICE 0x02 +#define PCIR_COMMAND 0x04 +#define PCIM_CMD_PORTEN 0x0001 +#define PCIM_CMD_MEMEN 0x0002 +#define PCIM_CMD_BUSMASTEREN 0x0004 +#define PCIM_CMD_MWRICEN 0x0010 +#define PCIM_CMD_PERRESPEN 0x0040 +#define PCIR_STATUS 0x06 +#define PCIR_REVID 0x08 +#define PCIR_PROGIF 0x09 +#define PCIR_SUBCLASS 0x0a +#define PCIR_CLASS 0x0b +#define PCIR_CACHELNSZ 0x0c +#define PCIR_LATTIMER 0x0d +#define PCIR_HEADERTYPE 0x0e +#define PCIM_MFDEV 0x80 +#define PCIR_BIST 0x0f +#define PCIR_CAP_PTR 0x34 + +/* config registers for header type 0 devices */ +#define PCIR_MAPS 0x10 +#define PCIR_SUBVEND_0 0x2c +#define PCIR_SUBDEV_0 0x2e + +/**************************** VL/EISA Routines ********************************/ +int aic7770_linux_probe(Scsi_Host_Template *); +int aic7770_map_registers(struct ahc_softc *ahc); +int aic7770_map_int(struct ahc_softc *ahc, + u_int irq, int shared); + +/******************************* PCI Routines *********************************/ +/* + * We need to use the bios32.h routines if we are kernel version 2.1.92 or less. + */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) +#if defined(__sparc_v9__) || defined(__powerpc__) +#error "PPC and Sparc platforms are only support under 2.1.92 and above" +#endif +#include +#endif + +int ahc_linux_pci_probe(Scsi_Host_Template *); +int ahc_pci_map_registers(struct ahc_softc *ahc); +int ahc_pci_map_int(struct ahc_softc *ahc); + +static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci, + int reg, int width); + +static __inline uint32_t +ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width) +{ + switch (width) { + case 1: + { + uint8_t retval; + + pci_read_config_byte(pci, reg, &retval); + return (retval); + } + case 2: + { + uint16_t retval; + pci_read_config_word(pci, reg, &retval); + return (retval); + } + case 4: + { + uint32_t retval; + pci_read_config_dword(pci, reg, &retval); + return (retval); + } + default: + panic("ahc_pci_read_config: Read size too big"); + /* NOTREACHED */ + } +} + +static __inline void ahc_pci_write_config(ahc_dev_softc_t pci, + int reg, uint32_t value, + int width); + +static __inline void +ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width) +{ + switch (width) { + case 1: + pci_write_config_byte(pci, reg, value); + break; + case 2: + pci_write_config_word(pci, reg, value); + break; + case 4: + pci_write_config_dword(pci, reg, value); + break; + default: + panic("ahc_pci_write_config: Write size too big"); + /* NOTREACHED */ + } +} + +static __inline int ahc_get_pci_function(ahc_dev_softc_t); +static __inline int +ahc_get_pci_function(ahc_dev_softc_t pci) +{ + return (PCI_FUNC(pci->devfn)); +} + +static __inline int ahc_get_pci_slot(ahc_dev_softc_t); +static __inline int +ahc_get_pci_slot(ahc_dev_softc_t pci) +{ + return (PCI_SLOT(pci->devfn)); +} + +static __inline int ahc_get_pci_bus(ahc_dev_softc_t); +static __inline int +ahc_get_pci_bus(ahc_dev_softc_t pci) +{ + return (pci->bus->number); +} + +static __inline void ahc_flush_device_writes(struct ahc_softc *); +static __inline void +ahc_flush_device_writes(struct ahc_softc *ahc) +{ + /* XXX Is this sufficient for all architectures??? */ + ahc_inb(ahc, INTSTAT); +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0) +#define pci_map_sg(pdev, sg_list, nseg, direction) (nseg) +#define pci_unmap_sg(pdev, sg_list, nseg, direction) +#define sg_dma_address(sg) (VIRT_TO_BUS((sg)->address)) +#define sg_dma_len(sg) ((sg)->length) +#define pci_map_single(pdev, buffer, bufflen, direction) \ + (VIRT_TO_BUS(buffer)) +#define pci_unmap_single(pdev, buffer, buflen, direction) +#endif + +/*********************** Transaction Access Wrappers **************************/ +static __inline void ahc_set_transaction_status(struct scb *, uint32_t); +static __inline +void ahc_set_transaction_status(struct scb *scb, uint32_t status) +{ + scb->io_ctx->result &= ~(CAM_STATUS_MASK << 16); + scb->io_ctx->result |= status << 16; +} + +static __inline void ahc_set_scsi_status(struct scb *, uint32_t); +static __inline +void ahc_set_scsi_status(struct scb *scb, uint32_t status) +{ + scb->io_ctx->result &= ~0xFFFF; + scb->io_ctx->result |= status; +} + +static __inline uint32_t ahc_get_transaction_status(struct scb *); +static __inline +uint32_t ahc_get_transaction_status(struct scb *scb) +{ + return ((scb->io_ctx->result >> 16) & CAM_STATUS_MASK); +} + +static __inline uint32_t ahc_get_scsi_status(struct scb *); +static __inline +uint32_t ahc_get_scsi_status(struct scb *scb) +{ + return (scb->io_ctx->result & 0xFFFF); +} + +static __inline void ahc_set_transaction_tag(struct scb *, int, u_int); +static __inline +void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type) +{ + /* + * Nothing to do for linux as the incoming transaction + * has no concept of tag/non tagged, etc. + */ +} + +static __inline u_long ahc_get_transfer_length(struct scb *); +static __inline +u_long ahc_get_transfer_length(struct scb *scb) +{ + return (scb->platform_data->xfer_len); +} + +static __inline int ahc_get_transfer_dir(struct scb *); +static __inline +int ahc_get_transfer_dir(struct scb *scb) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,40) + return (scb->io_ctx->sc_data_direction); +#else + if (scb->io_ctx->bufflen == 0) + return (CAM_DIR_NONE); + + switch(scb->io_ctx->cmnd[0]) { + case 0x08: /* READ(6) */ + case 0x28: /* READ(10) */ + case 0xA8: /* READ(12) */ + return (CAM_DIR_IN); + case 0x0A: /* WRITE(6) */ + case 0x2A: /* WRITE(10) */ + case 0xAA: /* WRITE(12) */ + return (CAM_DIR_OUT); + default: + return (CAM_DIR_NONE); + } +#endif +} + +static __inline void ahc_set_residual(struct scb *, u_long); +static __inline +void ahc_set_residual(struct scb *scb, u_long resid) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + scb->io_ctx->resid = resid; +#else + scb->platform_data->resid = resid; +#endif +} + +static __inline void ahc_set_sense_residual(struct scb *, u_long); +static __inline +void ahc_set_sense_residual(struct scb *scb, u_long resid) +{ + /* This can't be reported in Linux */ +} + +static __inline u_long ahc_get_residual(struct scb *); +static __inline +u_long ahc_get_residual(struct scb *scb) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + return (scb->io_ctx->resid); +#else + return (scb->platform_data->resid); +#endif +} + +static __inline int ahc_perform_autosense(struct scb *); +static __inline +int ahc_perform_autosense(struct scb *scb) +{ + /* + * We always perform autosense in Linux. + * On other platforms this is set on a + * per-transaction basis. + */ + return (1); +} + +static __inline uint32_t +ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb) +{ + return (sizeof(struct scsi_sense_data)); +} + +static __inline void ahc_notify_xfer_settings_change(struct ahc_softc *, + struct ahc_devinfo *); +static __inline void +ahc_notify_xfer_settings_change(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo) +{ + /* Nothing to do here for linux */ +} + +static __inline void ahc_platform_scb_free(struct ahc_softc *ahc, + struct scb *scb); +static __inline void +ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb) +{ + ahc->flags &= ~AHC_RESOURCE_SHORTAGE; +} + +int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg); +void ahc_platform_free(struct ahc_softc *ahc); +void ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb); +static __inline void ahc_freeze_scb(struct scb *scb); +static __inline void +ahc_freeze_scb(struct scb *scb) +{ + /* Noting to do here for linux */ +} + +void ahc_platform_set_tags(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo, int enable); +int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, + char channel, int lun, u_int tag, + role_t role, uint32_t status); +void aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs); +void ahc_platform_flushwork(struct ahc_softc *ahc); +int ahc_softc_comp(struct ahc_softc *, struct ahc_softc *); +void ahc_done(struct ahc_softc*, struct scb*); +void ahc_send_async(struct ahc_softc *, char channel, + u_int target, u_int lun, ac_code); +void ahc_print_path(struct ahc_softc *, struct scb *); +void ahc_platform_dump_card_state(struct ahc_softc *ahc); + +#ifdef CONFIG_PCI +#define AHC_PCI_CONFIG 1 +#else +#define AHC_PCI_CONFIG 0 +#endif +#define bootverbose aic7xxx_verbose +extern int aic7xxx_verbose; +#endif /* _AIC7XXX_LINUX_H_ */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_pci.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_pci.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_pci.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,2137 @@ +/* + * Product specific probe and attach routines for: + * 3940, 2940, aic7895, aic7890, aic7880, + * aic7870, aic7860 and aic7850 SCSI controllers + * + * Copyright (c) 1995-2000 Justin T. Gibbs + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#17 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $ + */ + +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" +#include "aic7xxx_93cx6.h" + +#define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */ +#define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */ + +static __inline uint64_t +ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) +{ + uint64_t id; + + id = subvendor + | (subdevice << 16) + | ((uint64_t)vendor << 32) + | ((uint64_t)device << 48); + + return (id); +} + +#define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull +#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull +#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull +#define ID_9005_SISL_MASK 0x000FFFFF00000000ull +#define ID_9005_SISL_ID 0x0005900500000000ull +#define ID_AIC7850 0x5078900400000000ull +#define ID_AHA_2902_04_10_15_20_30C 0x5078900478509004ull +#define ID_AIC7855 0x5578900400000000ull +#define ID_AIC7859 0x3860900400000000ull +#define ID_AHA_2930CU 0x3860900438699004ull +#define ID_AIC7860 0x6078900400000000ull +#define ID_AIC7860C 0x6078900478609004ull +#define ID_AHA_1480A 0x6075900400000000ull +#define ID_AHA_2940AU_0 0x6178900400000000ull +#define ID_AHA_2940AU_1 0x6178900478619004ull +#define ID_AHA_2940AU_CN 0x2178900478219004ull +#define ID_AHA_2930C_VAR 0x6038900438689004ull + +#define ID_AIC7870 0x7078900400000000ull +#define ID_AHA_2940 0x7178900400000000ull +#define ID_AHA_3940 0x7278900400000000ull +#define ID_AHA_398X 0x7378900400000000ull +#define ID_AHA_2944 0x7478900400000000ull +#define ID_AHA_3944 0x7578900400000000ull +#define ID_AHA_4944 0x7678900400000000ull + +#define ID_AIC7880 0x8078900400000000ull +#define ID_AIC7880_B 0x8078900478809004ull +#define ID_AHA_2940U 0x8178900400000000ull +#define ID_AHA_3940U 0x8278900400000000ull +#define ID_AHA_2944U 0x8478900400000000ull +#define ID_AHA_3944U 0x8578900400000000ull +#define ID_AHA_398XU 0x8378900400000000ull +#define ID_AHA_4944U 0x8678900400000000ull +#define ID_AHA_2940UB 0x8178900478819004ull +#define ID_AHA_2930U 0x8878900478889004ull +#define ID_AHA_2940U_PRO 0x8778900478879004ull +#define ID_AHA_2940U_CN 0x0078900478009004ull + +#define ID_AIC7895 0x7895900478959004ull +#define ID_AIC7895_ARO 0x7890900478939004ull +#define ID_AIC7895_ARO_MASK 0xFFF0FFFFFFFFFFFFull +#define ID_AHA_2940U_DUAL 0x7895900478919004ull +#define ID_AHA_3940AU 0x7895900478929004ull +#define ID_AHA_3944AU 0x7895900478949004ull + +#define ID_AIC7890 0x001F9005000F9005ull +#define ID_AIC7890_ARO 0x00139005000F9005ull +#define ID_AAA_131U2 0x0013900500039005ull +#define ID_AHA_2930U2 0x0011900501819005ull +#define ID_AHA_2940U2B 0x00109005A1009005ull +#define ID_AHA_2940U2_OEM 0x0010900521809005ull +#define ID_AHA_2940U2 0x00109005A1809005ull +#define ID_AHA_2950U2B 0x00109005E1009005ull + +#define ID_AIC7892 0x008F9005FFFF9005ull +#define ID_AIC7892_ARO 0x00839005FFFF9005ull +#define ID_AHA_29160 0x00809005E2A09005ull +#define ID_AHA_29160_CPQ 0x00809005E2A00E11ull +#define ID_AHA_29160N 0x0080900562A09005ull +#define ID_AHA_29160C 0x0080900562209005ull +#define ID_AHA_29160B 0x00809005E2209005ull +#define ID_AHA_19160B 0x0081900562A19005ull + +#define ID_AIC7896 0x005F9005FFFF9005ull +#define ID_AIC7896_ARO 0x00539005FFFF9005ull +#define ID_AHA_3950U2B_0 0x00509005FFFF9005ull +#define ID_AHA_3950U2B_1 0x00509005F5009005ull +#define ID_AHA_3950U2D_0 0x00519005FFFF9005ull +#define ID_AHA_3950U2D_1 0x00519005B5009005ull + +#define ID_AIC7899 0x00CF9005FFFF9005ull +#define ID_AIC7899_ARO 0x00C39005FFFF9005ull +#define ID_AHA_3960D 0x00C09005F6209005ull +#define ID_AHA_3960D_CPQ 0x00C09005F6200E11ull + +#define ID_AIC7810 0x1078900400000000ull +#define ID_AIC7815 0x7815900400000000ull + +#define DEVID_9005_TYPE(id) ((id) & 0xF) +#define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */ +#define DEVID_9005_TYPE_AAA 0x3 /* RAID Card */ +#define DEVID_9005_TYPE_SISL 0x5 /* Low Cost Card */ +#define DEVID_9005_TYPE_MB 0xF /* On Motherboard */ + +#define DEVID_9005_MAXRATE(id) (((id) & 0x30) >> 4) +#define DEVID_9005_MAXRATE_U160 0x0 +#define DEVID_9005_MAXRATE_ULTRA2 0x1 +#define DEVID_9005_MAXRATE_ULTRA 0x2 +#define DEVID_9005_MAXRATE_FAST 0x3 + +#define DEVID_9005_MFUNC(id) (((id) & 0x40) >> 6) + +#define DEVID_9005_CLASS(id) (((id) & 0xFF00) >> 8) +#define DEVID_9005_CLASS_SPI 0x0 /* Parallel SCSI */ + +#define SUBID_9005_TYPE(id) ((id) & 0xF) +#define SUBID_9005_TYPE_MB 0xF /* On Motherboard */ +#define SUBID_9005_TYPE_CARD 0x0 /* Standard Card */ +#define SUBID_9005_TYPE_LCCARD 0x1 /* Low Cost Card */ +#define SUBID_9005_TYPE_RAID 0x3 /* Combined with Raid */ + +#define SUBID_9005_TYPE_KNOWN(id) \ + ((((id) & 0xF) == SUBID_9005_TYPE_MB) \ + || (((id) & 0xF) == SUBID_9005_TYPE_CARD) \ + || (((id) & 0xF) == SUBID_9005_TYPE_LCCARD) \ + || (((id) & 0xF) == SUBID_9005_TYPE_RAID)) + +#define SUBID_9005_MAXRATE(id) (((id) & 0x30) >> 4) +#define SUBID_9005_MAXRATE_ULTRA2 0x0 +#define SUBID_9005_MAXRATE_ULTRA 0x1 +#define SUBID_9005_MAXRATE_U160 0x2 +#define SUBID_9005_MAXRATE_RESERVED 0x3 + +#define SUBID_9005_SEEPTYPE(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? ((id) & 0xC0) >> 6 \ + : ((id) & 0x300) >> 8) +#define SUBID_9005_SEEPTYPE_NONE 0x0 +#define SUBID_9005_SEEPTYPE_1K 0x1 +#define SUBID_9005_SEEPTYPE_2K_4K 0x2 +#define SUBID_9005_SEEPTYPE_RESERVED 0x3 +#define SUBID_9005_AUTOTERM(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? (((id) & 0x400) >> 10) == 0 \ + : (((id) & 0x40) >> 6) == 0) + +#define SUBID_9005_NUMCHAN(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? ((id) & 0x300) >> 8 \ + : ((id) & 0xC00) >> 10) + +#define SUBID_9005_LEGACYCONN(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? 0 \ + : ((id) & 0x80) >> 7) + +#define SUBID_9005_MFUNCENB(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? ((id) & 0x800) >> 11 \ + : ((id) & 0x1000) >> 12) +/* + * Informational only. Should use chip register to be + * ceratian, but may be use in identification strings. + */ +#define SUBID_9005_CARD_SCSIWIDTH_MASK 0x2000 +#define SUBID_9005_CARD_PCIWIDTH_MASK 0x4000 +#define SUBID_9005_CARD_SEDIFF_MASK 0x8000 + +static ahc_device_setup_t ahc_aic785X_setup; +static ahc_device_setup_t ahc_aic7860_setup; +static ahc_device_setup_t ahc_apa1480_setup; +static ahc_device_setup_t ahc_aic7870_setup; +static ahc_device_setup_t ahc_aha394X_setup; +static ahc_device_setup_t ahc_aha494X_setup; +static ahc_device_setup_t ahc_aha398X_setup; +static ahc_device_setup_t ahc_aic7880_setup; +static ahc_device_setup_t ahc_aha2940Pro_setup; +static ahc_device_setup_t ahc_aha394XU_setup; +static ahc_device_setup_t ahc_aha398XU_setup; +static ahc_device_setup_t ahc_aic7890_setup; +static ahc_device_setup_t ahc_aic7892_setup; +static ahc_device_setup_t ahc_aic7895_setup; +static ahc_device_setup_t ahc_aic7896_setup; +static ahc_device_setup_t ahc_aic7899_setup; +static ahc_device_setup_t ahc_aha29160C_setup; +static ahc_device_setup_t ahc_raid_setup; +static ahc_device_setup_t ahc_aha394XX_setup; +static ahc_device_setup_t ahc_aha494XX_setup; +static ahc_device_setup_t ahc_aha398XX_setup; + +struct ahc_pci_identity ahc_pci_ident_table [] = +{ + /* aic7850 based controllers */ + { + ID_AHA_2902_04_10_15_20_30C, + ID_ALL_MASK, + "Adaptec 2902/04/10/15/20/30C SCSI adapter", + ahc_aic785X_setup + }, + /* aic7860 based controllers */ + { + ID_AHA_2930CU, + ID_ALL_MASK, + "Adaptec 2930CU SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AHA_1480A & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 1480A Ultra SCSI adapter", + ahc_apa1480_setup + }, + { + ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940A Ultra SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940A/CN Ultra SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2930C SCSI adapter (VAR)", + ahc_aic7860_setup + }, + /* aic7870 based controllers */ + { + ID_AHA_2940, + ID_ALL_MASK, + "Adaptec 2940 SCSI adapter", + ahc_aic7870_setup + }, + { + ID_AHA_3940, + ID_ALL_MASK, + "Adaptec 3940 SCSI adapter", + ahc_aha394X_setup + }, + { + ID_AHA_398X, + ID_ALL_MASK, + "Adaptec 398X SCSI RAID adapter", + ahc_aha398X_setup + }, + { + ID_AHA_2944, + ID_ALL_MASK, + "Adaptec 2944 SCSI adapter", + ahc_aic7870_setup + }, + { + ID_AHA_3944, + ID_ALL_MASK, + "Adaptec 3944 SCSI adapter", + ahc_aha394X_setup + }, + { + ID_AHA_4944, + ID_ALL_MASK, + "Adaptec 4944 SCSI adapter", + ahc_aha494X_setup + }, + /* aic7880 based controllers */ + { + ID_AHA_2940U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AHA_3940U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 3940 Ultra SCSI adapter", + ahc_aha394XU_setup + }, + { + ID_AHA_2944U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2944 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AHA_3944U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 3944 Ultra SCSI adapter", + ahc_aha394XU_setup + }, + { + ID_AHA_398XU & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 398X Ultra SCSI RAID adapter", + ahc_aha398XU_setup + }, + { + /* + * XXX Don't know the slot numbers + * so we can't identify channels + */ + ID_AHA_4944U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 4944 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AHA_2930U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2930 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940 Pro Ultra SCSI adapter", + ahc_aha2940Pro_setup + }, + { + ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940/CN Ultra SCSI adapter", + ahc_aic7880_setup + }, + /* Ignore all SISL (AAC on MB) based controllers. */ + { + ID_9005_SISL_ID, + ID_9005_SISL_MASK, + NULL, + NULL + }, + /* aic7890 based controllers */ + { + ID_AHA_2930U2, + ID_ALL_MASK, + "Adaptec 2930 Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AHA_2940U2B, + ID_ALL_MASK, + "Adaptec 2940B Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AHA_2940U2_OEM, + ID_ALL_MASK, + "Adaptec 2940 Ultra2 SCSI adapter (OEM)", + ahc_aic7890_setup + }, + { + ID_AHA_2940U2, + ID_ALL_MASK, + "Adaptec 2940 Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AHA_2950U2B, + ID_ALL_MASK, + "Adaptec 2950 Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AIC7890_ARO, + ID_ALL_MASK, + "Adaptec aic7890/91 Ultra2 SCSI adapter (ARO)", + ahc_aic7890_setup + }, + { + ID_AAA_131U2, + ID_ALL_MASK, + "Adaptec AAA-131 Ultra2 RAID adapter", + ahc_aic7890_setup + }, + /* aic7892 based controllers */ + { + ID_AHA_29160, + ID_ALL_MASK, + "Adaptec 29160 Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AHA_29160_CPQ, + ID_ALL_MASK, + "Adaptec (Compaq OEM) 29160 Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AHA_29160N, + ID_ALL_MASK, + "Adaptec 29160N Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AHA_29160C, + ID_ALL_MASK, + "Adaptec 29160C Ultra160 SCSI adapter", + ahc_aha29160C_setup + }, + { + ID_AHA_29160B, + ID_ALL_MASK, + "Adaptec 29160B Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AHA_19160B, + ID_ALL_MASK, + "Adaptec 19160B Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AIC7892_ARO, + ID_ALL_MASK, + "Adaptec aic7892 Ultra2 SCSI adapter (ARO)", + ahc_aic7892_setup + }, + /* aic7895 based controllers */ + { + ID_AHA_2940U_DUAL, + ID_ALL_MASK, + "Adaptec 2940/DUAL Ultra SCSI adapter", + ahc_aic7895_setup + }, + { + ID_AHA_3940AU, + ID_ALL_MASK, + "Adaptec 3940A Ultra SCSI adapter", + ahc_aic7895_setup + }, + { + ID_AHA_3944AU, + ID_ALL_MASK, + "Adaptec 3944A Ultra SCSI adapter", + ahc_aic7895_setup + }, + { + ID_AIC7895_ARO, + ID_AIC7895_ARO_MASK, + "Adaptec aic7895 Ultra SCSI adapter (ARO)", + ahc_aic7895_setup + }, + /* aic7896/97 based controllers */ + { + ID_AHA_3950U2B_0, + ID_ALL_MASK, + "Adaptec 3950B Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AHA_3950U2B_1, + ID_ALL_MASK, + "Adaptec 3950B Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AHA_3950U2D_0, + ID_ALL_MASK, + "Adaptec 3950D Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AHA_3950U2D_1, + ID_ALL_MASK, + "Adaptec 3950D Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AIC7896_ARO, + ID_ALL_MASK, + "Adaptec aic7896/97 Ultra2 SCSI adapter (ARO)", + ahc_aic7896_setup + }, + /* aic7899 based controllers */ + { + ID_AHA_3960D, + ID_ALL_MASK, + "Adaptec 3960D Ultra160 SCSI adapter", + ahc_aic7899_setup + }, + { + ID_AHA_3960D_CPQ, + ID_ALL_MASK, + "Adaptec (Compaq OEM) 3960D Ultra160 SCSI adapter", + ahc_aic7899_setup + }, + { + ID_AIC7899_ARO, + ID_ALL_MASK, + "Adaptec aic7899 Ultra160 SCSI adapter (ARO)", + ahc_aic7899_setup + }, + /* Generic chip probes for devices we don't know 'exactly' */ + { + ID_AIC7850 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7850 SCSI adapter", + ahc_aic785X_setup + }, + { + ID_AIC7855 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7855 SCSI adapter", + ahc_aic785X_setup + }, + { + ID_AIC7859 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7859 Ultra SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AIC7860 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7860 SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AIC7870 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7870 SCSI adapter", + ahc_aic7870_setup + }, + { + ID_AIC7880 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7880 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AIC7890 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + "Adaptec aic7890/91 Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AIC7892 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + "Adaptec aic7892 Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AIC7895 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7895 Ultra SCSI adapter", + ahc_aic7895_setup + }, + { + ID_AIC7896 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + "Adaptec aic7896/97 Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AIC7899 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + "Adaptec aic7899 Ultra160 SCSI adapter", + ahc_aic7899_setup + }, + { + ID_AIC7810 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7810 RAID memory controller", + ahc_raid_setup + }, + { + ID_AIC7815 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7815 RAID memory controller", + ahc_raid_setup + } +}; + +const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table); + +#define AHC_394X_SLOT_CHANNEL_A 4 +#define AHC_394X_SLOT_CHANNEL_B 5 + +#define AHC_398X_SLOT_CHANNEL_A 4 +#define AHC_398X_SLOT_CHANNEL_B 8 +#define AHC_398X_SLOT_CHANNEL_C 12 + +#define AHC_494X_SLOT_CHANNEL_A 4 +#define AHC_494X_SLOT_CHANNEL_B 5 +#define AHC_494X_SLOT_CHANNEL_C 6 +#define AHC_494X_SLOT_CHANNEL_D 7 + +#define DEVCONFIG 0x40 +#define SCBSIZE32 0x00010000ul /* aic789X only */ +#define REXTVALID 0x00001000ul /* ultra cards only */ +#define MPORTMODE 0x00000400ul /* aic7870 only */ +#define RAMPSM 0x00000200ul /* aic7870 only */ +#define VOLSENSE 0x00000100ul +#define SCBRAMSEL 0x00000080ul +#define MRDCEN 0x00000040ul +#define EXTSCBTIME 0x00000020ul /* aic7870 only */ +#define EXTSCBPEN 0x00000010ul /* aic7870 only */ +#define BERREN 0x00000008ul +#define DACEN 0x00000004ul +#define STPWLEVEL 0x00000002ul +#define DIFACTNEGEN 0x00000001ul /* aic7870 only */ + +#define CSIZE_LATTIME 0x0c +#define CACHESIZE 0x0000003ful /* only 5 bits */ +#define LATTIME 0x0000ff00ul + +typedef enum +{ + AHC_POWER_STATE_D0, + AHC_POWER_STATE_D1, + AHC_POWER_STATE_D2, + AHC_POWER_STATE_D3 +} ahc_power_state; + +static void ahc_power_state_change(struct ahc_softc *ahc, + ahc_power_state new_state); +static int ahc_ext_scbram_present(struct ahc_softc *ahc); +static void ahc_scbram_config(struct ahc_softc *ahc, int enable, + int pcheck, int fast, int large); +static void ahc_probe_ext_scbram(struct ahc_softc *ahc); +static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1); +static void configure_termination(struct ahc_softc *ahc, + struct seeprom_descriptor *sd, + u_int adapter_control, + u_int *sxfrctl1); + +static void ahc_new_term_detect(struct ahc_softc *ahc, + int *enableSEC_low, + int *enableSEC_high, + int *enablePRI_low, + int *enablePRI_high, + int *eeprom_present); +static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present, + int *internal68_present, + int *externalcable_present, + int *eeprom_present); +static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, + int *externalcable_present, + int *eeprom_present); +static int acquire_seeprom(struct ahc_softc *ahc, + struct seeprom_descriptor *sd); +static void release_seeprom(struct seeprom_descriptor *sd); +static void write_brdctl(struct ahc_softc *ahc, uint8_t value); +static uint8_t read_brdctl(struct ahc_softc *ahc); + +struct ahc_pci_identity * +ahc_find_pci_device(ahc_dev_softc_t pci) +{ + uint64_t full_id; + uint16_t device; + uint16_t vendor; + uint16_t subdevice; + uint16_t subvendor; + struct ahc_pci_identity *entry; + u_int i; + + vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); + device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); + subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); + subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); + full_id = ahc_compose_id(device, + vendor, + subdevice, + subvendor); + + /* If the second function is not hooked up, ignore it. */ + if (ahc_get_pci_function(pci) > 0 + && subvendor == 0x9005 + && SUBID_9005_TYPE_KNOWN(subdevice) != 0 + && SUBID_9005_MFUNCENB(subdevice) == 0) + return (NULL); + + for (i = 0; i < ahc_num_pci_devs; i++) { + entry = &ahc_pci_ident_table[i]; + if (entry->full_id == (full_id & entry->id_mask)) { + /* Honor exclusion entries. */ + if (entry->name == NULL) + return (NULL); + return (entry); + } + } + return (NULL); +} + +int +ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) +{ + struct ahc_probe_config probe_config; + struct scb_data *shared_scb_data; + u_int command; + u_int our_id = 0; + u_int sxfrctl1; + u_int scsiseq; + u_int dscommand0; + int error; + uint8_t sblkctl; + + shared_scb_data = NULL; + ahc_init_probe_config(&probe_config); + error = entry->setup(ahc->dev_softc, &probe_config); + if (error != 0) + return (error); + probe_config.chip |= AHC_PCI; + probe_config.description = entry->name; + + error = ahc_pci_map_registers(ahc); + if (error != 0) + return (error); + + ahc_power_state_change(ahc, AHC_POWER_STATE_D0); + + /* Ensure busmastering is enabled */ + command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); + command |= PCIM_CMD_BUSMASTEREN; + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1); + + /* On all PCI adapters, we allow SCB paging */ + probe_config.flags |= AHC_PAGESCBS; + + error = ahc_softc_init(ahc, &probe_config); + if (error != 0) + return (error); + + /* Remeber how the card was setup in case there is no SEEPROM */ + if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { + pause_sequencer(ahc); + if ((ahc->features & AHC_ULTRA2) != 0) + our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; + else + our_id = ahc_inb(ahc, SCSIID) & OID; + sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN; + scsiseq = ahc_inb(ahc, SCSISEQ); + } else { + sxfrctl1 = STPWEN; + our_id = 7; + scsiseq = 0; + } + + error = ahc_reset(ahc); + if (error != 0) + return (ENXIO); + + if ((ahc->features & AHC_DT) != 0) { + u_int sfunct; + + /* Perform ALT-Mode Setup */ + sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; + ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); + ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS); + ahc_outb(ahc, SFUNCT, sfunct); + + /* Normal mode setup */ + ahc_outb(ahc, CRCCONTROL1, CRCVALCHKEN|CRCENDCHKEN|CRCREQCHKEN + |TARGCRCENDEN); + } + + error = ahc_pci_map_int(ahc); + if (error != 0) + return (error); + dscommand0 = ahc_inb(ahc, DSCOMMAND0); + dscommand0 |= MPARCKEN|CACHETHEN; + if ((ahc->features & AHC_ULTRA2) != 0) { + + /* + * DPARCKEN doesn't work correctly on + * some MBs so don't use it. + */ + dscommand0 &= ~DPARCKEN; + } + + /* + * Handle chips that must have cache line + * streaming (dis/en)abled. + */ + if ((ahc->bugs & AHC_CACHETHEN_DIS_BUG) != 0) + dscommand0 |= CACHETHEN; + + if ((ahc->bugs & AHC_CACHETHEN_BUG) != 0) + dscommand0 &= ~CACHETHEN; + + ahc_outb(ahc, DSCOMMAND0, dscommand0); + + ahc->pci_cachesize = + ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, + /*bytes*/1) & CACHESIZE; + ahc->pci_cachesize *= 4; + + /* See if we have a SEEPROM and perform auto-term */ + check_extport(ahc, &sxfrctl1); + + /* + * Take the LED out of diagnostic mode + */ + sblkctl = ahc_inb(ahc, SBLKCTL); + ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON))); + + if ((ahc->features & AHC_ULTRA2) != 0) { + ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_MAX|WR_DFTHRSH_MAX); + } else { + ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100); + } + + if (ahc->flags & AHC_USEDEFAULTS) { + /* + * PCI Adapter default setup + * Should only be used if the adapter does not have + * a SEEPROM. + */ + /* See if someone else set us up already */ + if (scsiseq != 0) { + printf("%s: Using left over BIOS settings\n", + ahc_name(ahc)); + ahc->flags &= ~AHC_USEDEFAULTS; + ahc->flags |= AHC_BIOS_ENABLED; + } else { + /* + * Assume only one connector and always turn + * on termination. + */ + our_id = 0x07; + sxfrctl1 = STPWEN; + } + ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI); + + ahc->our_id = our_id; + } + + /* + * Take a look to see if we have external SRAM. + * We currently do not attempt to use SRAM that is + * shared among multiple controllers. + */ + ahc_probe_ext_scbram(ahc); + + /* + * Record our termination setting for the + * generic initialization routine. + */ + if ((sxfrctl1 & STPWEN) != 0) + ahc->flags |= AHC_TERM_ENB_A; + + /* + * We cannot perform ULTRA speeds without + * the presense of the external precision + * resistor. + */ + if ((ahc->features & AHC_ULTRA) != 0) { + uint32_t devconfig; + + devconfig = ahc_pci_read_config(ahc->dev_softc, + DEVCONFIG, /*bytes*/4); + if ((devconfig & REXTVALID) == 0) + ahc->flags |= AHC_ULTRA_DISABLED; + } + + /* Core initialization */ + error = ahc_init(ahc); + if (error != 0) + return (error); + + /* + * Link this softc in with all other ahc instances. + */ + ahc_softc_insert(ahc); + + return (0); +} + +static void +ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) +{ + uint32_t cap; + u_int cap_offset; + + /* + * Traverse the capability list looking for + * the power management capability. + */ + cap = 0; + cap_offset = ahc_pci_read_config(ahc->dev_softc, + PCIR_CAP_PTR, /*bytes*/1); + while (cap_offset != 0) { + + cap = ahc_pci_read_config(ahc->dev_softc, + cap_offset, /*bytes*/4); + if ((cap & 0xFF) == 1 + && ((cap >> 16) & 0x3) > 0) { + uint32_t pm_control; + + pm_control = ahc_pci_read_config(ahc->dev_softc, + cap_offset + 4, + /*bytes*/4); + pm_control &= ~0x3; + pm_control |= new_state; + ahc_pci_write_config(ahc->dev_softc, + cap_offset + 4, + pm_control, /*bytes*/2); + break; + } + cap_offset = (cap >> 8) & 0xFF; + } +} + +/* + * Test for the presense of external sram in an + * "unshared" configuration. + */ +static int +ahc_ext_scbram_present(struct ahc_softc *ahc) +{ + u_int chip; + int ramps; + int single_user; + uint32_t devconfig; + + chip = ahc->chip & AHC_CHIPID_MASK; + devconfig = ahc_pci_read_config(ahc->dev_softc, + DEVCONFIG, /*bytes*/4); + single_user = (devconfig & MPORTMODE) != 0; + + if ((ahc->features & AHC_ULTRA2) != 0) + ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0; + else if (chip >= AHC_AIC7870) + ramps = (devconfig & RAMPSM) != 0; + else + ramps = 0; + + if (ramps && single_user) + return (1); + return (0); +} + +/* + * Enable external scbram. + */ +static void +ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, + int fast, int large) +{ + uint32_t devconfig; + + if (ahc->features & AHC_MULTI_FUNC) { + /* + * Set the SCB Base addr (highest address bit) + * depending on which channel we are. + */ + ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc)); + } + + devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); + if ((ahc->features & AHC_ULTRA2) != 0) { + u_int dscommand0; + + dscommand0 = ahc_inb(ahc, DSCOMMAND0); + if (enable) + dscommand0 &= ~INTSCBRAMSEL; + else + dscommand0 |= INTSCBRAMSEL; + if (large) + dscommand0 &= ~USCBSIZE32; + else + dscommand0 |= USCBSIZE32; + ahc_outb(ahc, DSCOMMAND0, dscommand0); + } else { + if (fast) + devconfig &= ~EXTSCBTIME; + else + devconfig |= EXTSCBTIME; + if (enable) + devconfig &= ~SCBRAMSEL; + else + devconfig |= SCBRAMSEL; + if (large) + devconfig &= ~SCBSIZE32; + else + devconfig |= SCBSIZE32; + } + if (pcheck) + devconfig |= EXTSCBPEN; + else + devconfig &= ~EXTSCBPEN; + + ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); +} + +/* + * Take a look to see if we have external SRAM. + * We currently do not attempt to use SRAM that is + * shared among multiple controllers. + */ +static void +ahc_probe_ext_scbram(struct ahc_softc *ahc) +{ + int num_scbs; + int test_num_scbs; + int enable; + int pcheck; + int fast; + int large; + + enable = FALSE; + pcheck = FALSE; + fast = FALSE; + large = FALSE; + num_scbs = 0; + + if (ahc_ext_scbram_present(ahc) == 0) + goto done; + + /* + * Probe for the best parameters to use. + */ + ahc_scbram_config(ahc, /*enable*/TRUE, pcheck, fast, large); + num_scbs = ahc_probe_scbs(ahc); + if (num_scbs == 0) { + /* The SRAM wasn't really present. */ + goto done; + } + enable = TRUE; + + /* + * Clear any outstanding parity error + * and ensure that parity error reporting + * is enabled. + */ + ahc_outb(ahc, SEQCTL, 0); + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, CLRINT, CLRBRKADRINT); + + /* Now see if we can do parity */ + ahc_scbram_config(ahc, enable, /*pcheck*/TRUE, fast, large); + num_scbs = ahc_probe_scbs(ahc); + if ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0 + || (ahc_inb(ahc, ERROR) & MPARERR) == 0) + pcheck = TRUE; + + /* Clear any resulting parity error */ + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, CLRINT, CLRBRKADRINT); + + /* Now see if we can do fast timing */ + ahc_scbram_config(ahc, enable, pcheck, /*fast*/TRUE, large); + test_num_scbs = ahc_probe_scbs(ahc); + if (test_num_scbs == num_scbs + && ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0 + || (ahc_inb(ahc, ERROR) & MPARERR) == 0)) + fast = TRUE; + + /* + * See if we can use large SCBs and still maintain + * the same overall count of SCBs. + */ + if ((ahc->features & AHC_LARGE_SCBS) != 0) { + ahc_scbram_config(ahc, enable, pcheck, fast, /*large*/TRUE); + test_num_scbs = ahc_probe_scbs(ahc); + if (test_num_scbs >= num_scbs) { + large = TRUE; + num_scbs = test_num_scbs; + if (num_scbs >= 64) { + /* + * We have enough space to move the + * "busy targets table" into SCB space + * and make it qualify all the way to the + * lun level. + */ + ahc->flags |= AHC_SCB_BTT; + } + } + } +done: + /* + * Disable parity error reporting until we + * can load instruction ram. + */ + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); + /* Clear any latched parity error */ + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, CLRINT, CLRBRKADRINT); + if (bootverbose && enable) { + printf("%s: External SRAM, %s access%s, %dbytes/SCB\n", + ahc_name(ahc), fast ? "fast" : "slow", + pcheck ? ", parity checking enabled" : "", + large ? 64 : 32); + } + ahc_scbram_config(ahc, enable, pcheck, fast, large); +} + +/* + * Check the external port logic for a serial eeprom + * and termination/cable detection contrls. + */ +static void +check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) +{ + struct seeprom_descriptor sd; + struct seeprom_config sc; + u_int scsi_conf; + u_int adapter_control; + int have_seeprom; + int have_autoterm; + + sd.sd_ahc = ahc; + sd.sd_control_offset = SEECTL; + sd.sd_status_offset = SEECTL; + sd.sd_dataout_offset = SEECTL; + + /* + * For some multi-channel devices, the c46 is simply too + * small to work. For the other controller types, we can + * get our information from either SEEPROM type. Set the + * type to start our probe with accordingly. + */ + if (ahc->flags & AHC_LARGE_SEEPROM) + sd.sd_chip = C56_66; + else + sd.sd_chip = C46; + + sd.sd_MS = SEEMS; + sd.sd_RDY = SEERDY; + sd.sd_CS = SEECS; + sd.sd_CK = SEECK; + sd.sd_DO = SEEDO; + sd.sd_DI = SEEDI; + + have_seeprom = acquire_seeprom(ahc, &sd); + if (have_seeprom) { + + if (bootverbose) + printf("%s: Reading SEEPROM...", ahc_name(ahc)); + + for (;;) { + u_int start_addr; + + start_addr = 32 * (ahc->channel - 'A'); + + have_seeprom = read_seeprom(&sd, (uint16_t *)&sc, + start_addr, sizeof(sc)/2); + + if (have_seeprom) + have_seeprom = verify_cksum(&sc); + + if (have_seeprom != 0 || sd.sd_chip == C56_66) { + if (bootverbose) { + if (have_seeprom == 0) + printf ("checksum error\n"); + else + printf ("done.\n"); + } + break; + } + sd.sd_chip = C56_66; + } + } + +#if 0 + if (!have_seeprom) { + /* + * Pull scratch ram settings and treat them as + * if they are the contents of an seeprom if + * the 'ADPT' signature is found in SCB2. + */ + ahc_outb(ahc, SCBPTR, 2); + if (ahc_inb(ahc, SCB_BASE) == 'A' + && ahc_inb(ahc, SCB_BASE + 1) == 'D' + && ahc_inb(ahc, SCB_BASE + 2) == 'P' + && ahc_inb(ahc, SCB_BASE + 3) == 'T') { + uint8_t *sc_bytes; + int i; + + sc_bytes = (uint8_t *)≻ + for (i = 0; i < 64; i++) + sc_bytes[i] = ahc_inb(ahc, TARG_SCSIRATE + i); + /* Byte 0x1c is stored in byte 4 of SCB2 */ + sc_bytes[0x1c] = ahc_inb(ahc, SCB_BASE + 4); + have_seeprom = verify_cksum(&sc); + } + } +#endif + + if (!have_seeprom) { + if (bootverbose) + printf("%s: No SEEPROM available.\n", ahc_name(ahc)); + ahc->flags |= AHC_USEDEFAULTS; + } else { + /* + * Put the data we've collected down into SRAM + * where ahc_init will find it. + */ + int i; + int max_targ = sc.max_targets & CFMAXTARG; + uint16_t discenable; + uint16_t ultraenb; + + discenable = 0; + ultraenb = 0; + if ((sc.adapter_control & CFULTRAEN) != 0) { + /* + * Determine if this adapter has a "newstyle" + * SEEPROM format. + */ + for (i = 0; i < max_targ; i++) { + if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0){ + ahc->flags |= AHC_NEWEEPROM_FMT; + break; + } + } + } + + for (i = 0; i < max_targ; i++) { + u_int scsirate; + uint16_t target_mask; + + target_mask = 0x01 << i; + if (sc.device_flags[i] & CFDISC) + discenable |= target_mask; + if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) { + if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0) + ultraenb |= target_mask; + } else if ((sc.adapter_control & CFULTRAEN) != 0) { + ultraenb |= target_mask; + } + if ((sc.device_flags[i] & CFXFER) == 0x04 + && (ultraenb & target_mask) != 0) { + /* Treat 10MHz as a non-ultra speed */ + sc.device_flags[i] &= ~CFXFER; + ultraenb &= ~target_mask; + } + if ((ahc->features & AHC_ULTRA2) != 0) { + u_int offset; + + if (sc.device_flags[i] & CFSYNCH) + offset = MAX_OFFSET_ULTRA2; + else + offset = 0; + ahc_outb(ahc, TARG_OFFSET + i, offset); + + /* + * The ultra enable bits contain the + * high bit of the ultra2 sync rate + * field. + */ + scsirate = (sc.device_flags[i] & CFXFER) + | ((ultraenb & target_mask) + ? 0x8 : 0x0); + if (sc.device_flags[i] & CFWIDEB) + scsirate |= WIDEXFER; + } else { + scsirate = (sc.device_flags[i] & CFXFER) << 4; + if (sc.device_flags[i] & CFSYNCH) + scsirate |= SOFS; + if (sc.device_flags[i] & CFWIDEB) + scsirate |= WIDEXFER; + } + ahc_outb(ahc, TARG_SCSIRATE + i, scsirate); + } + ahc->our_id = sc.brtime_id & CFSCSIID; + + scsi_conf = (ahc->our_id & 0x7); + if (sc.adapter_control & CFSPARITY) + scsi_conf |= ENSPCHK; + if (sc.adapter_control & CFRESETB) + scsi_conf |= RESET_SCSI; + + if ((sc.adapter_control & CFCHNLBPRIMARY) != 0 + && (ahc->features & AHC_MULTI_FUNC) != 0) + ahc->flags |= AHC_CHANNEL_B_PRIMARY; + + if (sc.bios_control & CFEXTEND) + ahc->flags |= AHC_EXTENDED_TRANS_A; + + if (sc.bios_control & CFBIOSEN) + ahc->flags |= AHC_BIOS_ENABLED; + if (ahc->features & AHC_ULTRA + && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) { + /* Should we enable Ultra mode? */ + if (!(sc.adapter_control & CFULTRAEN)) + /* Treat us as a non-ultra card */ + ultraenb = 0; + } + + if (sc.signature == CFSIGNATURE) { + uint32_t devconfig; + + /* Honor the STPWLEVEL settings */ + devconfig = ahc_pci_read_config(ahc->dev_softc, + DEVCONFIG, /*bytes*/4); + devconfig &= ~STPWLEVEL; + if ((sc.bios_control & CFSTPWLEVEL) != 0) + devconfig |= STPWLEVEL; + ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, + devconfig, /*bytes*/4); + } + /* Set SCSICONF info */ + ahc_outb(ahc, SCSICONF, scsi_conf); + ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); + ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); + ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff); + ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff); + } + + /* + * Cards that have the external logic necessary to talk to + * a SEEPROM, are almost certain to have the remaining logic + * necessary for auto-termination control. This assumption + * hasn't failed yet... + */ + have_autoterm = have_seeprom; + if (have_seeprom) + adapter_control = sc.adapter_control; + else + adapter_control = CFAUTOTERM; + + /* + * Some low-cost chips have SEEPROM and auto-term control built + * in, instead of using a GAL. They can tell us directly + * if the termination logic is enabled. + */ + if ((ahc->features & AHC_SPIOCAP) != 0) { + if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) != 0) + have_autoterm = TRUE; + else + have_autoterm = FALSE; + } + + if (have_autoterm) + configure_termination(ahc, &sd, adapter_control, sxfrctl1); + + release_seeprom(&sd); +} + +static void +configure_termination(struct ahc_softc *ahc, + struct seeprom_descriptor *sd, + u_int adapter_control, + u_int *sxfrctl1) +{ + uint8_t brddat; + + brddat = 0; + + /* + * Update the settings in sxfrctl1 to match the + * termination settings + */ + *sxfrctl1 = 0; + + /* + * SEECS must be on for the GALS to latch + * the data properly. Be sure to leave MS + * on or we will release the seeprom. + */ + SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS); + if ((adapter_control & CFAUTOTERM) != 0 + || (ahc->features & AHC_NEW_TERMCTL) != 0) { + int internal50_present; + int internal68_present; + int externalcable_present; + int eeprom_present; + int enableSEC_low; + int enableSEC_high; + int enablePRI_low; + int enablePRI_high; + int sum; + + enableSEC_low = 0; + enableSEC_high = 0; + enablePRI_low = 0; + enablePRI_high = 0; + if ((ahc->features & AHC_NEW_TERMCTL) != 0) { + ahc_new_term_detect(ahc, &enableSEC_low, + &enableSEC_high, + &enablePRI_low, + &enablePRI_high, + &eeprom_present); + if ((adapter_control & CFSEAUTOTERM) == 0) { + if (bootverbose) + printf("%s: Manual SE Termination\n", + ahc_name(ahc)); + enableSEC_low = (adapter_control & CFSELOWTERM); + enableSEC_high = + (adapter_control & CFSEHIGHTERM); + } + if ((adapter_control & CFAUTOTERM) == 0) { + if (bootverbose) + printf("%s: Manual LVD Termination\n", + ahc_name(ahc)); + enablePRI_low = (adapter_control & CFSTERM); + enablePRI_high = (adapter_control & CFWSTERM); + } + /* Make the table calculations below happy */ + internal50_present = 0; + internal68_present = 1; + externalcable_present = 1; + } else if ((ahc->features & AHC_SPIOCAP) != 0) { + aic785X_cable_detect(ahc, &internal50_present, + &externalcable_present, + &eeprom_present); + } else { + aic787X_cable_detect(ahc, &internal50_present, + &internal68_present, + &externalcable_present, + &eeprom_present); + } + + if ((ahc->features & AHC_WIDE) == 0) + internal68_present = 0; + + if (bootverbose + && (ahc->features & AHC_ULTRA2) == 0) { + printf("%s: internal 50 cable %s present", + ahc_name(ahc), + internal50_present ? "is":"not"); + + if ((ahc->features & AHC_WIDE) != 0) + printf(", internal 68 cable %s present", + internal68_present ? "is":"not"); + printf("\n%s: external cable %s present\n", + ahc_name(ahc), + externalcable_present ? "is":"not"); + } + if (bootverbose) + printf("%s: BIOS eeprom %s present\n", + ahc_name(ahc), eeprom_present ? "is" : "not"); + + if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) { + /* + * The 50 pin connector is a separate bus, + * so force it to always be terminated. + * In the future, perform current sensing + * to determine if we are in the middle of + * a properly terminated bus. + */ + internal50_present = 0; + } + + /* + * Now set the termination based on what + * we found. + * Flash Enable = BRDDAT7 + * Secondary High Term Enable = BRDDAT6 + * Secondary Low Term Enable = BRDDAT5 (7890) + * Primary High Term Enable = BRDDAT4 (7890) + */ + if ((ahc->features & AHC_ULTRA2) == 0 + && (internal50_present != 0) + && (internal68_present != 0) + && (externalcable_present != 0)) { + printf("%s: Illegal cable configuration!!. " + "Only two connectors on the " + "adapter may be used at a " + "time!\n", ahc_name(ahc)); + } + + if ((ahc->features & AHC_WIDE) != 0 + && ((externalcable_present == 0) + || (internal68_present == 0) + || (enableSEC_high != 0))) { + brddat |= BRDDAT6; + if (bootverbose) { + if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) + printf("%s: 68 pin termination " + "Enabled\n", ahc_name(ahc)); + else + printf("%s: %sHigh byte termination " + "Enabled\n", ahc_name(ahc), + enableSEC_high ? "Secondary " + : ""); + } + } + + sum = internal50_present + internal68_present + + externalcable_present; + if (sum < 2 || (enableSEC_low != 0)) { + if ((ahc->features & AHC_ULTRA2) != 0) + brddat |= BRDDAT5; + else + *sxfrctl1 |= STPWEN; + if (bootverbose) { + if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) + printf("%s: 50 pin termination " + "Enabled\n", ahc_name(ahc)); + else + printf("%s: %sLow byte termination " + "Enabled\n", ahc_name(ahc), + enableSEC_low ? "Secondary " + : ""); + } + } + + if (enablePRI_low != 0) { + *sxfrctl1 |= STPWEN; + if (bootverbose) + printf("%s: Primary Low Byte termination " + "Enabled\n", ahc_name(ahc)); + } + + /* + * Setup STPWEN before setting up the rest of + * the termination per the tech note on the U160 cards. + */ + ahc_outb(ahc, SXFRCTL1, *sxfrctl1); + + if (enablePRI_high != 0) { + brddat |= BRDDAT4; + if (bootverbose) + printf("%s: Primary High Byte " + "termination Enabled\n", + ahc_name(ahc)); + } + + write_brdctl(ahc, brddat); + + } else { + if ((adapter_control & CFSTERM) != 0) { + *sxfrctl1 |= STPWEN; + + if (bootverbose) + printf("%s: %sLow byte termination Enabled\n", + ahc_name(ahc), + (ahc->features & AHC_ULTRA2) ? "Primary " + : ""); + } + + if ((adapter_control & CFWSTERM) != 0 + && (ahc->features & AHC_WIDE) != 0) { + brddat |= BRDDAT6; + if (bootverbose) + printf("%s: %sHigh byte termination Enabled\n", + ahc_name(ahc), + (ahc->features & AHC_ULTRA2) + ? "Secondary " : ""); + } + + /* + * Setup STPWEN before setting up the rest of + * the termination per the tech note on the U160 cards. + */ + ahc_outb(ahc, SXFRCTL1, *sxfrctl1); + + if ((ahc->features & AHC_WIDE) != 0) + write_brdctl(ahc, brddat); + } + SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */ +} + +static void +ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low, + int *enableSEC_high, int *enablePRI_low, + int *enablePRI_high, int *eeprom_present) +{ + uint8_t brdctl; + + /* + * BRDDAT7 = Eeprom + * BRDDAT6 = Enable Secondary High Byte termination + * BRDDAT5 = Enable Secondary Low Byte termination + * BRDDAT4 = Enable Primary high byte termination + * BRDDAT3 = Enable Primary low byte termination + */ + brdctl = read_brdctl(ahc); + *eeprom_present = brdctl & BRDDAT7; + *enableSEC_high = (brdctl & BRDDAT6); + *enableSEC_low = (brdctl & BRDDAT5); + *enablePRI_high = (brdctl & BRDDAT4); + *enablePRI_low = (brdctl & BRDDAT3); +} + +static void +aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present, + int *internal68_present, int *externalcable_present, + int *eeprom_present) +{ + uint8_t brdctl; + + /* + * First read the status of our cables. + * Set the rom bank to 0 since the + * bank setting serves as a multiplexor + * for the cable detection logic. + * BRDDAT5 controls the bank switch. + */ + write_brdctl(ahc, 0); + + /* + * Now read the state of the internal + * connectors. BRDDAT6 is INT50 and + * BRDDAT7 is INT68. + */ + brdctl = read_brdctl(ahc); + *internal50_present = (brdctl & BRDDAT6) ? 0 : 1; + *internal68_present = (brdctl & BRDDAT7) ? 0 : 1; + + /* + * Set the rom bank to 1 and determine + * the other signals. + */ + write_brdctl(ahc, BRDDAT5); + + /* + * Now read the state of the external + * connectors. BRDDAT6 is EXT68 and + * BRDDAT7 is EPROMPS. + */ + brdctl = read_brdctl(ahc); + *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; + *eeprom_present = (brdctl & BRDDAT7) ? 1 : 0; +} + +static void +aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, + int *externalcable_present, int *eeprom_present) +{ + uint8_t brdctl; + + ahc_outb(ahc, BRDCTL, BRDRW|BRDCS); + ahc_outb(ahc, BRDCTL, 0); + brdctl = ahc_inb(ahc, BRDCTL); + *internal50_present = (brdctl & BRDDAT5) ? 0 : 1; + *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; + + *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0; +} + +static int +acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd) +{ + int wait; + + if ((ahc->features & AHC_SPIOCAP) != 0 + && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0) + return (0); + + /* + * Request access of the memory port. When access is + * granted, SEERDY will go high. We use a 1 second + * timeout which should be near 1 second more than + * is needed. Reason: after the chip reset, there + * should be no contention. + */ + SEEPROM_OUTB(sd, sd->sd_MS); + wait = 1000; /* 1 second timeout in msec */ + while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) { + ahc_delay(1000); /* delay 1 msec */ + } + if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) { + SEEPROM_OUTB(sd, 0); + return (0); + } + return(1); +} + +static void +release_seeprom(struct seeprom_descriptor *sd) +{ + /* Release access to the memory port and the serial EEPROM. */ + SEEPROM_OUTB(sd, 0); +} + +static void +write_brdctl(struct ahc_softc *ahc, uint8_t value) +{ + uint8_t brdctl; + + if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + brdctl = BRDSTB; + if (ahc->channel == 'B') + brdctl |= BRDCS; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + brdctl = 0; + } else { + brdctl = BRDSTB|BRDCS; + } + ahc_outb(ahc, BRDCTL, brdctl); + ahc_flush_device_writes(ahc); + brdctl |= value; + ahc_outb(ahc, BRDCTL, brdctl); + ahc_flush_device_writes(ahc); + if ((ahc->features & AHC_ULTRA2) != 0) + brdctl |= BRDSTB_ULTRA2; + else + brdctl &= ~BRDSTB; + ahc_outb(ahc, BRDCTL, brdctl); + ahc_flush_device_writes(ahc); + if ((ahc->features & AHC_ULTRA2) != 0) + brdctl = 0; + else + brdctl &= ~BRDCS; + ahc_outb(ahc, BRDCTL, brdctl); +} + +static uint8_t +read_brdctl(ahc) + struct ahc_softc *ahc; +{ + uint8_t brdctl; + uint8_t value; + + if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + brdctl = BRDRW; + if (ahc->channel == 'B') + brdctl |= BRDCS; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + brdctl = BRDRW_ULTRA2; + } else { + brdctl = BRDRW|BRDCS; + } + ahc_outb(ahc, BRDCTL, brdctl); + ahc_flush_device_writes(ahc); + value = ahc_inb(ahc, BRDCTL); + ahc_outb(ahc, BRDCTL, 0); + return (value); +} + +#define DPE 0x80 +#define SSE 0x40 +#define RMA 0x20 +#define RTA 0x10 +#define STA 0x08 +#define DPR 0x01 + +void +ahc_pci_intr(struct ahc_softc *ahc) +{ + u_int error; + u_int status1; + + error = ahc_inb(ahc, ERROR); + if ((error & PCIERRSTAT) == 0) + return; + + status1 = ahc_pci_read_config(ahc->dev_softc, + PCIR_STATUS + 1, /*bytes*/1); + + printf("%s: PCI error Interrupt at seqaddr = 0x%x\n", + ahc_name(ahc), + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); + + if (status1 & DPE) { + printf("%s: Data Parity Error Detected during address " + "or write data phase\n", ahc_name(ahc)); + } + if (status1 & SSE) { + printf("%s: Signal System Error Detected\n", ahc_name(ahc)); + } + if (status1 & RMA) { + printf("%s: Received a Master Abort\n", ahc_name(ahc)); + } + if (status1 & RTA) { + printf("%s: Received a Target Abort\n", ahc_name(ahc)); + } + if (status1 & STA) { + printf("%s: Signaled a Target Abort\n", ahc_name(ahc)); + } + if (status1 & DPR) { + printf("%s: Data Parity Error has been reported via PERR#\n", + ahc_name(ahc)); + } + if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) { + printf("%s: Latched PCIERR interrupt with " + "no status bits set\n", ahc_name(ahc)); + } + ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, + status1, /*bytes*/1); + + if (status1 & (DPR|RMA|RTA)) { + ahc_outb(ahc, CLRINT, CLRPARERR); + } + + unpause_sequencer(ahc); +} + +static int +ahc_aic785X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + uint8_t rev; + + probe_config->channel = 'A'; + probe_config->chip = AHC_AIC7850; + probe_config->features = AHC_AIC7850_FE; + probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG + | AHC_PCI_MWI_BUG; + rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + if (rev >= 1) + probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG; + return (0); +} + +static int +ahc_aic7860_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + uint8_t rev; + + probe_config->channel = 'A'; + probe_config->chip = AHC_AIC7860; + probe_config->features = AHC_AIC7860_FE; + probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG + | AHC_PCI_MWI_BUG; + rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + if (rev >= 1) + probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG; + return (0); +} + +static int +ahc_apa1480_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7860_setup(pci, probe_config); + if (error != 0) + return (error); + probe_config->features |= AHC_REMOVABLE; + return (0); +} + +static int +ahc_aic7870_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + probe_config->channel = 'A'; + probe_config->chip = AHC_AIC7870; + probe_config->features = AHC_AIC7870_FE; + probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG + | AHC_PCI_MWI_BUG; + return (0); +} + +static int +ahc_aha394X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7870_setup(pci, probe_config); + if (error == 0) + error = ahc_aha394XX_setup(pci, probe_config); + return (error); +} + +static int +ahc_aha398X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7870_setup(pci, probe_config); + if (error == 0) + error = ahc_aha398XX_setup(pci, probe_config); + return (error); +} + +static int +ahc_aha494X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7870_setup(pci, probe_config); + if (error == 0) + error = ahc_aha494XX_setup(pci, probe_config); + return (error); +} + +static int +ahc_aic7880_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + uint8_t rev; + + probe_config->channel = 'A'; + probe_config->chip = AHC_AIC7880; + probe_config->features = AHC_AIC7880_FE; + probe_config->bugs |= AHC_TMODE_WIDEODD_BUG; + rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + if (rev >= 1) { + probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG; + } else { + probe_config->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; + } + return (0); +} + +static int +ahc_aha2940Pro_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + int error; + + probe_config->flags |= AHC_INT50_SPEEDFLEX; + error = ahc_aic7880_setup(pci, probe_config); + return (0); +} + +static int +ahc_aha394XU_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7880_setup(pci, probe_config); + if (error == 0) + error = ahc_aha394XX_setup(pci, probe_config); + return (error); +} + +static int +ahc_aha398XU_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7880_setup(pci, probe_config); + if (error == 0) + error = ahc_aha398XX_setup(pci, probe_config); + return (error); +} + +static int +ahc_aic7890_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + uint8_t rev; + + probe_config->channel = 'A'; + probe_config->chip = AHC_AIC7890; + probe_config->features = AHC_AIC7890_FE; + probe_config->flags |= AHC_NEWEEPROM_FMT; + rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + if (rev == 0) + probe_config->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG; + return (0); +} + +static int +ahc_aic7892_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + probe_config->channel = 'A'; + probe_config->chip = AHC_AIC7892; + probe_config->features = AHC_AIC7892_FE; + probe_config->flags |= AHC_NEWEEPROM_FMT; + probe_config->bugs |= AHC_SCBCHAN_UPLOAD_BUG; + return (0); +} + +static int +ahc_aic7895_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + uint8_t rev; + + probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; + /* + * The 'C' revision of the aic7895 has a few additional features. + */ + rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + if (rev >= 4) { + probe_config->chip = AHC_AIC7895C; + probe_config->features = AHC_AIC7895C_FE; + } else { + u_int command; + + probe_config->chip = AHC_AIC7895; + probe_config->features = AHC_AIC7895_FE; + + /* + * The BIOS disables the use of MWI transactions + * since it does not have the MWI bug work around + * we have. Disabling MWI reduces performance, so + * turn it on again. + */ + command = ahc_pci_read_config(pci, PCIR_COMMAND, /*bytes*/1); + command |= PCIM_CMD_MWRICEN; + ahc_pci_write_config(pci, PCIR_COMMAND, command, /*bytes*/1); + probe_config->bugs |= AHC_PCI_MWI_BUG; + } + /* + * XXX Does CACHETHEN really not work??? What about PCI retry? + * on C level chips. Need to test, but for now, play it safe. + */ + probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG + | AHC_CACHETHEN_BUG; + +#if 0 + uint32_t devconfig; + + /* + * Cachesize must also be zero due to stray DAC + * problem when sitting behind some bridges. + */ + ahc_pci_write_config(pci, CSIZE_LATTIME, 0, /*bytes*/1); + devconfig = ahc_pci_read_config(pci, DEVCONFIG, /*bytes*/1); + devconfig |= MRDCEN; + ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1); +#endif + probe_config->flags |= AHC_NEWEEPROM_FMT; + return (0); +} + +static int +ahc_aic7896_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; + probe_config->chip = AHC_AIC7896; + probe_config->features = AHC_AIC7896_FE; + probe_config->flags |= AHC_NEWEEPROM_FMT; + probe_config->bugs |= AHC_CACHETHEN_DIS_BUG; + return (0); +} + +static int +ahc_aic7899_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; + probe_config->chip = AHC_AIC7899; + probe_config->features = AHC_AIC7899_FE; + probe_config->flags |= AHC_NEWEEPROM_FMT; + probe_config->bugs |= AHC_SCBCHAN_UPLOAD_BUG; + return (0); +} + +static int +ahc_aha29160C_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + int error; + + error = ahc_aic7899_setup(pci, probe_config); + if (error != 0) + return (error); + probe_config->features |= AHC_REMOVABLE; + return (0); +} + +static int +ahc_raid_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + printf("RAID functionality unsupported\n"); + return (ENXIO); +} + +static int +ahc_aha394XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + switch (ahc_get_pci_slot(pci)) { + case AHC_394X_SLOT_CHANNEL_A: + probe_config->channel = 'A'; + break; + case AHC_394X_SLOT_CHANNEL_B: + probe_config->channel = 'B'; + break; + default: + printf("adapter at unexpected slot %d\n" + "unable to map to a channel\n", + ahc_get_pci_slot(pci)); + probe_config->channel = 'A'; + } + return (0); +} + +static int +ahc_aha398XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + switch (ahc_get_pci_slot(pci)) { + case AHC_398X_SLOT_CHANNEL_A: + probe_config->channel = 'A'; + break; + case AHC_398X_SLOT_CHANNEL_B: + probe_config->channel = 'B'; + break; + case AHC_398X_SLOT_CHANNEL_C: + probe_config->channel = 'C'; + break; + default: + printf("adapter at unexpected slot %d\n" + "unable to map to a channel\n", + ahc_get_pci_slot(pci)); + probe_config->channel = 'A'; + break; + } + probe_config->flags |= AHC_LARGE_SEEPROM; + return (0); +} + +static int +ahc_aha494XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config) +{ + switch (ahc_get_pci_slot(pci)) { + case AHC_494X_SLOT_CHANNEL_A: + probe_config->channel = 'A'; + break; + case AHC_494X_SLOT_CHANNEL_B: + probe_config->channel = 'B'; + break; + case AHC_494X_SLOT_CHANNEL_C: + probe_config->channel = 'C'; + break; + case AHC_494X_SLOT_CHANNEL_D: + probe_config->channel = 'D'; + break; + default: + printf("adapter at unexpected slot %d\n" + "unable to map to a channel\n", + ahc_get_pci_slot(pci)); + probe_config->channel = 'A'; + } + probe_config->flags |= AHC_LARGE_SEEPROM; + return (0); +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c linux/drivers/scsi/aic7xxx/aic7xxx_proc.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_proc.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2000, 2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * String handling code courtesy of Gerard Roudier's + * sym driver. + * + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#7 $ + */ +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" + +static void copy_mem_info(struct info_str *info, char *data, int len); +static int copy_info(struct info_str *info, char *fmt, ...); +static u_int scsi_calc_syncsrate(u_int period_factor); +static void ahc_dump_target_state(struct ahc_softc *ahc, + struct info_str *info, + u_int our_id, char channel, + u_int target_id, u_int target_offset); +static void ahc_dump_device_state(struct info_str *info, + struct ahc_linux_device *dev); + +static void +copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->offset + info->length) + len = info->offset + info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + + if (info->pos < info->offset) { + off_t partial; + + partial = info->offset - info->pos; + data += partial; + info->pos += partial; + len -= partial; + } + + if (len > 0) { + memcpy(info->buffer, data, len); + info->pos += len; + info->buffer += len; + } +} + +static int +copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[256]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return (len); +} + +/* + * Table of syncrates that don't follow the "divisible by 4" + * rule. This table will be expanded in future SCSI specs. + */ +static struct { + u_int period_factor; + u_int period; /* in 10ths of ns */ +} scsi_syncrates[] = { + { 0x09, 125 }, /* FAST-80 */ + { 0x0a, 250 }, /* FAST-40 40MHz */ + { 0x0b, 303 }, /* FAST-40 33MHz */ + { 0x0c, 500 } /* FAST-20 */ +}; + +/* + * Return the frequency in kHz corresponding to the given + * sync period factor. + */ +static u_int +scsi_calc_syncsrate(u_int period_factor) +{ + int i; + int num_syncrates; + + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period_factor == scsi_syncrates[i].period_factor) { + /* Period in kHz */ + return (10000000 / scsi_syncrates[i].period); + } + } + + /* + * Wasn't in the table, so use the standard + * 4 times conversion. + */ + return (10000000 / (period_factor * 4 * 10)); +} + +void +ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo) +{ + u_int speed; + u_int freq; + u_int mb; + + speed = 3300; + freq = 0; + if (tinfo->offset != 0) { + freq = scsi_calc_syncsrate(tinfo->period); + speed = freq; + } + speed *= (0x01 << tinfo->width); + mb = speed / 1000; + if (mb > 0) + copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000); + else + copy_info(info, "%dKB/s transfers", speed); + + if (freq != 0) { + copy_info(info, " (%d.%03dMHz%s, offset %d", + freq / 1000, freq % 1000, + (tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0 + ? " DT" : "", tinfo->offset); + } + + if (tinfo->width > 0) { + if (freq != 0) { + copy_info(info, ", "); + } else { + copy_info(info, " ("); + } + copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width)); + } else if (freq != 0) { + copy_info(info, ")"); + } + copy_info(info, "\n"); +} + +static void +ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info, + u_int our_id, char channel, u_int target_id, + u_int target_offset) +{ + struct ahc_linux_target *targ; + struct ahc_initiator_tinfo *tinfo; + struct tmode_tstate *tstate; + int lun; + + tinfo = ahc_fetch_transinfo(ahc, channel, our_id, + target_id, &tstate); + copy_info(info, "Channel %c Target %d Negotiation Settings\n", + channel, target_id); + copy_info(info, "\tUser: "); + ahc_format_transinfo(info, &tinfo->user); + targ = ahc->platform_data->targets[target_offset]; + if (targ == NULL) + return; + + copy_info(info, "\tGoal: "); + ahc_format_transinfo(info, &tinfo->goal); + copy_info(info, "\tCurr: "); + ahc_format_transinfo(info, &tinfo->current); + + for (lun = 0; lun < AHC_NUM_LUNS; lun++) { + struct ahc_linux_device *dev; + + dev = targ->devices[lun]; + + if (dev == NULL) + continue; + + ahc_dump_device_state(info, dev); + } +} + +static void +ahc_dump_device_state(struct info_str *info, struct ahc_linux_device *dev) +{ + copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", + dev->target->channel + 'A', dev->target->target, dev->lun); + + copy_info(info, "\t\tCommands Queued %d\n", dev->num_commands); + copy_info(info, "\t\tCommands Active %d\n", dev->active); + copy_info(info, "\t\tCommand Openings %d\n", dev->openings); + copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags); + copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen); +} + +/* + * Return information to handle /proc support for the driver. + */ +int +aic7xxx_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + struct ahc_softc *ahc; + struct info_str info; + char ahc_info[256]; + u_int max_targ; + u_int i; + + TAILQ_FOREACH(ahc, &ahc_tailq, links) { + if (ahc->platform_data->host->host_no == hostno) + break; + } + + if (ahc == NULL) + return (-EINVAL); + + /* Has data been written to the file? */ + if (inout == TRUE) + return (-ENOSYS); + + if (start) + *start = buffer; + + info.buffer = buffer; + info.length = length; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "Adaptec AIC7xxx driver version: %s\n", + AIC7XXX_DRIVER_VERSION); + ahc_controller_info(ahc, ahc_info); + copy_info(&info, "%s\n", ahc_info); + + max_targ = 15; + if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) + max_targ = 7; + + for (i = 0; i <= max_targ; i++) { + u_int our_id; + u_int target_id; + char channel; + + channel = 'A'; + our_id = ahc->our_id; + target_id = i; + if (i > 7 && (ahc->features & AHC_TWIN) != 0) { + channel = 'B'; + our_id = ahc->our_id_b; + target_id = i % 8; + } + + ahc_dump_target_state(ahc, &info, our_id, + channel, target_id, i); + } + return (info.pos > info.offset ? info.pos - info.offset : 0); +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_reg.h linux/drivers/scsi/aic7xxx/aic7xxx_reg.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_reg.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_reg.h Tue Mar 6 19:18:16 2001 @@ -0,0 +1,706 @@ +/* + * DO NOT EDIT - This file is automatically generated. + */ + +#define SCSISEQ 0x00 +#define TEMODE 0x80 +#define SCSIRSTO 0x01 + +#define SXFRCTL0 0x01 +#define DFON 0x80 +#define DFPEXP 0x40 +#define FAST20 0x20 +#define CLRSTCNT 0x10 +#define SPIOEN 0x08 +#define SCAMEN 0x04 +#define CLRCHN 0x02 + +#define SXFRCTL1 0x02 +#define BITBUCKET 0x80 +#define SWRAPEN 0x40 +#define STIMESEL 0x18 +#define ENSTIMER 0x04 +#define ACTNEGEN 0x02 +#define STPWEN 0x01 + +#define SCSISIGO 0x03 +#define CDO 0x80 +#define IOO 0x40 +#define MSGO 0x20 +#define ATNO 0x10 +#define SELO 0x08 +#define BSYO 0x04 +#define REQO 0x02 +#define ACKO 0x01 + +#define SCSISIGI 0x03 +#define P_DATAIN_DT 0x60 +#define P_DATAOUT_DT 0x20 +#define ATNI 0x10 +#define SELI 0x08 +#define BSYI 0x04 +#define REQI 0x02 +#define ACKI 0x01 + +#define SCSIRATE 0x04 +#define WIDEXFER 0x80 +#define SXFR 0x70 +#define ENABLE_CRC 0x40 +#define SINGLE_EDGE 0x10 +#define SOFS 0x0f +#define SXFR_ULTRA2 0x0f + +#define SCSIID 0x05 +#define SCSIOFFSET 0x05 +#define SOFS_ULTRA2 0x7f + +#define SCSIDATL 0x06 + +#define SCSIDATH 0x07 + +#define STCNT 0x08 + +#define OPTIONMODE 0x08 +#define AUTORATEEN 0x80 +#define AUTOACKEN 0x40 +#define ATNMGMNTEN 0x20 +#define BUSFREEREV 0x10 +#define EXPPHASEDIS 0x08 +#define SCSIDATL_IMGEN 0x04 +#define OPTIONMODE_DEFAULTS 0x03 +#define AUTO_MSGOUT_DE 0x02 +#define DIS_MSGIN_DUALEDGE 0x01 + +#define TARGCRCCNT 0x0a + +#define CLRSINT0 0x0b +#define CLRSELDO 0x40 +#define CLRSELDI 0x20 +#define CLRSELINGO 0x10 +#define CLRIOERR 0x08 +#define CLRSWRAP 0x08 +#define CLRSPIORDY 0x02 + +#define SSTAT0 0x0b +#define TARGET 0x80 +#define SELDO 0x40 +#define SELDI 0x20 +#define SELINGO 0x10 +#define IOERR 0x08 +#define SWRAP 0x08 +#define SDONE 0x04 +#define SPIORDY 0x02 +#define DMADONE 0x01 + +#define CLRSINT1 0x0c +#define CLRSELTIMEO 0x80 +#define CLRATNO 0x40 +#define CLRSCSIRSTI 0x20 +#define CLRBUSFREE 0x08 +#define CLRSCSIPERR 0x04 +#define CLRPHASECHG 0x02 +#define CLRREQINIT 0x01 + +#define SSTAT1 0x0c +#define SELTO 0x80 +#define ATNTARG 0x40 +#define SCSIRSTI 0x20 +#define PHASEMIS 0x10 +#define BUSFREE 0x08 +#define SCSIPERR 0x04 +#define PHASECHG 0x02 +#define REQINIT 0x01 + +#define SSTAT2 0x0d +#define OVERRUN 0x80 +#define SHVALID 0x40 +#define SFCNT 0x1f +#define EXP_ACTIVE 0x10 +#define CRCVALERR 0x08 +#define CRCENDERR 0x04 +#define CRCREQERR 0x02 +#define DUAL_EDGE_ERR 0x01 + +#define SSTAT3 0x0e +#define SCSICNT 0xf0 +#define OFFCNT 0x0f + +#define SCSIID_ULTRA2 0x0f + +#define SIMODE0 0x10 +#define ENSELDO 0x40 +#define ENSELDI 0x20 +#define ENSELINGO 0x10 +#define ENIOERR 0x08 +#define ENSWRAP 0x08 +#define ENSDONE 0x04 +#define ENSPIORDY 0x02 +#define ENDMADONE 0x01 + +#define SIMODE1 0x11 +#define ENSELTIMO 0x80 +#define ENATNTARG 0x40 +#define ENSCSIRST 0x20 +#define ENPHASEMIS 0x10 +#define ENBUSFREE 0x08 +#define ENSCSIPERR 0x04 +#define ENPHASECHG 0x02 +#define ENREQINIT 0x01 + +#define SCSIBUSL 0x12 + +#define SCSIBUSH 0x13 + +#define SHADDR 0x14 + +#define SELTIMER 0x18 +#define TARGIDIN 0x18 +#define STAGE6 0x20 +#define STAGE5 0x10 +#define STAGE4 0x08 +#define STAGE3 0x04 +#define STAGE2 0x02 +#define STAGE1 0x01 + +#define SELID 0x19 +#define SELID_MASK 0xf0 +#define ONEBIT 0x08 + +#define SCAMCTL 0x1a +#define ENSCAMSELO 0x80 +#define CLRSCAMSELID 0x40 +#define ALTSTIM 0x20 +#define DFLTTID 0x10 +#define SCAMLVL 0x03 + +#define TARGID 0x1b + +#define SPIOCAP 0x1b +#define SOFT1 0x80 +#define SOFT0 0x40 +#define SOFTCMDEN 0x20 +#define HAS_BRDCTL 0x10 +#define SEEPROM 0x08 +#define EEPROM 0x04 +#define ROM 0x02 +#define SSPIOCPS 0x01 + +#define BRDCTL 0x1d +#define BRDDAT7 0x80 +#define BRDDAT6 0x40 +#define BRDDAT5 0x20 +#define BRDDAT4 0x10 +#define BRDSTB 0x10 +#define BRDCS 0x08 +#define BRDDAT3 0x08 +#define BRDDAT2 0x04 +#define BRDRW 0x04 +#define BRDRW_ULTRA2 0x02 +#define BRDCTL1 0x02 +#define BRDCTL0 0x01 +#define BRDSTB_ULTRA2 0x01 + +#define SEECTL 0x1e +#define EXTARBACK 0x80 +#define EXTARBREQ 0x40 +#define SEEMS 0x20 +#define SEERDY 0x10 +#define SEECS 0x08 +#define SEECK 0x04 +#define SEEDO 0x02 +#define SEEDI 0x01 + +#define SBLKCTL 0x1f +#define DIAGLEDEN 0x80 +#define DIAGLEDON 0x40 +#define AUTOFLUSHDIS 0x20 +#define ENAB40 0x08 +#define SELBUSB 0x08 +#define ENAB20 0x04 +#define SELWIDE 0x02 +#define XCVR 0x01 + +#define BUSY_TARGETS 0x20 +#define TARG_SCSIRATE 0x20 + +#define SRAM_BASE 0x20 + +#define ULTRA_ENB 0x30 +#define CMDSIZE_TABLE 0x30 + +#define DISC_DSB 0x32 + +#define CMDSIZE_TABLE_TAIL 0x34 + +#define MWI_RESIDUAL 0x38 + +#define NEXT_QUEUED_SCB 0x39 + +#define MSG_OUT 0x3a + +#define DMAPARAMS 0x3b +#define PRELOADEN 0x80 +#define WIDEODD 0x40 +#define SCSIEN 0x20 +#define SDMAENACK 0x10 +#define SDMAEN 0x10 +#define HDMAEN 0x08 +#define HDMAENACK 0x08 +#define DIRECTION 0x04 +#define FIFOFLUSH 0x02 +#define FIFORESET 0x01 + +#define SEQ_FLAGS 0x3c +#define IDENTIFY_SEEN 0x80 +#define TARGET_CMD_IS_TAGGED 0x40 +#define DPHASE 0x20 +#define TARG_CMD_PENDING 0x10 +#define CMDPHASE_PENDING 0x08 +#define DPHASE_PENDING 0x04 +#define SPHASE_PENDING 0x02 +#define NO_DISCONNECT 0x01 + +#define SAVED_SCSIID 0x3d + +#define SAVED_LUN 0x3e + +#define LASTPHASE 0x3f +#define P_MESGIN 0xe0 +#define PHASE_MASK 0xe0 +#define P_STATUS 0xc0 +#define P_MESGOUT 0xa0 +#define P_COMMAND 0x80 +#define CDI 0x80 +#define IOI 0x40 +#define P_DATAIN 0x40 +#define MSGI 0x20 +#define P_BUSFREE 0x01 +#define P_DATAOUT 0x00 + +#define WAITING_SCBH 0x40 + +#define DISCONNECTED_SCBH 0x41 + +#define FREE_SCBH 0x42 + +#define COMPLETE_SCBH 0x43 + +#define HSCB_ADDR 0x44 + +#define SHARED_DATA_ADDR 0x48 + +#define KERNEL_QINPOS 0x4c + +#define QINPOS 0x4d + +#define QOUTPOS 0x4e + +#define KERNEL_TQINPOS 0x4f + +#define TQINPOS 0x50 + +#define ARG_1 0x51 +#define RETURN_1 0x51 +#define SEND_MSG 0x80 +#define SEND_SENSE 0x40 +#define SEND_REJ 0x20 +#define MSGOUT_PHASEMIS 0x10 +#define EXIT_MSG_LOOP 0x08 +#define CONT_MSG_LOOP 0x04 +#define CONT_TARG_SESSION 0x02 + +#define ARG_2 0x52 +#define RETURN_2 0x52 + +#define LAST_MSG 0x53 + +#define TARGET_MSG_REQUEST 0x54 + +#define SCSISEQ_TEMPLATE 0x56 +#define ENSELO 0x40 +#define ENSELI 0x20 +#define ENRSELI 0x10 +#define ENAUTOATNO 0x08 +#define ENAUTOATNI 0x04 +#define ENAUTOATNP 0x02 + +#define DATA_COUNT_ODD 0x57 + +#define INITIATOR_TAG 0x58 + +#define SEQ_FLAGS2 0x59 +#define SCB_DMA 0x01 + +#define SCSICONF 0x5a +#define TERM_ENB 0x80 +#define RESET_SCSI 0x40 +#define ENSPCHK 0x20 +#define HWSCSIID 0x0f +#define HSCSIID 0x07 + +#define INTDEF 0x5c +#define EDGE_TRIG 0x80 +#define VECTOR 0x0f + +#define HOSTCONF 0x5d + +#define HA_274_BIOSCTRL 0x5f +#define BIOSMODE 0x30 +#define BIOSDISABLED 0x30 +#define CHANNEL_B_PRIMARY 0x08 + +#define SEQCTL 0x60 +#define PERRORDIS 0x80 +#define PAUSEDIS 0x40 +#define FAILDIS 0x20 +#define FASTMODE 0x10 +#define BRKADRINTEN 0x08 +#define STEP 0x04 +#define SEQRESET 0x02 +#define LOADRAM 0x01 + +#define SEQRAM 0x61 + +#define SEQADDR0 0x62 + +#define SEQADDR1 0x63 +#define SEQADDR1_MASK 0x01 + +#define ACCUM 0x64 + +#define SINDEX 0x65 + +#define DINDEX 0x66 + +#define ALLONES 0x69 + +#define ALLZEROS 0x6a + +#define NONE 0x6a + +#define FLAGS 0x6b +#define ZERO 0x02 +#define CARRY 0x01 + +#define SINDIR 0x6c + +#define DINDIR 0x6d + +#define FUNCTION1 0x6e + +#define STACK 0x6f + +#define TARG_OFFSET 0x70 + +#define BCTL 0x84 +#define ACE 0x08 +#define ENABLE 0x01 + +#define DSCOMMAND0 0x84 +#define CACHETHEN 0x80 +#define DPARCKEN 0x40 +#define MPARCKEN 0x20 +#define EXTREQLCK 0x10 +#define INTSCBRAMSEL 0x08 +#define RAMPS 0x04 +#define USCBSIZE32 0x02 +#define CIOPARCKEN 0x01 + +#define BUSTIME 0x85 +#define BOFF 0xf0 +#define BON 0x0f + +#define BUSSPD 0x86 +#define DFTHRSH 0xc0 +#define DFTHRSH_75 0x80 +#define STBOFF 0x38 +#define STBON 0x07 + +#define HS_MAILBOX 0x86 +#define HOST_MAILBOX 0xf0 +#define HOST_TQINPOS 0x80 +#define SEQ_MAILBOX 0x0f + +#define DSPCISTATUS 0x86 +#define DFTHRSH_100 0xc0 + +#define HCNTRL 0x87 +#define POWRDN 0x40 +#define SWINT 0x10 +#define IRQMS 0x08 +#define PAUSE 0x04 +#define INTEN 0x02 +#define CHIPRST 0x01 +#define CHIPRSTACK 0x01 + +#define HADDR 0x88 + +#define HCNT 0x8c + +#define SCBPTR 0x90 + +#define INTSTAT 0x91 +#define SEQINT_MASK 0xf1 +#define OUT_OF_RANGE 0xe1 +#define NO_FREE_SCB 0xd1 +#define SCB_MISMATCH 0xc1 +#define MISSED_BUSFREE 0xb1 +#define MKMSG_FAILED 0xa1 +#define DATA_OVERRUN 0x91 +#define PERR_DETECTED 0x81 +#define BAD_STATUS 0x71 +#define HOST_MSG_LOOP 0x61 +#define RESIDUAL 0x51 +#define IGN_WIDE_RES 0x41 +#define NO_MATCH 0x31 +#define NO_IDENT 0x21 +#define SEND_REJECT 0x11 +#define INT_PEND 0x0f +#define BRKADRINT 0x08 +#define SCSIINT 0x04 +#define CMDCMPLT 0x02 +#define BAD_PHASE 0x01 +#define SEQINT 0x01 + +#define CLRINT 0x92 +#define CLRPARERR 0x10 +#define CLRBRKADRINT 0x08 +#define CLRSCSIINT 0x04 +#define CLRCMDINT 0x02 +#define CLRSEQINT 0x01 + +#define ERROR 0x92 +#define CIOPARERR 0x80 +#define PCIERRSTAT 0x40 +#define MPARERR 0x20 +#define DPARERR 0x10 +#define SQPARERR 0x08 +#define ILLOPCODE 0x04 +#define ILLSADDR 0x02 +#define ILLHADDR 0x01 + +#define DFCNTRL 0x93 + +#define DFSTATUS 0x94 +#define PRELOAD_AVAIL 0x80 +#define DWORDEMP 0x20 +#define MREQPEND 0x10 +#define HDONE 0x08 +#define DFTHRESH 0x04 +#define FIFOFULL 0x02 +#define FIFOEMP 0x01 + +#define DFWADDR 0x95 + +#define DFRADDR 0x97 + +#define DFDAT 0x99 + +#define SCBCNT 0x9a +#define SCBAUTO 0x80 +#define SCBCNT_MASK 0x1f + +#define QINFIFO 0x9b + +#define QINCNT 0x9c + +#define QOUTFIFO 0x9d + +#define CRCCONTROL1 0x9d +#define CRCONSEEN 0x80 +#define CRCVALCHKEN 0x40 +#define CRCENDCHKEN 0x20 +#define CRCREQCHKEN 0x10 +#define TARGCRCENDEN 0x08 +#define TARGCRCCNTEN 0x04 + +#define QOUTCNT 0x9e + +#define SCSIPHASE 0x9e +#define STATUS_PHASE 0x20 +#define COMMAND_PHASE 0x10 +#define MSG_IN_PHASE 0x08 +#define MSG_OUT_PHASE 0x04 +#define DATA_IN_PHASE 0x02 +#define DATA_OUT_PHASE 0x01 + +#define SFUNCT 0x9f +#define ALT_MODE 0x80 + +#define SCB_CDB_PTR 0xa0 +#define SCB_CDB_STORE 0xa0 +#define SCB_TARGET_INFO 0xa0 +#define SCB_RESIDUAL_DATACNT 0xa0 + +#define SCB_BASE 0xa0 + +#define SCB_RESIDUAL_SGPTR 0xa4 + +#define SCB_SCSI_STATUS 0xa8 + +#define SCB_CDB_STORE_PAD 0xa9 + +#define SCB_DATAPTR 0xac + +#define SCB_DATACNT 0xb0 +#define SG_LAST_SEG 0x80 +#define SG_HIGH_ADDR_BITS 0x7f + +#define SCB_SGPTR 0xb4 +#define SG_RESID_VALID 0x04 +#define SG_FULL_RESID 0x02 +#define SG_LIST_NULL 0x01 + +#define SCB_CONTROL 0xb8 +#define TARGET_SCB 0x80 +#define DISCENB 0x40 +#define TAG_ENB 0x20 +#define MK_MESSAGE 0x10 +#define ULTRAENB 0x08 +#define DISCONNECTED 0x04 +#define SCB_TAG_TYPE 0x03 + +#define SCB_SCSIID 0xb9 +#define TID 0xf0 +#define TWIN_CHNLB 0x80 +#define TWIN_TID 0x70 +#define OID 0x0f + +#define SCB_LUN 0xba +#define LID 0xff + +#define SCB_TAG 0xbb + +#define SCB_CDB_LEN 0xbc + +#define SCB_SCSIRATE 0xbd + +#define SCB_SCSIOFFSET 0xbe + +#define SCB_NEXT 0xbf + +#define SEECTL_2840 0xc0 +#define CS_2840 0x04 +#define CK_2840 0x02 +#define DO_2840 0x01 + +#define SCB_64_SPARE 0xc0 + +#define STATUS_2840 0xc1 +#define EEPROM_TF 0x80 +#define BIOS_SEL 0x60 +#define ADSEL 0x1e +#define DI_2840 0x01 + +#define SCB_64_BTT 0xd0 + +#define CCHADDR 0xe0 + +#define CCHCNT 0xe8 + +#define CCSGRAM 0xe9 + +#define CCSGADDR 0xea + +#define CCSGCTL 0xeb +#define CCSGDONE 0x80 +#define CCSGEN 0x08 +#define SG_FETCH_NEEDED 0x02 +#define CCSGRESET 0x01 + +#define CCSCBRAM 0xec + +#define CCSCBADDR 0xed + +#define CCSCBCTL 0xee +#define CCSCBDONE 0x80 +#define ARRDONE 0x40 +#define CCARREN 0x10 +#define CCSCBEN 0x08 +#define CCSCBDIR 0x04 +#define CCSCBRESET 0x01 + +#define CCSCBCNT 0xef + +#define SCBBADDR 0xf0 + +#define CCSCBPTR 0xf1 + +#define HNSCB_QOFF 0xf4 + +#define SNSCB_QOFF 0xf6 + +#define SDSCB_QOFF 0xf8 + +#define QOFF_CTLSTA 0xfa +#define SCB_AVAIL 0x40 +#define SNSCB_ROLLOVER 0x20 +#define SDSCB_ROLLOVER 0x10 +#define SCB_QSIZE 0x07 +#define SCB_QSIZE_256 0x06 + +#define DFF_THRSH 0xfb +#define WR_DFTHRSH 0x70 +#define WR_DFTHRSH_MAX 0x70 +#define WR_DFTHRSH_90 0x60 +#define WR_DFTHRSH_85 0x50 +#define WR_DFTHRSH_75 0x40 +#define WR_DFTHRSH_63 0x30 +#define WR_DFTHRSH_50 0x20 +#define WR_DFTHRSH_25 0x10 +#define RD_DFTHRSH_MAX 0x07 +#define RD_DFTHRSH 0x07 +#define RD_DFTHRSH_90 0x06 +#define RD_DFTHRSH_85 0x05 +#define RD_DFTHRSH_75 0x04 +#define RD_DFTHRSH_63 0x03 +#define RD_DFTHRSH_50 0x02 +#define RD_DFTHRSH_25 0x01 +#define RD_DFTHRSH_MIN 0x00 +#define WR_DFTHRSH_MIN 0x00 + +#define SG_CACHE_SHADOW 0xfc +#define SG_ADDR_MASK 0xf8 +#define ODD_SEG 0x04 +#define LAST_SEG 0x02 +#define LAST_SEG_DONE 0x01 + +#define SG_CACHE_PRE 0xfc + + +#define CMD_GROUP_CODE_SHIFT 0x05 +#define BUS_8_BIT 0x00 +#define CCSGRAM_MAXSEGS 0x10 +#define TARGET_DATA_IN 0x01 +#define STATUS_QUEUE_FULL 0x28 +#define STATUS_BUSY 0x08 +#define MAX_OFFSET_8BIT 0x0f +#define BUS_16_BIT 0x01 +#define TID_SHIFT 0x04 +#define SCB_DOWNLOAD_SIZE_64 0x30 +#define SCB_UPLOAD_SIZE 0x20 +#define HOST_MAILBOX_SHIFT 0x04 +#define SCB_INITIATOR_TAG 0x03 +#define SCB_TARGET_STATUS 0x02 +#define SCB_TARGET_DATA_DIR 0x01 +#define SCB_TARGET_PHASES 0x00 +#define MAX_OFFSET_ULTRA2 0x7f +#define MAX_OFFSET_16BIT 0x08 +#define TARGET_CMD_CMPLT 0xfe +#define SCB_LIST_NULL 0xff +#define SG_SIZEOF 0x08 +#define SCB_DOWNLOAD_SIZE 0x20 +#define SEQ_MAILBOX_SHIFT 0x00 +#define HOST_MSG 0xff +#define BUS_32_BIT 0x02 +#define CCSGADDR_MAX 0x80 + + +/* Downloaded Constant Definitions */ +#define SG_PREFETCH_ADDR_MASK 0x06 +#define SG_PREFETCH_ALIGN_MASK 0x05 +#define QOUTFIFO_OFFSET 0x00 +#define SG_PREFETCH_CNT 0x04 +#define INVERTED_CACHESIZE_MASK 0x03 +#define CACHESIZE_MASK 0x02 +#define QINFIFO_OFFSET 0x01 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_seq.h linux/drivers/scsi/aic7xxx/aic7xxx_seq.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_seq.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aic7xxx_seq.h Tue Mar 6 19:18:16 2001 @@ -0,0 +1,1239 @@ +/* + * DO NOT EDIT - This file is automatically generated. + */ +static uint8_t seqprog[] = { + 0xb2, 0x00, 0x00, 0x08, + 0xf7, 0x11, 0x22, 0x08, + 0x00, 0x65, 0xde, 0x59, + 0xf7, 0x01, 0x02, 0x08, + 0xff, 0x6a, 0x24, 0x08, + 0x40, 0x00, 0x40, 0x68, + 0x08, 0x1f, 0x3e, 0x10, + 0x40, 0x00, 0x40, 0x68, + 0xff, 0x40, 0x3c, 0x60, + 0x08, 0x1f, 0x3e, 0x10, + 0x60, 0x0b, 0x42, 0x68, + 0x40, 0xfa, 0x12, 0x78, + 0x01, 0x4d, 0xc8, 0x30, + 0x00, 0x4c, 0x12, 0x70, + 0x01, 0x39, 0xa2, 0x30, + 0x00, 0x6a, 0x7e, 0x5e, + 0x01, 0x51, 0x20, 0x31, + 0x01, 0x59, 0xb2, 0x00, + 0x0d, 0x6a, 0x76, 0x00, + 0x00, 0x51, 0xda, 0x5d, + 0x01, 0x51, 0xc8, 0x30, + 0x00, 0x39, 0xde, 0x60, + 0x00, 0xbb, 0x30, 0x70, + 0xc1, 0x6a, 0x96, 0x5e, + 0x01, 0xbf, 0x72, 0x30, + 0x01, 0x40, 0x7e, 0x31, + 0x01, 0x90, 0x80, 0x30, + 0x01, 0xf6, 0xd4, 0x30, + 0x01, 0x4d, 0x9a, 0x18, + 0xfe, 0x59, 0xb2, 0x08, + 0x01, 0x40, 0x20, 0x31, + 0x00, 0x65, 0xe2, 0x58, + 0x60, 0x0b, 0x40, 0x78, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x11, 0x22, 0x00, + 0x60, 0x0b, 0x00, 0x78, + 0x40, 0x0b, 0x12, 0x69, + 0x80, 0x0b, 0xcc, 0x78, + 0x20, 0x6a, 0x16, 0x00, + 0x20, 0x11, 0x54, 0x68, + 0x20, 0x6a, 0x18, 0x00, + 0x20, 0x11, 0x22, 0x00, + 0xa4, 0x6a, 0x06, 0x00, + 0x08, 0x3c, 0x78, 0x00, + 0x01, 0x50, 0xc8, 0x30, + 0xe0, 0x6a, 0xcc, 0x00, + 0x48, 0x6a, 0xc4, 0x5d, + 0x01, 0x6a, 0xdc, 0x01, + 0x88, 0x6a, 0xcc, 0x00, + 0x48, 0x6a, 0xc4, 0x5d, + 0x01, 0x6a, 0x26, 0x01, + 0xf0, 0x19, 0x7a, 0x08, + 0x0f, 0x18, 0xc8, 0x08, + 0x0f, 0x0f, 0xc8, 0x08, + 0x0f, 0x05, 0xc8, 0x08, + 0x00, 0x3d, 0x7a, 0x00, + 0x08, 0x1f, 0x74, 0x78, + 0x80, 0x3d, 0x7a, 0x00, + 0x01, 0x3d, 0xd8, 0x31, + 0x01, 0x3d, 0x32, 0x31, + 0x10, 0x03, 0x56, 0x79, + 0x00, 0x65, 0x0a, 0x59, + 0x80, 0x66, 0xa8, 0x78, + 0x01, 0x66, 0xd8, 0x31, + 0x01, 0x66, 0x32, 0x31, + 0x40, 0x66, 0x86, 0x68, + 0x01, 0x3c, 0x78, 0x00, + 0x10, 0x03, 0xb0, 0x78, + 0x00, 0x65, 0x0a, 0x59, + 0xe0, 0x66, 0xc8, 0x18, + 0x00, 0x65, 0xb0, 0x50, + 0xdd, 0x66, 0xc8, 0x18, + 0x00, 0x65, 0xb0, 0x48, + 0x01, 0x66, 0xd8, 0x31, + 0x01, 0x66, 0x32, 0x31, + 0x10, 0x03, 0x56, 0x79, + 0x00, 0x65, 0x0a, 0x59, + 0x01, 0x66, 0xd8, 0x31, + 0x01, 0x66, 0x32, 0x31, + 0x01, 0x66, 0xb0, 0x30, + 0x40, 0x3c, 0x78, 0x00, + 0x10, 0x03, 0xa6, 0x78, + 0x00, 0x65, 0x0a, 0x59, + 0x00, 0x65, 0xb0, 0x40, + 0x61, 0x6a, 0x96, 0x5e, + 0x08, 0x51, 0x2e, 0x71, + 0x02, 0x0b, 0xac, 0x78, + 0x00, 0x65, 0xa8, 0x40, + 0x80, 0x86, 0xc8, 0x08, + 0x01, 0x4f, 0xc8, 0x30, + 0x00, 0x50, 0xc2, 0x60, + 0xc4, 0x6a, 0x32, 0x5d, + 0x40, 0x3c, 0xbe, 0x78, + 0x28, 0x6a, 0x48, 0x5d, + 0x00, 0x65, 0x54, 0x41, + 0x08, 0x6a, 0x48, 0x5d, + 0x00, 0x65, 0x54, 0x41, + 0xff, 0x6a, 0xd8, 0x01, + 0xff, 0x6a, 0x32, 0x01, + 0x90, 0x3c, 0x78, 0x00, + 0x10, 0x03, 0x4a, 0x69, + 0x00, 0x65, 0x2e, 0x41, + 0x1a, 0x01, 0x02, 0x00, + 0xf0, 0x19, 0x7a, 0x08, + 0x0f, 0x0f, 0xc8, 0x08, + 0x0f, 0x05, 0xc8, 0x08, + 0x00, 0x3d, 0x7a, 0x00, + 0x08, 0x1f, 0xda, 0x78, + 0x80, 0x3d, 0x7a, 0x00, + 0x20, 0x6a, 0x16, 0x00, + 0x00, 0x65, 0xbe, 0x41, + 0x00, 0x65, 0x76, 0x5e, + 0x00, 0x65, 0x12, 0x40, + 0x20, 0x11, 0xe8, 0x68, + 0x20, 0x6a, 0x18, 0x00, + 0x20, 0x11, 0x22, 0x00, + 0xf7, 0x1f, 0xca, 0x08, + 0x80, 0xb9, 0xee, 0x78, + 0x08, 0x65, 0xca, 0x00, + 0x01, 0x65, 0x3e, 0x30, + 0x01, 0xb9, 0x1e, 0x30, + 0x7f, 0xb9, 0x0a, 0x08, + 0x01, 0xb9, 0x0a, 0x30, + 0x01, 0x56, 0xca, 0x30, + 0x80, 0xb8, 0xfc, 0x78, + 0x80, 0x65, 0xca, 0x00, + 0x01, 0x65, 0x00, 0x34, + 0x01, 0x56, 0x00, 0x34, + 0x1a, 0x01, 0x02, 0x00, + 0x08, 0xb8, 0x06, 0x79, + 0x20, 0x01, 0x02, 0x00, + 0x02, 0xbd, 0x08, 0x34, + 0x01, 0xbd, 0x08, 0x34, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0x0c, 0x79, + 0xf7, 0x01, 0x02, 0x08, + 0x01, 0x06, 0xcc, 0x34, + 0xb2, 0x00, 0x00, 0x08, + 0x40, 0x6a, 0x16, 0x00, + 0x01, 0x40, 0x20, 0x31, + 0x01, 0xbf, 0x80, 0x30, + 0x01, 0xb9, 0x7a, 0x30, + 0x01, 0xba, 0x7c, 0x30, + 0x00, 0x65, 0x00, 0x59, + 0x80, 0x0b, 0xba, 0x79, + 0xe4, 0x6a, 0x32, 0x5d, + 0x80, 0xba, 0x48, 0x5d, + 0x20, 0xb8, 0x2c, 0x79, + 0x20, 0x6a, 0x48, 0x5d, + 0x00, 0xa3, 0x48, 0x5d, + 0x01, 0xa0, 0x78, 0x30, + 0x10, 0x03, 0x46, 0x69, + 0x08, 0x3c, 0x62, 0x69, + 0x04, 0x3c, 0x88, 0x69, + 0x02, 0x3c, 0x8e, 0x69, + 0x01, 0x3c, 0x4c, 0x79, + 0x00, 0x6a, 0x7e, 0x5e, + 0x01, 0x6a, 0xa2, 0x30, + 0x00, 0x65, 0x9a, 0x59, + 0x04, 0x51, 0x3e, 0x61, + 0x0d, 0x6a, 0x76, 0x00, + 0x00, 0xbb, 0xda, 0x5d, + 0x00, 0x65, 0x2c, 0x41, + 0xa4, 0x6a, 0x06, 0x00, + 0x00, 0x65, 0x0a, 0x59, + 0x00, 0x65, 0xa8, 0x40, + 0xe4, 0x6a, 0x32, 0x5d, + 0x20, 0x3c, 0x52, 0x79, + 0x02, 0x6a, 0x48, 0x5d, + 0x04, 0x6a, 0x48, 0x5d, + 0x01, 0x03, 0x54, 0x69, + 0xf7, 0x11, 0x22, 0x08, + 0xff, 0x6a, 0x24, 0x08, + 0xff, 0x6a, 0x06, 0x08, + 0x01, 0x6a, 0x7e, 0x00, + 0x00, 0x65, 0x9a, 0x59, + 0x00, 0x65, 0x04, 0x40, + 0x84, 0x6a, 0x32, 0x5d, + 0x00, 0x65, 0x0a, 0x59, + 0x01, 0x66, 0xc8, 0x30, + 0x01, 0x64, 0xd8, 0x31, + 0x01, 0x64, 0x32, 0x31, + 0x5b, 0x64, 0xc8, 0x28, + 0x30, 0x64, 0xca, 0x18, + 0x01, 0x6c, 0xc8, 0x30, + 0xff, 0x64, 0x84, 0x79, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0x76, 0x79, + 0x01, 0x64, 0x7c, 0x61, + 0xf7, 0x01, 0x02, 0x08, + 0x01, 0x06, 0xd8, 0x31, + 0x01, 0x06, 0x32, 0x31, + 0xff, 0x64, 0xc8, 0x18, + 0xff, 0x64, 0x76, 0x69, + 0xf7, 0x3c, 0x78, 0x08, + 0x00, 0x65, 0x2e, 0x41, + 0x40, 0xa1, 0x7e, 0x10, + 0x04, 0xa1, 0x32, 0x5d, + 0x00, 0x65, 0x62, 0x42, + 0xc4, 0x6a, 0x32, 0x5d, + 0xc0, 0x6a, 0x7e, 0x00, + 0x00, 0xa2, 0x48, 0x5d, + 0xe4, 0x6a, 0x06, 0x00, + 0x00, 0x6a, 0x48, 0x5d, + 0x00, 0x65, 0x54, 0x41, + 0x10, 0x3c, 0x9e, 0x69, + 0x00, 0xbb, 0x64, 0x44, + 0x18, 0x6a, 0xda, 0x01, + 0x01, 0x69, 0xd8, 0x31, + 0x1c, 0x6a, 0xd0, 0x01, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xa6, 0x79, + 0xff, 0x6a, 0xdc, 0x09, + 0x01, 0x93, 0x26, 0x01, + 0x03, 0x6a, 0x2a, 0x01, + 0x01, 0x69, 0x32, 0x31, + 0x1c, 0x6a, 0xa8, 0x5d, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x6c, 0x5e, + 0x01, 0x50, 0xa0, 0x18, + 0x02, 0x6a, 0x22, 0x05, + 0x80, 0x6a, 0x74, 0x00, + 0x80, 0x3c, 0x78, 0x00, + 0x00, 0x65, 0xa0, 0x5d, + 0x01, 0x3f, 0xc8, 0x30, + 0xbf, 0x64, 0x62, 0x7a, + 0x80, 0x64, 0x82, 0x73, + 0xa0, 0x64, 0xd8, 0x73, + 0xc0, 0x64, 0xd0, 0x73, + 0xe0, 0x64, 0x18, 0x74, + 0x01, 0x6a, 0x96, 0x5e, + 0x00, 0x65, 0xbe, 0x41, + 0xf7, 0x11, 0x22, 0x08, + 0x01, 0x06, 0xd4, 0x30, + 0xff, 0x6a, 0x24, 0x08, + 0xf7, 0x01, 0x02, 0x08, + 0x09, 0x0c, 0xd8, 0x79, + 0x08, 0x0c, 0x04, 0x68, + 0xb1, 0x6a, 0x96, 0x5e, + 0xff, 0x6a, 0x26, 0x09, + 0x12, 0x01, 0x02, 0x00, + 0x02, 0x6a, 0x08, 0x30, + 0xff, 0x6a, 0x08, 0x08, + 0xdf, 0x01, 0x02, 0x08, + 0x01, 0x6a, 0x7e, 0x00, + 0xff, 0x6a, 0x78, 0x0c, + 0xff, 0x6a, 0xc8, 0x08, + 0x08, 0xa4, 0x48, 0x19, + 0x00, 0xa5, 0x4a, 0x21, + 0x00, 0xa6, 0x4c, 0x21, + 0x00, 0xa7, 0x4e, 0x25, + 0x08, 0xeb, 0x9a, 0x7e, + 0x80, 0xeb, 0xf8, 0x79, + 0xff, 0x6a, 0xd6, 0x09, + 0x08, 0xeb, 0xfc, 0x69, + 0xff, 0x6a, 0xd4, 0x0c, + 0x88, 0xeb, 0x12, 0x72, + 0x08, 0xeb, 0x9a, 0x6e, + 0x80, 0xa3, 0x9a, 0x6e, + 0x04, 0xea, 0x16, 0xe2, + 0x08, 0xee, 0x9a, 0x6e, + 0x04, 0x6a, 0xd0, 0x81, + 0x05, 0xa4, 0xc0, 0x89, + 0x03, 0xa5, 0xc2, 0x31, + 0x09, 0x6a, 0xd6, 0x05, + 0x00, 0x65, 0xfa, 0x59, + 0x06, 0xa4, 0xd4, 0x89, + 0x80, 0x94, 0x9a, 0x7e, + 0x04, 0xe9, 0x10, 0x31, + 0x01, 0xe9, 0xca, 0x30, + 0x01, 0x65, 0x20, 0x7a, + 0x01, 0x57, 0xae, 0x10, + 0x01, 0x65, 0x18, 0x31, + 0x02, 0xe9, 0x1a, 0x31, + 0x01, 0xe9, 0x46, 0x31, + 0x00, 0x65, 0xec, 0x59, + 0x01, 0xa4, 0xca, 0x30, + 0x01, 0x57, 0x2e, 0x7a, + 0x04, 0x65, 0xca, 0x00, + 0x80, 0xa3, 0x32, 0x7a, + 0x02, 0x65, 0xca, 0x00, + 0x01, 0x65, 0xf8, 0x31, + 0x01, 0x3b, 0x26, 0x31, + 0xff, 0x6a, 0xd4, 0x0c, + 0x01, 0x8c, 0xc8, 0x30, + 0x00, 0x88, 0xc8, 0x18, + 0x02, 0x64, 0xc8, 0x88, + 0xff, 0x64, 0x9a, 0x7e, + 0xff, 0x8d, 0x48, 0x6a, + 0xff, 0x8e, 0x48, 0x6a, + 0x03, 0x8c, 0xd4, 0x98, + 0x00, 0x65, 0x9a, 0x56, + 0x01, 0x64, 0x70, 0x30, + 0xff, 0x64, 0xc8, 0x10, + 0x01, 0x64, 0xc8, 0x18, + 0x00, 0x8c, 0x18, 0x19, + 0xff, 0x8d, 0x1a, 0x21, + 0xff, 0x8e, 0x1c, 0x25, + 0x04, 0x14, 0x10, 0x31, + 0x03, 0xa0, 0x18, 0x31, + 0x03, 0xa0, 0x10, 0x30, + 0x08, 0x6a, 0xcc, 0x00, + 0xa0, 0x6a, 0xbe, 0x5d, + 0x01, 0xa0, 0xae, 0x08, + 0x00, 0x65, 0x88, 0x42, + 0xa8, 0x6a, 0x76, 0x00, + 0x79, 0x6a, 0x76, 0x00, + 0x40, 0x3f, 0x6a, 0x6a, + 0x04, 0x3b, 0x76, 0x00, + 0x00, 0x65, 0x52, 0x5d, + 0x04, 0x6a, 0xd4, 0x81, + 0x20, 0x3c, 0x54, 0x6a, + 0x20, 0x3c, 0x78, 0x00, + 0x07, 0xac, 0x10, 0x31, + 0x05, 0xb3, 0x46, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0xac, 0x6a, 0xb6, 0x5d, + 0xa3, 0x6a, 0xcc, 0x00, + 0xb3, 0x6a, 0xba, 0x5d, + 0x00, 0x65, 0x38, 0x5a, + 0xfd, 0xa4, 0x48, 0x09, + 0x01, 0x8c, 0xae, 0x08, + 0x03, 0x8c, 0x10, 0x30, + 0x00, 0x65, 0xae, 0x5d, + 0x01, 0xa4, 0x98, 0x7a, + 0x04, 0x3b, 0x76, 0x08, + 0x01, 0x3b, 0x26, 0x31, + 0x80, 0x02, 0x04, 0x00, + 0x10, 0x0c, 0x90, 0x7a, + 0x7f, 0x02, 0x04, 0x08, + 0x91, 0x6a, 0x96, 0x5e, + 0x00, 0x65, 0xbe, 0x41, + 0x01, 0xa4, 0xca, 0x30, + 0x80, 0xa3, 0x9e, 0x7a, + 0x02, 0x65, 0xca, 0x00, + 0x01, 0x57, 0xa2, 0x7a, + 0x04, 0x65, 0xca, 0x00, + 0x01, 0x65, 0xf8, 0x31, + 0x01, 0x3b, 0x26, 0x31, + 0x00, 0x65, 0x00, 0x5a, + 0x01, 0xfc, 0xae, 0x6a, + 0x80, 0x0b, 0xa6, 0x6a, + 0x10, 0x0c, 0xa6, 0x7a, + 0x04, 0x93, 0xc0, 0x6a, + 0xdf, 0x93, 0x26, 0x09, + 0x20, 0x93, 0xb2, 0x6a, + 0x02, 0x93, 0x26, 0x01, + 0x01, 0x94, 0xb4, 0x7a, + 0x01, 0x94, 0xb4, 0x7a, + 0x01, 0x94, 0xb4, 0x7a, + 0x01, 0x94, 0xb4, 0x7a, + 0x01, 0x94, 0xb4, 0x7a, + 0x10, 0x94, 0xc0, 0x6a, + 0xd7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0xc4, 0x6a, + 0x02, 0xfc, 0xce, 0x7a, + 0x01, 0xfc, 0x4e, 0x7b, + 0x01, 0xa4, 0x48, 0x01, + 0x00, 0x65, 0x4e, 0x43, + 0x40, 0x0d, 0xd4, 0x6a, + 0x00, 0x65, 0x00, 0x5a, + 0x00, 0x65, 0xc6, 0x42, + 0x80, 0xfc, 0xde, 0x7a, + 0x80, 0xa4, 0xde, 0x6a, + 0xff, 0xa5, 0x4a, 0x19, + 0xff, 0xa6, 0x4c, 0x21, + 0xff, 0xa7, 0x4e, 0x21, + 0xf8, 0xfc, 0x48, 0x09, + 0xff, 0x6a, 0xae, 0x08, + 0x04, 0xfc, 0xe6, 0x7a, + 0x01, 0x57, 0xae, 0x00, + 0xff, 0x6a, 0x46, 0x09, + 0xff, 0x38, 0xf2, 0x6a, + 0x80, 0xa3, 0xf2, 0x7a, + 0x80, 0x0b, 0xf0, 0x7a, + 0x04, 0x3b, 0xf2, 0x7a, + 0xbf, 0x3b, 0x76, 0x08, + 0x01, 0x3b, 0x26, 0x31, + 0x00, 0x65, 0x00, 0x5a, + 0x01, 0x0b, 0x00, 0x6b, + 0x10, 0x0c, 0xf4, 0x7a, + 0x04, 0x93, 0xfe, 0x6a, + 0x01, 0x94, 0xfc, 0x7a, + 0x10, 0x94, 0xfe, 0x6a, + 0xc7, 0x93, 0x26, 0x09, + 0x01, 0x99, 0xd4, 0x30, + 0x38, 0x93, 0x02, 0x6b, + 0xff, 0x08, 0x4e, 0x6b, + 0xff, 0x09, 0x4e, 0x6b, + 0xff, 0x0a, 0x4e, 0x6b, + 0xff, 0x38, 0x1e, 0x7b, + 0x04, 0x14, 0x10, 0x31, + 0x01, 0x38, 0x18, 0x31, + 0x02, 0x6a, 0x1a, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0x14, 0x6a, 0xbc, 0x5d, + 0x00, 0x38, 0xa8, 0x5d, + 0xff, 0x6a, 0x70, 0x08, + 0x00, 0x65, 0x44, 0x43, + 0x80, 0xa3, 0x24, 0x7b, + 0x01, 0xa4, 0x48, 0x01, + 0x00, 0x65, 0x4e, 0x43, + 0x08, 0xeb, 0x2a, 0x7b, + 0x00, 0x65, 0x00, 0x5a, + 0x08, 0xeb, 0x26, 0x6b, + 0x07, 0xe9, 0x10, 0x31, + 0x80, 0xe9, 0x30, 0x7b, + 0x80, 0xa3, 0x46, 0x01, + 0x88, 0x6a, 0xcc, 0x00, + 0xa4, 0x6a, 0xbc, 0x5d, + 0x08, 0x6a, 0xa8, 0x5d, + 0x0d, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x6c, 0x5e, + 0x88, 0x6a, 0xcc, 0x00, + 0x00, 0x65, 0x4e, 0x5e, + 0x01, 0x99, 0x46, 0x31, + 0x00, 0x65, 0x38, 0x5a, + 0x00, 0x65, 0xec, 0x59, + 0x03, 0x8c, 0x10, 0x30, + 0x00, 0x65, 0xae, 0x5d, + 0x01, 0x8c, 0x4c, 0x7b, + 0x01, 0x57, 0xae, 0x10, + 0x80, 0x0b, 0x88, 0x6a, + 0x80, 0x0b, 0x54, 0x6b, + 0x01, 0x0c, 0x50, 0x7b, + 0x10, 0x0c, 0x88, 0x7a, + 0x00, 0x65, 0xf6, 0x59, + 0xff, 0x38, 0x66, 0x7b, + 0x01, 0x38, 0xc8, 0x30, + 0x00, 0x08, 0x40, 0x19, + 0xff, 0x6a, 0xc8, 0x08, + 0x00, 0x09, 0x42, 0x21, + 0x00, 0x0a, 0x44, 0x21, + 0xff, 0x6a, 0x70, 0x08, + 0x00, 0x65, 0x68, 0x43, + 0x03, 0x08, 0x40, 0x31, + 0x03, 0x08, 0x40, 0x31, + 0x01, 0x08, 0x40, 0x31, + 0x01, 0x09, 0x42, 0x31, + 0x01, 0x0a, 0x44, 0x31, + 0xfd, 0xb4, 0x68, 0x09, + 0x12, 0x01, 0x02, 0x00, + 0x12, 0x01, 0x02, 0x00, + 0x04, 0x3c, 0xbe, 0x79, + 0xfb, 0x3c, 0x78, 0x08, + 0x04, 0x93, 0x2e, 0x79, + 0x01, 0x0c, 0x7c, 0x6b, + 0x00, 0x65, 0x2e, 0x41, + 0x00, 0x65, 0xbe, 0x41, + 0x00, 0x65, 0x52, 0x5d, + 0x01, 0xbc, 0x18, 0x31, + 0x02, 0x6a, 0x1a, 0x31, + 0x02, 0x6a, 0xf8, 0x01, + 0x01, 0xbc, 0x10, 0x30, + 0x02, 0x6a, 0x12, 0x30, + 0x01, 0xbc, 0x10, 0x30, + 0xff, 0x6a, 0x12, 0x08, + 0xff, 0x6a, 0x14, 0x08, + 0xf3, 0xbc, 0xd4, 0x18, + 0xa0, 0x6a, 0xaa, 0x53, + 0x04, 0xa0, 0x10, 0x31, + 0xac, 0x6a, 0x26, 0x01, + 0x04, 0xa0, 0x10, 0x31, + 0x03, 0x08, 0x18, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0xa0, 0x6a, 0xbc, 0x5d, + 0x00, 0xbc, 0xa8, 0x5d, + 0x3d, 0x6a, 0x26, 0x01, + 0x00, 0x65, 0xc2, 0x43, + 0xff, 0x6a, 0x10, 0x09, + 0xa4, 0x6a, 0x26, 0x01, + 0x0c, 0xa0, 0x32, 0x31, + 0x05, 0x6a, 0x26, 0x01, + 0x35, 0x6a, 0x26, 0x01, + 0x0c, 0xa0, 0x32, 0x31, + 0x36, 0x6a, 0x26, 0x01, + 0x02, 0x93, 0x26, 0x01, + 0x35, 0x6a, 0x26, 0x01, + 0x00, 0x65, 0x60, 0x5e, + 0x00, 0x65, 0x60, 0x5e, + 0x02, 0x93, 0x26, 0x01, + 0x04, 0x0b, 0xc6, 0x6b, + 0x10, 0x0c, 0xc2, 0x7b, + 0x01, 0x03, 0xc6, 0x6b, + 0xc7, 0x93, 0x26, 0x09, + 0x38, 0x93, 0xca, 0x6b, + 0x10, 0x01, 0x02, 0x00, + 0x00, 0x65, 0xbe, 0x41, + 0x00, 0x65, 0x52, 0x5d, + 0x01, 0x06, 0x50, 0x31, + 0x00, 0x65, 0xbe, 0x41, + 0x10, 0x3f, 0x06, 0x00, + 0x01, 0x3a, 0xca, 0x30, + 0x80, 0x65, 0x04, 0x64, + 0x10, 0xb8, 0x28, 0x6c, + 0x01, 0xb9, 0xdc, 0x30, + 0x01, 0x6e, 0xc8, 0x30, + 0x01, 0x54, 0xca, 0x30, + 0x80, 0xb9, 0xe8, 0x7b, + 0x01, 0x55, 0xca, 0x30, + 0x80, 0xb9, 0xec, 0x7b, + 0x01, 0x55, 0xca, 0x30, + 0x00, 0x65, 0x28, 0x6c, + 0xc0, 0xba, 0xca, 0x00, + 0x40, 0xb8, 0xf4, 0x6b, + 0xbf, 0x65, 0xca, 0x08, + 0x20, 0xb8, 0x08, 0x7c, + 0x01, 0x65, 0x0c, 0x30, + 0x00, 0x65, 0xa0, 0x5d, + 0xa0, 0x3f, 0x10, 0x64, + 0x23, 0xb8, 0x0c, 0x08, + 0x00, 0x65, 0xa0, 0x5d, + 0xa0, 0x3f, 0x10, 0x64, + 0x00, 0xbb, 0x08, 0x44, + 0xff, 0x65, 0x08, 0x64, + 0x00, 0x65, 0x28, 0x44, + 0x40, 0x6a, 0x18, 0x00, + 0x01, 0x65, 0x0c, 0x30, + 0x00, 0x65, 0xa0, 0x5d, + 0xa0, 0x3f, 0xd6, 0x73, + 0x40, 0x6a, 0x18, 0x00, + 0x01, 0x3a, 0xa6, 0x30, + 0x08, 0x6a, 0x74, 0x00, + 0x00, 0x65, 0xbe, 0x41, + 0x64, 0x6a, 0x2c, 0x5d, + 0x80, 0x64, 0x9e, 0x6c, + 0x04, 0x64, 0x74, 0x74, + 0x02, 0x64, 0x82, 0x74, + 0x00, 0x6a, 0x44, 0x74, + 0x03, 0x64, 0x90, 0x74, + 0x23, 0x64, 0x30, 0x74, + 0x08, 0x64, 0x40, 0x74, + 0x61, 0x6a, 0x96, 0x5e, + 0x00, 0x65, 0xa0, 0x5d, + 0x08, 0x51, 0xc0, 0x71, + 0x00, 0x65, 0x28, 0x44, + 0x80, 0x04, 0x3e, 0x7c, + 0x51, 0x6a, 0x22, 0x5d, + 0x01, 0x51, 0x3e, 0x64, + 0x01, 0xa4, 0x3a, 0x7c, + 0x01, 0x57, 0x40, 0x7c, + 0x41, 0x6a, 0x96, 0x5e, + 0x00, 0x65, 0x40, 0x44, + 0x07, 0x6a, 0x1a, 0x5d, + 0x01, 0x06, 0xd4, 0x30, + 0x00, 0x65, 0xbe, 0x41, + 0x10, 0xb8, 0x48, 0x7c, + 0xa1, 0x6a, 0x96, 0x5e, + 0x01, 0xb4, 0x4e, 0x6c, + 0x02, 0xb4, 0x50, 0x6c, + 0x01, 0xa4, 0x50, 0x7c, + 0xff, 0xa8, 0x60, 0x7c, + 0x04, 0xb4, 0x68, 0x01, + 0x01, 0x6a, 0x76, 0x00, + 0x00, 0xbb, 0xda, 0x5d, + 0xff, 0xa8, 0x60, 0x7c, + 0x71, 0x6a, 0x96, 0x5e, + 0x40, 0x51, 0x60, 0x64, + 0x00, 0x65, 0x76, 0x5e, + 0x00, 0x65, 0xd0, 0x41, + 0x00, 0xbb, 0x64, 0x5c, + 0x00, 0x65, 0xd0, 0x41, + 0x00, 0x65, 0x76, 0x5e, + 0x01, 0x65, 0xa2, 0x30, + 0x01, 0xf8, 0xc8, 0x30, + 0x01, 0x4e, 0xc8, 0x30, + 0x00, 0x6a, 0x7e, 0xdd, + 0x00, 0x51, 0x90, 0x5d, + 0x01, 0x4e, 0x9c, 0x18, + 0x02, 0x6a, 0x22, 0x05, + 0x04, 0xb8, 0x70, 0x01, + 0x00, 0x65, 0x92, 0x5e, + 0x20, 0xb8, 0xd0, 0x69, + 0x01, 0xbb, 0xa2, 0x30, + 0x01, 0xba, 0x7c, 0x30, + 0x00, 0xb9, 0x94, 0x5c, + 0x00, 0x65, 0xd0, 0x41, + 0x20, 0x3c, 0x40, 0x7c, + 0x04, 0x14, 0x58, 0x31, + 0x08, 0xa0, 0x60, 0x31, + 0xac, 0x6a, 0xcc, 0x00, + 0x14, 0x6a, 0xbc, 0x5d, + 0xa0, 0x6a, 0xb4, 0x5d, + 0x00, 0x65, 0x40, 0x44, + 0xdf, 0x3c, 0x78, 0x08, + 0x00, 0x65, 0x40, 0x44, + 0x4c, 0x65, 0xcc, 0x28, + 0x01, 0x3e, 0x20, 0x31, + 0xd0, 0x66, 0xcc, 0x18, + 0x20, 0x66, 0xcc, 0x18, + 0x01, 0x51, 0xda, 0x34, + 0x4c, 0x3d, 0xca, 0x28, + 0x3f, 0x64, 0x7c, 0x08, + 0xd0, 0x65, 0xca, 0x18, + 0x01, 0x3e, 0x20, 0x31, + 0x30, 0x65, 0xd4, 0x18, + 0x00, 0x65, 0xac, 0x4c, + 0xe1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x20, 0x65, 0xd4, 0x18, + 0x00, 0x65, 0xb4, 0x54, + 0xe1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x20, 0x65, 0xca, 0x18, + 0xe0, 0x65, 0xd4, 0x18, + 0x00, 0x65, 0xbe, 0x4c, + 0xe1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0xd0, 0x65, 0xd4, 0x18, + 0x00, 0x65, 0xc6, 0x54, + 0xe1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x01, 0x6c, 0xa2, 0x30, + 0xff, 0x51, 0xd8, 0x74, + 0x00, 0x51, 0x56, 0x5d, + 0x01, 0x51, 0x20, 0x31, + 0x00, 0x65, 0xfa, 0x44, + 0x01, 0xba, 0xc8, 0x30, + 0x00, 0x3e, 0xfa, 0x74, + 0x00, 0x65, 0x74, 0x5e, + 0x80, 0x3c, 0x78, 0x00, + 0x01, 0x06, 0xd4, 0x30, + 0x00, 0x65, 0xa0, 0x5d, + 0x01, 0x3c, 0x78, 0x00, + 0xe0, 0x3f, 0x16, 0x65, + 0x02, 0x3c, 0x78, 0x00, + 0x20, 0x12, 0x16, 0x65, + 0x51, 0x6a, 0x22, 0x5d, + 0x00, 0x51, 0x56, 0x5d, + 0x51, 0x6a, 0x22, 0x5d, + 0x01, 0x51, 0x20, 0x31, + 0x04, 0x3c, 0x78, 0x00, + 0x01, 0xb9, 0xc8, 0x30, + 0x00, 0x3d, 0x14, 0x65, + 0x08, 0x3c, 0x78, 0x00, + 0x01, 0xba, 0xc8, 0x30, + 0x00, 0x3e, 0x14, 0x65, + 0x10, 0x3c, 0x78, 0x00, + 0x04, 0xb8, 0x14, 0x7d, + 0xfb, 0xb8, 0x70, 0x09, + 0x20, 0xb8, 0x0a, 0x6d, + 0x01, 0x90, 0xc8, 0x30, + 0xff, 0x6a, 0xa2, 0x00, + 0x00, 0x3d, 0x94, 0x5c, + 0x01, 0x64, 0x20, 0x31, + 0x80, 0x6a, 0x78, 0x00, + 0x00, 0x65, 0x02, 0x59, + 0x10, 0xb8, 0x40, 0x7c, + 0xff, 0x6a, 0x1a, 0x5d, + 0x00, 0x65, 0x40, 0x44, + 0x00, 0x65, 0x74, 0x5e, + 0x31, 0x6a, 0x96, 0x5e, + 0x00, 0x65, 0x40, 0x44, + 0x10, 0x3f, 0x06, 0x00, + 0x01, 0x65, 0x74, 0x34, + 0x81, 0x6a, 0x96, 0x5e, + 0x00, 0x65, 0x24, 0x45, + 0x01, 0x06, 0xd4, 0x30, + 0x01, 0x0c, 0x24, 0x7d, + 0x04, 0x0c, 0x1e, 0x6d, + 0xe0, 0x03, 0x7e, 0x08, + 0xe0, 0x3f, 0xbe, 0x61, + 0x01, 0x65, 0xcc, 0x30, + 0x01, 0x12, 0xda, 0x34, + 0x01, 0x06, 0xd4, 0x34, + 0x01, 0x03, 0x32, 0x6d, + 0x40, 0x03, 0xcc, 0x08, + 0x01, 0x65, 0x06, 0x30, + 0x40, 0x65, 0xc8, 0x08, + 0x00, 0x66, 0x40, 0x75, + 0x40, 0x65, 0x40, 0x7d, + 0x00, 0x65, 0x40, 0x5d, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x0c, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0x4a, 0x7d, + 0x01, 0x65, 0x0c, 0x30, + 0x02, 0x0b, 0x4e, 0x7d, + 0xf7, 0x01, 0x02, 0x0c, + 0x80, 0x3c, 0x9a, 0x6e, + 0x21, 0x6a, 0x96, 0x46, + 0x01, 0x65, 0xc8, 0x30, + 0xff, 0x41, 0x76, 0x75, + 0x01, 0x41, 0x20, 0x31, + 0xff, 0x6a, 0xa4, 0x00, + 0x00, 0x65, 0x66, 0x45, + 0xff, 0xbf, 0x76, 0x75, + 0x01, 0x90, 0xa4, 0x30, + 0x01, 0xbf, 0x20, 0x31, + 0x00, 0xbb, 0x60, 0x65, + 0xff, 0x52, 0x74, 0x75, + 0x01, 0xbf, 0xcc, 0x30, + 0x01, 0x90, 0xca, 0x30, + 0x01, 0x52, 0x20, 0x31, + 0x01, 0x66, 0x7e, 0x31, + 0x01, 0x65, 0x20, 0x35, + 0x01, 0xbf, 0x82, 0x34, + 0x01, 0x64, 0xa2, 0x30, + 0x00, 0x6a, 0x7e, 0x5e, + 0x0d, 0x6a, 0x76, 0x00, + 0x00, 0x51, 0xda, 0x45, + 0x01, 0x65, 0xa4, 0x30, + 0xe0, 0x6a, 0xcc, 0x00, + 0x48, 0x6a, 0xce, 0x5d, + 0x01, 0x6a, 0xd0, 0x01, + 0x01, 0x6a, 0xdc, 0x05, + 0x88, 0x6a, 0xcc, 0x00, + 0x48, 0x6a, 0xce, 0x5d, + 0x01, 0x6a, 0xa8, 0x5d, + 0x01, 0x6a, 0x26, 0x05, + 0x01, 0x65, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0x94, 0x7d, + 0xff, 0x6a, 0xdc, 0x0d, + 0x01, 0x65, 0x32, 0x31, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x6c, 0x46, + 0x81, 0x6a, 0x96, 0x5e, + 0x01, 0x0c, 0xa0, 0x7d, + 0x04, 0x0c, 0x9e, 0x6d, + 0xe0, 0x03, 0x06, 0x08, + 0xe0, 0x03, 0x7e, 0x0c, + 0x01, 0x65, 0x18, 0x31, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x0d, + 0x01, 0x8c, 0x10, 0x30, + 0x01, 0x8d, 0x12, 0x30, + 0x01, 0x8e, 0x14, 0x34, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x34, + 0x3d, 0x64, 0xa4, 0x28, + 0x55, 0x64, 0xc8, 0x28, + 0x00, 0x65, 0xce, 0x45, + 0x2e, 0x64, 0xa4, 0x28, + 0x66, 0x64, 0xc8, 0x28, + 0x00, 0x6c, 0xda, 0x18, + 0x01, 0x52, 0xc8, 0x30, + 0x00, 0x6c, 0xda, 0x20, + 0xff, 0x6a, 0xc8, 0x08, + 0x00, 0x6c, 0xda, 0x20, + 0x00, 0x6c, 0xda, 0x24, + 0x01, 0x65, 0xc8, 0x30, + 0xe0, 0x6a, 0xcc, 0x00, + 0x44, 0x6a, 0xca, 0x5d, + 0x01, 0x90, 0xe2, 0x31, + 0x04, 0x3b, 0xee, 0x7d, + 0x30, 0x6a, 0xd0, 0x01, + 0x20, 0x6a, 0xd0, 0x01, + 0x1d, 0x6a, 0xdc, 0x01, + 0xdc, 0xee, 0xea, 0x65, + 0x00, 0x65, 0x06, 0x46, + 0x20, 0x6a, 0xd0, 0x01, + 0x01, 0x6a, 0xdc, 0x01, + 0x20, 0xa0, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xf6, 0x7d, + 0x11, 0x6a, 0xdc, 0x01, + 0x50, 0xee, 0xfa, 0x65, + 0x20, 0x6a, 0xd0, 0x01, + 0x09, 0x6a, 0xdc, 0x01, + 0x88, 0xee, 0x00, 0x66, + 0x19, 0x6a, 0xdc, 0x01, + 0xd8, 0xee, 0x04, 0x66, + 0xff, 0x6a, 0xdc, 0x09, + 0x18, 0xee, 0x08, 0x6e, + 0xff, 0x6a, 0xd4, 0x0c, + 0x88, 0x6a, 0xcc, 0x00, + 0x44, 0x6a, 0xca, 0x5d, + 0x20, 0x6a, 0xa8, 0x5d, + 0x01, 0x3b, 0x26, 0x31, + 0x04, 0x3b, 0x22, 0x6e, + 0xa0, 0x6a, 0xca, 0x00, + 0x20, 0x65, 0xc8, 0x18, + 0x00, 0x65, 0x5c, 0x5e, + 0x00, 0x65, 0x1a, 0x66, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x6c, 0x46, + 0xa0, 0x6a, 0xcc, 0x00, + 0xff, 0x6a, 0xc8, 0x08, + 0x01, 0x94, 0x26, 0x6e, + 0x10, 0x94, 0x28, 0x6e, + 0x08, 0x94, 0x3e, 0x6e, + 0x08, 0x94, 0x3e, 0x6e, + 0x08, 0x94, 0x3e, 0x6e, + 0x07, 0x8c, 0xca, 0x18, + 0x3d, 0x65, 0xca, 0x28, + 0x00, 0x65, 0xc8, 0x18, + 0x00, 0x65, 0x42, 0x5e, + 0xff, 0x65, 0xca, 0x10, + 0x05, 0x65, 0xc8, 0x18, + 0x00, 0x65, 0x26, 0x46, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x40, 0x6e, + 0x00, 0x62, 0xc4, 0x18, + 0x00, 0x65, 0x6c, 0x5e, + 0x00, 0x65, 0x4c, 0x5e, + 0x00, 0x65, 0x4c, 0x5e, + 0x00, 0x65, 0x4c, 0x5e, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x34, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x35, + 0x08, 0x94, 0x6c, 0x7e, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x70, 0x6e, + 0xff, 0x6a, 0xd4, 0x0c, + 0x04, 0xb8, 0x92, 0x6e, + 0x01, 0x42, 0x7e, 0x31, + 0xff, 0x6a, 0x76, 0x01, + 0x01, 0x90, 0x84, 0x34, + 0xff, 0x6a, 0x76, 0x05, + 0xff, 0x42, 0x8e, 0x66, + 0xff, 0x41, 0x86, 0x66, + 0xd1, 0x6a, 0x96, 0x5e, + 0xff, 0x6a, 0xca, 0x04, + 0x01, 0x41, 0x20, 0x31, + 0x01, 0xbf, 0x82, 0x30, + 0x01, 0x6a, 0x76, 0x00, + 0x00, 0xbb, 0xda, 0x45, + 0x01, 0x42, 0x20, 0x31, + 0x01, 0xbf, 0x84, 0x34, + 0x01, 0x41, 0x7e, 0x31, + 0x01, 0x90, 0x82, 0x34, + 0x01, 0x65, 0x22, 0x31, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x0c +}; + +static int ahc_patch22_func(struct ahc_softc *ahc); + +static int +ahc_patch22_func(struct ahc_softc *ahc) +{ + return ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0); +} + +static int ahc_patch21_func(struct ahc_softc *ahc); + +static int +ahc_patch21_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_CMD_CHAN) == 0); +} + +static int ahc_patch20_func(struct ahc_softc *ahc); + +static int +ahc_patch20_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_QUEUE_REGS) == 0); +} + +static int ahc_patch19_func(struct ahc_softc *ahc); + +static int +ahc_patch19_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_WIDE) != 0); +} + +static int ahc_patch18_func(struct ahc_softc *ahc); + +static int +ahc_patch18_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_SCB_BTT) != 0); +} + +static int ahc_patch17_func(struct ahc_softc *ahc); + +static int +ahc_patch17_func(struct ahc_softc *ahc) +{ + return ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0); +} + +static int ahc_patch16_func(struct ahc_softc *ahc); + +static int +ahc_patch16_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0); +} + +static int ahc_patch15_func(struct ahc_softc *ahc); + +static int +ahc_patch15_func(struct ahc_softc *ahc) +{ + return ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0); +} + +static int ahc_patch14_func(struct ahc_softc *ahc); + +static int +ahc_patch14_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_DT) == 0); +} + +static int ahc_patch13_func(struct ahc_softc *ahc); + +static int +ahc_patch13_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA2) == 0); +} + +static int ahc_patch12_func(struct ahc_softc *ahc); + +static int +ahc_patch12_func(struct ahc_softc *ahc) +{ + return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); +} + +static int ahc_patch11_func(struct ahc_softc *ahc); + +static int +ahc_patch11_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA) != 0); +} + +static int ahc_patch10_func(struct ahc_softc *ahc); + +static int +ahc_patch10_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_HS_MAILBOX) != 0); +} + +static int ahc_patch9_func(struct ahc_softc *ahc); + +static int +ahc_patch9_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_MULTI_TID) != 0); +} + +static int ahc_patch8_func(struct ahc_softc *ahc); + +static int +ahc_patch8_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_CMD_CHAN) != 0); +} + +static int ahc_patch7_func(struct ahc_softc *ahc); + +static int +ahc_patch7_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_INITIATORROLE) != 0); +} + +static int ahc_patch6_func(struct ahc_softc *ahc); + +static int +ahc_patch6_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_TARGETROLE) != 0); +} + +static int ahc_patch5_func(struct ahc_softc *ahc); + +static int +ahc_patch5_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0); +} + +static int ahc_patch4_func(struct ahc_softc *ahc); + +static int +ahc_patch4_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_PAGESCBS) != 0); +} + +static int ahc_patch3_func(struct ahc_softc *ahc); + +static int +ahc_patch3_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_QUEUE_REGS) != 0); +} + +static int ahc_patch2_func(struct ahc_softc *ahc); + +static int +ahc_patch2_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_TWIN) != 0); +} + +static int ahc_patch1_func(struct ahc_softc *ahc); + +static int +ahc_patch1_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA2) != 0); +} + +static int ahc_patch0_func(struct ahc_softc *ahc); + +static int +ahc_patch0_func(struct ahc_softc *ahc) +{ + return (0); +} + +typedef int patch_func_t (struct ahc_softc *); +struct patch { + patch_func_t *patch_func; + uint32_t begin :10, + skip_instr :10, + skip_patch :12; +} patches[] = { + { ahc_patch1_func, 4, 1, 1 }, + { ahc_patch2_func, 6, 2, 1 }, + { ahc_patch2_func, 9, 1, 1 }, + { ahc_patch3_func, 11, 1, 2 }, + { ahc_patch0_func, 12, 2, 1 }, + { ahc_patch4_func, 15, 1, 2 }, + { ahc_patch0_func, 16, 1, 1 }, + { ahc_patch5_func, 22, 2, 1 }, + { ahc_patch3_func, 27, 1, 2 }, + { ahc_patch0_func, 28, 1, 1 }, + { ahc_patch6_func, 37, 65, 21 }, + { ahc_patch7_func, 37, 1, 1 }, + { ahc_patch8_func, 45, 3, 2 }, + { ahc_patch0_func, 48, 3, 1 }, + { ahc_patch9_func, 52, 1, 2 }, + { ahc_patch0_func, 53, 2, 3 }, + { ahc_patch1_func, 53, 1, 2 }, + { ahc_patch0_func, 54, 1, 1 }, + { ahc_patch2_func, 56, 2, 1 }, + { ahc_patch8_func, 58, 1, 2 }, + { ahc_patch0_func, 59, 1, 1 }, + { ahc_patch8_func, 63, 1, 2 }, + { ahc_patch0_func, 64, 1, 1 }, + { ahc_patch8_func, 73, 1, 2 }, + { ahc_patch0_func, 74, 1, 1 }, + { ahc_patch8_func, 77, 1, 2 }, + { ahc_patch0_func, 78, 1, 1 }, + { ahc_patch10_func, 88, 1, 2 }, + { ahc_patch0_func, 89, 1, 1 }, + { ahc_patch8_func, 97, 1, 2 }, + { ahc_patch0_func, 98, 1, 1 }, + { ahc_patch7_func, 102, 9, 4 }, + { ahc_patch1_func, 104, 1, 2 }, + { ahc_patch0_func, 105, 1, 1 }, + { ahc_patch2_func, 107, 2, 1 }, + { ahc_patch2_func, 116, 4, 1 }, + { ahc_patch1_func, 120, 1, 2 }, + { ahc_patch0_func, 121, 2, 3 }, + { ahc_patch2_func, 121, 1, 2 }, + { ahc_patch0_func, 122, 1, 1 }, + { ahc_patch6_func, 123, 4, 2 }, + { ahc_patch0_func, 127, 1, 1 }, + { ahc_patch11_func, 129, 2, 1 }, + { ahc_patch1_func, 131, 1, 2 }, + { ahc_patch0_func, 132, 1, 1 }, + { ahc_patch6_func, 133, 4, 1 }, + { ahc_patch6_func, 144, 77, 9 }, + { ahc_patch4_func, 156, 1, 1 }, + { ahc_patch1_func, 172, 1, 1 }, + { ahc_patch8_func, 180, 1, 2 }, + { ahc_patch0_func, 181, 1, 1 }, + { ahc_patch8_func, 190, 1, 2 }, + { ahc_patch0_func, 191, 1, 1 }, + { ahc_patch8_func, 207, 6, 2 }, + { ahc_patch0_func, 213, 6, 1 }, + { ahc_patch7_func, 221, 18, 2 }, + { ahc_patch1_func, 234, 1, 1 }, + { ahc_patch1_func, 241, 1, 2 }, + { ahc_patch0_func, 242, 2, 2 }, + { ahc_patch11_func, 243, 1, 1 }, + { ahc_patch8_func, 251, 33, 2 }, + { ahc_patch1_func, 267, 16, 1 }, + { ahc_patch12_func, 284, 14, 1 }, + { ahc_patch1_func, 298, 2, 2 }, + { ahc_patch0_func, 300, 3, 3 }, + { ahc_patch8_func, 300, 1, 2 }, + { ahc_patch0_func, 301, 2, 1 }, + { ahc_patch1_func, 305, 1, 2 }, + { ahc_patch0_func, 306, 1, 1 }, + { ahc_patch8_func, 310, 1, 1 }, + { ahc_patch8_func, 313, 2, 2 }, + { ahc_patch0_func, 315, 4, 1 }, + { ahc_patch12_func, 319, 1, 1 }, + { ahc_patch13_func, 322, 2, 3 }, + { ahc_patch8_func, 322, 1, 2 }, + { ahc_patch0_func, 323, 1, 1 }, + { ahc_patch1_func, 332, 40, 6 }, + { ahc_patch6_func, 341, 1, 1 }, + { ahc_patch7_func, 342, 1, 1 }, + { ahc_patch14_func, 344, 2, 1 }, + { ahc_patch15_func, 346, 5, 1 }, + { ahc_patch0_func, 372, 51, 15 }, + { ahc_patch12_func, 372, 1, 1 }, + { ahc_patch6_func, 374, 2, 2 }, + { ahc_patch16_func, 375, 1, 1 }, + { ahc_patch8_func, 378, 1, 1 }, + { ahc_patch17_func, 385, 1, 1 }, + { ahc_patch12_func, 390, 9, 3 }, + { ahc_patch8_func, 391, 3, 2 }, + { ahc_patch0_func, 394, 3, 1 }, + { ahc_patch8_func, 402, 6, 2 }, + { ahc_patch0_func, 408, 8, 1 }, + { ahc_patch12_func, 416, 1, 1 }, + { ahc_patch8_func, 418, 1, 2 }, + { ahc_patch0_func, 419, 1, 1 }, + { ahc_patch6_func, 422, 1, 1 }, + { ahc_patch6_func, 423, 1, 1 }, + { ahc_patch7_func, 424, 2, 1 }, + { ahc_patch8_func, 426, 1, 1 }, + { ahc_patch12_func, 427, 9, 4 }, + { ahc_patch8_func, 427, 1, 1 }, + { ahc_patch8_func, 434, 2, 1 }, + { ahc_patch0_func, 436, 4, 3 }, + { ahc_patch8_func, 436, 1, 2 }, + { ahc_patch0_func, 437, 3, 1 }, + { ahc_patch1_func, 441, 2, 1 }, + { ahc_patch6_func, 443, 5, 2 }, + { ahc_patch0_func, 448, 1, 1 }, + { ahc_patch7_func, 449, 113, 22 }, + { ahc_patch1_func, 450, 3, 2 }, + { ahc_patch0_func, 453, 5, 3 }, + { ahc_patch8_func, 453, 2, 2 }, + { ahc_patch0_func, 455, 3, 1 }, + { ahc_patch1_func, 460, 2, 2 }, + { ahc_patch0_func, 462, 6, 3 }, + { ahc_patch8_func, 462, 2, 2 }, + { ahc_patch0_func, 464, 3, 1 }, + { ahc_patch1_func, 470, 2, 2 }, + { ahc_patch0_func, 472, 9, 7 }, + { ahc_patch8_func, 472, 5, 6 }, + { ahc_patch18_func, 472, 1, 2 }, + { ahc_patch0_func, 473, 1, 1 }, + { ahc_patch18_func, 475, 1, 2 }, + { ahc_patch0_func, 476, 1, 1 }, + { ahc_patch0_func, 477, 4, 1 }, + { ahc_patch1_func, 486, 1, 1 }, + { ahc_patch2_func, 498, 2, 2 }, + { ahc_patch0_func, 500, 2, 2 }, + { ahc_patch19_func, 500, 2, 1 }, + { ahc_patch19_func, 536, 7, 1 }, + { ahc_patch3_func, 564, 1, 2 }, + { ahc_patch0_func, 565, 1, 1 }, + { ahc_patch20_func, 568, 1, 1 }, + { ahc_patch7_func, 570, 95, 26 }, + { ahc_patch4_func, 571, 1, 1 }, + { ahc_patch8_func, 578, 2, 2 }, + { ahc_patch0_func, 580, 3, 1 }, + { ahc_patch18_func, 587, 2, 2 }, + { ahc_patch0_func, 589, 1, 1 }, + { ahc_patch18_func, 593, 10, 3 }, + { ahc_patch5_func, 595, 8, 1 }, + { ahc_patch0_func, 603, 9, 2 }, + { ahc_patch5_func, 604, 8, 1 }, + { ahc_patch4_func, 614, 1, 2 }, + { ahc_patch0_func, 615, 1, 1 }, + { ahc_patch18_func, 616, 1, 2 }, + { ahc_patch0_func, 617, 3, 2 }, + { ahc_patch4_func, 619, 1, 1 }, + { ahc_patch5_func, 620, 1, 1 }, + { ahc_patch5_func, 623, 1, 1 }, + { ahc_patch5_func, 625, 1, 1 }, + { ahc_patch4_func, 627, 2, 2 }, + { ahc_patch0_func, 629, 2, 1 }, + { ahc_patch5_func, 631, 1, 1 }, + { ahc_patch5_func, 634, 1, 1 }, + { ahc_patch5_func, 637, 1, 1 }, + { ahc_patch18_func, 641, 1, 1 }, + { ahc_patch18_func, 644, 1, 1 }, + { ahc_patch4_func, 650, 1, 1 }, + { ahc_patch6_func, 665, 16, 1 }, + { ahc_patch4_func, 683, 20, 1 }, + { ahc_patch8_func, 704, 4, 2 }, + { ahc_patch0_func, 708, 4, 1 }, + { ahc_patch8_func, 712, 4, 2 }, + { ahc_patch0_func, 716, 3, 1 }, + { ahc_patch21_func, 724, 14, 1 }, + { ahc_patch6_func, 738, 3, 1 }, + { ahc_patch8_func, 750, 24, 8 }, + { ahc_patch18_func, 754, 1, 2 }, + { ahc_patch0_func, 755, 1, 1 }, + { ahc_patch13_func, 760, 4, 2 }, + { ahc_patch0_func, 764, 7, 3 }, + { ahc_patch22_func, 764, 5, 2 }, + { ahc_patch0_func, 769, 2, 1 }, + { ahc_patch0_func, 774, 40, 3 }, + { ahc_patch17_func, 786, 16, 2 }, + { ahc_patch0_func, 802, 1, 1 }, + { ahc_patch4_func, 826, 1, 1 }, + { ahc_patch4_func, 827, 3, 2 }, + { ahc_patch0_func, 830, 1, 1 }, + { ahc_patch4_func, 831, 12, 1 } +}; +struct cs { + u_int16_t begin; + u_int16_t end; +} critical_sections[] = { + { 11, 18 }, + { 21, 30 }, + { 683, 699 }, + { 827, 830 }, + { 831, 837 }, + { 839, 841 }, + { 841, 843 } +}; +const int num_critical_sections = sizeof(critical_sections) + / sizeof(*critical_sections); diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/Makefile linux/drivers/scsi/aic7xxx/aicasm/Makefile --- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aicasm/Makefile Tue Mar 6 22:44:16 2001 @@ -0,0 +1,28 @@ +PROG= aicasm + +CSRCS= aicasm.c aicasm_symbol.c +GENSRCS= aicasm_gram.c aicasm_scan.c + +GENHDRS= y.tab.h + +SRCS= ${GENSRCS} ${CSRCS} +CLEANFILES= ${GENSRCS} ${GENHDRS} y.output +# Override default kernel CFLAGS. This is a userland app. +AICASM_CFLAGS:= -I/usr/include -ldb1 +YFLAGS= -d + +NOMAN= noman + +ifdef DEBUG +CFLAGS+= -DDEBUG -g +YFLAGS+= -t -v +LFLAGS= -d +endif + +.SUFFIXES= .l .y .c + +$(PROG): $(SRCS) + $(HOSTCC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) + +clean: + rm -f $(CLEANFILES) $(PROG) diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm.c linux/drivers/scsi/aic7xxx/aicasm/aicasm.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,777 @@ +/* + * Aic7xxx SCSI host adapter firmware asssembler + * + * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aicasm/aicasm.c#6 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.c,v 1.29 2000/10/05 04:25:42 gibbs Exp $ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "aicasm_insformat.h" + +typedef struct patch { + STAILQ_ENTRY(patch) links; + int patch_func; + u_int begin; + u_int skip_instr; + u_int skip_patch; +} patch_t; + +STAILQ_HEAD(patch_list, patch) patches; + +static void usage(void); +static void back_patch(void); +static void output_code(void); +static void output_listing(char *ifilename); +static void dump_scope(scope_t *scope); +static void emit_patch(scope_t *scope, int patch); +static int check_patch(patch_t **start_patch, int start_instr, + int *skip_addr, int *func_vals); + +struct path_list search_path; +int includes_search_curdir; +char *appname; +FILE *ofile; +char *ofilename; +char *regfilename; +FILE *regfile; +char *listfilename; +FILE *listfile; + +static STAILQ_HEAD(,instruction) seq_program; +struct cs_tailq cs_tailq; +struct scope_list scope_stack; +symlist_t patch_functions; + +#if DEBUG +extern int yy_flex_debug; +extern int yydebug; +#endif +extern FILE *yyin; +extern int yyparse(void); + +int main(int argc, char *argv[]); + +int +main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + int ch; + int retval; + char *inputfilename; + scope_t *sentinal; + + STAILQ_INIT(&patches); + SLIST_INIT(&search_path); + STAILQ_INIT(&seq_program); + TAILQ_INIT(&cs_tailq); + SLIST_INIT(&scope_stack); + + /* Set Sentinal scope node */ + sentinal = scope_alloc(); + sentinal->type = SCOPE_ROOT; + + includes_search_curdir = 1; + appname = *argv; + regfile = NULL; + listfile = NULL; +#if DEBUG + yy_flex_debug = 0; + yydebug = 0; +#endif + while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) { + switch(ch) { + case 'd': +#if DEBUG + if (strcmp(optarg, "s") == 0) { + yy_flex_debug = 1; + } else if (strcmp(optarg, "p") == 0) { + yydebug = 1; + } else { + fprintf(stderr, "%s: -d Requires either an " + "'s' or 'p' argument\n", appname); + usage(); + } +#else + stop("-d: Assembler not built with debugging " + "information", EX_SOFTWARE); +#endif + break; + case 'l': + /* Create a program listing */ + if ((listfile = fopen(optarg, "w")) == NULL) { + perror(optarg); + stop(NULL, EX_CANTCREAT); + } + listfilename = optarg; + break; + case 'n': + /* Don't complain about the -nostdinc directrive */ + if (strcmp(optarg, "ostdinc")) { + fprintf(stderr, "%s: Unknown option -%c%s\n", + appname, ch, optarg); + usage(); + /* NOTREACHED */ + } + break; + case 'o': + if ((ofile = fopen(optarg, "w")) == NULL) { + perror(optarg); + stop(NULL, EX_CANTCREAT); + } + ofilename = optarg; + break; + case 'r': + if ((regfile = fopen(optarg, "w")) == NULL) { + perror(optarg); + stop(NULL, EX_CANTCREAT); + } + regfilename = optarg; + break; + case 'I': + { + path_entry_t include_dir; + + if (strcmp(optarg, "-") == 0) { + if (includes_search_curdir == 0) { + fprintf(stderr, "%s: Warning - '-I-' " + "specified multiple " + "times\n", appname); + } + includes_search_curdir = 0; + for (include_dir = search_path.slh_first; + include_dir != NULL; + include_dir = include_dir->links.sle_next) + /* + * All entries before a '-I-' only + * apply to includes specified with + * quotes instead of "<>". + */ + include_dir->quoted_includes_only = 1; + } else { + include_dir = + (path_entry_t)malloc(sizeof(*include_dir)); + if (include_dir == NULL) { + perror(optarg); + stop(NULL, EX_OSERR); + } + include_dir->directory = strdup(optarg); + if (include_dir->directory == NULL) { + perror(optarg); + stop(NULL, EX_OSERR); + } + include_dir->quoted_includes_only = 0; + SLIST_INSERT_HEAD(&search_path, include_dir, + links); + } + break; + } + case '?': + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc != 1) { + fprintf(stderr, "%s: No input file specifiled\n", appname); + usage(); + /* NOTREACHED */ + } + + symtable_open(); + inputfilename = *argv; + include_file(*argv, SOURCE_FILE); + retval = yyparse(); + if (retval == 0) { + if (SLIST_FIRST(&scope_stack) == NULL + || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { + stop("Unterminated conditional expression", + EX_DATAERR); + /* NOTREACHED */ + } + + /* Process outmost scope */ + process_scope(SLIST_FIRST(&scope_stack)); + /* + * Decend the tree of scopes and insert/emit + * patches as appropriate. We perform a depth first + * tranversal, recursively handling each scope. + */ + /* start at the root scope */ + dump_scope(SLIST_FIRST(&scope_stack)); + + /* Patch up forward jump addresses */ + back_patch(); + + if (ofile != NULL) + output_code(); + if (regfile != NULL) { + symtable_dump(regfile); + } + if (listfile != NULL) + output_listing(inputfilename); + } + + stop(NULL, 0); + /* NOTREACHED */ + return (0); +} + +static void +usage() +{ + + (void)fprintf(stderr, +"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file] + [-r register_output_file] [-l program_list_file] + input_file\n", + appname); + exit(EX_USAGE); +} + +static void +back_patch() +{ + struct instruction *cur_instr; + + for(cur_instr = seq_program.stqh_first; + cur_instr != NULL; + cur_instr = cur_instr->links.stqe_next) { + if (cur_instr->patch_label != NULL) { + struct ins_format3 *f3_instr; + u_int address; + + if (cur_instr->patch_label->type != LABEL) { + char buf[255]; + + snprintf(buf, sizeof(buf), + "Undefined label %s", + cur_instr->patch_label->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + } + f3_instr = &cur_instr->format.format3; + address = f3_instr->address; + address += cur_instr->patch_label->info.linfo->address; + f3_instr->address = address; + } + } +} + +static void +output_code() +{ + struct instruction *cur_instr; + patch_t *cur_patch; + critical_section_t *cs; + symbol_node_t *cur_node; + int instrcount; + + instrcount = 0; + fprintf(ofile, +"/* + * DO NOT EDIT - This file is automatically generated. + */\n"); + + fprintf(ofile, "static uint8_t seqprog[] = {\n"); + for(cur_instr = seq_program.stqh_first; + cur_instr != NULL; + cur_instr = cur_instr->links.stqe_next) { + + fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x", + cur_instr == seq_program.stqh_first ? "" : ",\n", +#if BYTE_ORDER == LITTLE_ENDIAN + cur_instr->format.bytes[0], + cur_instr->format.bytes[1], + cur_instr->format.bytes[2], + cur_instr->format.bytes[3]); +#else + cur_instr->format.bytes[3], + cur_instr->format.bytes[2], + cur_instr->format.bytes[1], + cur_instr->format.bytes[0]); +#endif + instrcount++; + } + fprintf(ofile, "\n};\n\n"); + + /* + * Output patch information. Patch functions first. + */ + for(cur_node = SLIST_FIRST(&patch_functions); + cur_node != NULL; + cur_node = SLIST_NEXT(cur_node,links)) { + fprintf(ofile, +"static int ahc_patch%d_func(struct ahc_softc *ahc); + +static int +ahc_patch%d_func(struct ahc_softc *ahc) +{ + return (%s); +}\n\n", + cur_node->symbol->info.condinfo->func_num, + cur_node->symbol->info.condinfo->func_num, + cur_node->symbol->name); + } + + fprintf(ofile, +"typedef int patch_func_t (struct ahc_softc *); +struct patch { + patch_func_t *patch_func; + uint32_t begin :10, + skip_instr :10, + skip_patch :12; +} patches[] = {\n"); + + for(cur_patch = STAILQ_FIRST(&patches); + cur_patch != NULL; + cur_patch = STAILQ_NEXT(cur_patch,links)) { + fprintf(ofile, "%s\t{ ahc_patch%d_func, %d, %d, %d }", + cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n", + cur_patch->patch_func, cur_patch->begin, + cur_patch->skip_instr, cur_patch->skip_patch); + } + + fprintf(ofile, "\n};\n"); + + fprintf(ofile, +"struct cs { + u_int16_t begin; + u_int16_t end; +} critical_sections[] = {\n"); + + for(cs = TAILQ_FIRST(&cs_tailq); + cs != NULL; + cs = TAILQ_NEXT(cs, links)) { + fprintf(ofile, "%s\t{ %d, %d }", + cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n", + cs->begin_addr, cs->end_addr); + } + + fprintf(ofile, "\n};\n"); + + fprintf(ofile, +"const int num_critical_sections = sizeof(critical_sections) + / sizeof(*critical_sections);\n"); + + fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); +} + +static void +dump_scope(scope_t *scope) +{ + scope_t *cur_scope; + + /* + * Emit the first patch for this scope + */ + emit_patch(scope, 0); + + /* + * Dump each scope within this one. + */ + cur_scope = TAILQ_FIRST(&scope->inner_scope); + + while (cur_scope != NULL) { + + dump_scope(cur_scope); + + cur_scope = TAILQ_NEXT(cur_scope, scope_links); + } + + /* + * Emit the second, closing, patch for this scope + */ + emit_patch(scope, 1); +} + +void +emit_patch(scope_t *scope, int patch) +{ + patch_info_t *pinfo; + patch_t *new_patch; + + pinfo = &scope->patches[patch]; + + if (pinfo->skip_instr == 0) + /* No-Op patch */ + return; + + new_patch = (patch_t *)malloc(sizeof(*new_patch)); + + if (new_patch == NULL) + stop("Could not malloc patch structure", EX_OSERR); + + memset(new_patch, 0, sizeof(*new_patch)); + + if (patch == 0) { + new_patch->patch_func = scope->func_num; + new_patch->begin = scope->begin_addr; + } else { + new_patch->patch_func = 0; + new_patch->begin = scope->end_addr; + } + new_patch->skip_instr = pinfo->skip_instr; + new_patch->skip_patch = pinfo->skip_patch; + STAILQ_INSERT_TAIL(&patches, new_patch, links); +} + +void +output_listing(char *ifilename) +{ + char buf[1024]; + FILE *ifile; + struct instruction *cur_instr; + patch_t *cur_patch; + symbol_node_t *cur_func; + int *func_values; + int instrcount; + int instrptr; + int line; + int func_count; + int skip_addr; + + instrcount = 0; + instrptr = 0; + line = 1; + skip_addr = 0; + if ((ifile = fopen(ifilename, "r")) == NULL) { + perror(ifilename); + stop(NULL, EX_DATAERR); + } + + /* + * Determine which options to apply to this listing. + */ + for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions); + cur_func != NULL; + cur_func = SLIST_NEXT(cur_func, links)) + func_count++; + + func_values = NULL; + if (func_count != 0) { + func_values = (int *)malloc(func_count * sizeof(int)); + + if (func_values == NULL) + stop("Could not malloc", EX_OSERR); + + func_values[0] = 0; /* FALSE func */ + func_count--; + + /* + * Ask the user to fill in the return values for + * the rest of the functions. + */ + + + for (cur_func = SLIST_FIRST(&patch_functions); + cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL; + cur_func = SLIST_NEXT(cur_func, links), func_count--) { + int input; + + fprintf(stdout, "\n(%s)\n", cur_func->symbol->name); + fprintf(stdout, + "Enter the return value for " + "this expression[T/F]:"); + + while (1) { + + input = getchar(); + input = toupper(input); + + if (input == 'T') { + func_values[func_count] = 1; + break; + } else if (input == 'F') { + func_values[func_count] = 0; + break; + } + } + if (isatty(fileno(stdin)) == 0) + putchar(input); + } + fprintf(stdout, "\nThanks!\n"); + } + + /* Now output the listing */ + cur_patch = STAILQ_FIRST(&patches); + for(cur_instr = STAILQ_FIRST(&seq_program); + cur_instr != NULL; + cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) { + + if (check_patch(&cur_patch, instrcount, + &skip_addr, func_values) == 0) { + /* Don't count this instruction as it is in a patch + * that was removed. + */ + continue; + } + + while (line < cur_instr->srcline) { + fgets(buf, sizeof(buf), ifile); + fprintf(listfile, "\t\t%s", buf); + line++; + } + fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, +#if BYTE_ORDER == LITTLE_ENDIAN + cur_instr->format.bytes[0], + cur_instr->format.bytes[1], + cur_instr->format.bytes[2], + cur_instr->format.bytes[3]); +#else + cur_instr->format.bytes[3], + cur_instr->format.bytes[2], + cur_instr->format.bytes[1], + cur_instr->format.bytes[0]); +#endif + fgets(buf, sizeof(buf), ifile); + fprintf(listfile, "\t%s", buf); + line++; + instrptr++; + } + /* Dump the remainder of the file */ + while(fgets(buf, sizeof(buf), ifile) != NULL) + fprintf(listfile, "\t\t%s", buf); + + fclose(ifile); +} + +static int +check_patch(patch_t **start_patch, int start_instr, + int *skip_addr, int *func_vals) +{ + patch_t *cur_patch; + + cur_patch = *start_patch; + + while (cur_patch != NULL && start_instr == cur_patch->begin) { + if (func_vals[cur_patch->patch_func] == 0) { + int skip; + + /* Start rejecting code */ + *skip_addr = start_instr + cur_patch->skip_instr; + for (skip = cur_patch->skip_patch; + skip > 0 && cur_patch != NULL; + skip--) + cur_patch = STAILQ_NEXT(cur_patch, links); + } else { + /* Accepted this patch. Advance to the next + * one and wait for our intruction pointer to + * hit this point. + */ + cur_patch = STAILQ_NEXT(cur_patch, links); + } + } + + *start_patch = cur_patch; + if (start_instr < *skip_addr) + /* Still skipping */ + return (0); + + return (1); +} + +/* + * Print out error information if appropriate, and clean up before + * terminating the program. + */ +void +stop(const char *string, int err_code) +{ + if (string != NULL) { + fprintf(stderr, "%s: ", appname); + if (yyfilename != NULL) { + fprintf(stderr, "Stopped at file %s, line %d - ", + yyfilename, yylineno); + } + fprintf(stderr, "%s\n", string); + } + + if (ofile != NULL) { + fclose(ofile); + if (err_code != 0) { + fprintf(stderr, "%s: Removing %s due to error\n", + appname, ofilename); + unlink(ofilename); + } + } + + if (regfile != NULL) { + fclose(regfile); + if (err_code != 0) { + fprintf(stderr, "%s: Removing %s due to error\n", + appname, regfilename); + unlink(regfilename); + } + } + + if (listfile != NULL) { + fclose(listfile); + if (err_code != 0) { + fprintf(stderr, "%s: Removing %s due to error\n", + appname, listfilename); + unlink(listfilename); + } + } + + symlist_free(&patch_functions); + symtable_close(); + + exit(err_code); +} + +struct instruction * +seq_alloc() +{ + struct instruction *new_instr; + + new_instr = (struct instruction *)malloc(sizeof(struct instruction)); + if (new_instr == NULL) + stop("Unable to malloc instruction object", EX_SOFTWARE); + memset(new_instr, 0, sizeof(*new_instr)); + STAILQ_INSERT_TAIL(&seq_program, new_instr, links); + new_instr->srcline = yylineno; + return new_instr; +} + +critical_section_t * +cs_alloc() +{ + critical_section_t *new_cs; + + new_cs= (critical_section_t *)malloc(sizeof(critical_section_t)); + if (new_cs == NULL) + stop("Unable to malloc critical_section object", EX_SOFTWARE); + memset(new_cs, 0, sizeof(*new_cs)); + + TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links); + return new_cs; +} + +scope_t * +scope_alloc() +{ + scope_t *new_scope; + + new_scope = (scope_t *)malloc(sizeof(scope_t)); + if (new_scope == NULL) + stop("Unable to malloc scope object", EX_SOFTWARE); + memset(new_scope, 0, sizeof(*new_scope)); + TAILQ_INIT(&new_scope->inner_scope); + + if (SLIST_FIRST(&scope_stack) != NULL) { + TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope, + new_scope, scope_links); + } + /* This patch is now the current scope */ + SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links); + return new_scope; +} + +void +process_scope(scope_t *scope) +{ + /* + * We are "leaving" this scope. We should now have + * enough information to process the lists of scopes + * we encapsulate. + */ + scope_t *cur_scope; + u_int skip_patch_count; + u_int skip_instr_count; + + cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq); + skip_patch_count = 0; + skip_instr_count = 0; + while (cur_scope != NULL) { + u_int patch0_patch_skip; + + patch0_patch_skip = 0; + switch (cur_scope->type) { + case SCOPE_IF: + case SCOPE_ELSE_IF: + if (skip_instr_count != 0) { + /* Create a tail patch */ + patch0_patch_skip++; + cur_scope->patches[1].skip_patch = + skip_patch_count + 1; + cur_scope->patches[1].skip_instr = + skip_instr_count; + } + + /* Count Head patch */ + patch0_patch_skip++; + + /* Count any patches contained in our inner scope */ + patch0_patch_skip += cur_scope->inner_scope_patches; + + cur_scope->patches[0].skip_patch = patch0_patch_skip; + cur_scope->patches[0].skip_instr = + cur_scope->end_addr - cur_scope->begin_addr; + + skip_instr_count += cur_scope->patches[0].skip_instr; + + skip_patch_count += patch0_patch_skip; + if (cur_scope->type == SCOPE_IF) { + scope->inner_scope_patches += skip_patch_count; + skip_patch_count = 0; + skip_instr_count = 0; + } + break; + case SCOPE_ELSE: + /* Count any patches contained in our innter scope */ + skip_patch_count += cur_scope->inner_scope_patches; + + skip_instr_count += cur_scope->end_addr + - cur_scope->begin_addr; + break; + case SCOPE_ROOT: + stop("Unexpected scope type encountered", EX_SOFTWARE); + /* NOTREACHED */ + } + + cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links); + } +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm.h linux/drivers/scsi/aic7xxx/aicasm/aicasm.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,78 @@ +/* + * Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aicasm/aicasm.h#4 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.h,v 1.11 2000/09/22 22:19:54 gibbs Exp $ + */ + +#ifdef __linux__ +#include "../queue.h" +#else +#include +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +typedef struct path_entry { + char *directory; + int quoted_includes_only; + SLIST_ENTRY(path_entry) links; +} *path_entry_t; + +typedef enum { + QUOTED_INCLUDE, + BRACKETED_INCLUDE, + SOURCE_FILE +} include_type; + +SLIST_HEAD(path_list, path_entry); + +extern struct path_list search_path; +extern struct cs_tailq cs_tailq; +extern struct scope_list scope_stack; +extern struct symlist patch_functions; +extern int includes_search_curdir; /* False if we've seen -I- */ +extern char *appname; +extern int yylineno; +extern char *yyfilename; + +void stop(const char *errstring, int err_code); +void include_file(char *file_name, include_type type); +struct instruction *seq_alloc(void); +struct critical_section *cs_alloc(void); +struct scope *scope_alloc(void); +void process_scope(struct scope *); diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y linux/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y --- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y Sun Mar 4 14:30:18 2001 @@ -0,0 +1,1455 @@ +%{ +/* + * Parser for the Aic7xxx SCSI Host adapter sequencer assembler. + * + * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aicasm/aicasm_gram.y#6 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_gram.y,v 1.12 2000/10/31 18:44:32 gibbs Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#ifdef __linux__ +#include "../queue.h" +#else +#include +#endif + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "aicasm_insformat.h" + +int yylineno; +char *yyfilename; +static symbol_t *cur_symbol; +static symtype cur_symtype; +static symbol_t *accumulator; +static symbol_ref_t allones; +static symbol_ref_t allzeros; +static symbol_ref_t none; +static symbol_ref_t sindex; +static int instruction_ptr; +static int sram_or_scb_offset; +static int download_constant_count; +static int in_critical_section; + +static void process_bitmask(int mask_type, symbol_t *sym, int mask); +static void initialize_symbol(symbol_t *symbol); +static void process_register(symbol_t **p_symbol); +static void format_1_instr(int opcode, symbol_ref_t *dest, + expression_t *immed, symbol_ref_t *src, int ret); +static void format_2_instr(int opcode, symbol_ref_t *dest, + expression_t *places, symbol_ref_t *src, int ret); +static void format_3_instr(int opcode, symbol_ref_t *src, + expression_t *immed, symbol_ref_t *address); +static void test_readable_symbol(symbol_t *symbol); +static void test_writable_symbol(symbol_t *symbol); +static void type_check(symbol_t *symbol, expression_t *expression, int and_op); +static void make_expression(expression_t *immed, int value); +static void add_conditional(symbol_t *symbol); +static int is_download_const(expression_t *immed); + +#define YYDEBUG 1 +#define SRAM_SYMNAME "SRAM_BASE" +#define SCB_SYMNAME "SCB_BASE" +%} + +%union { + int value; + char *str; + symbol_t *sym; + symbol_ref_t sym_ref; + expression_t expression; +} + +%token T_REGISTER + +%token T_CONST + +%token T_DOWNLOAD + +%token T_SCB + +%token T_SRAM + +%token T_ALIAS + +%token T_SIZE + +%token T_ADDRESS + +%token T_ACCESS_MODE + +%token T_MODE + +%token T_BEGIN_CS + +%token T_END_CS + +%token T_BIT + +%token T_MASK + +%token T_NUMBER + +%token T_PATH + +%token T_CEXPR + +%token T_EOF T_INCLUDE + +%token T_SHR T_SHL T_ROR T_ROL + +%token T_MVI T_MOV T_CLR T_BMOV + +%token T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL + +%token T_ADD T_ADC + +%token T_INC T_DEC + +%token T_STC T_CLC + +%token T_CMP T_NOT T_XOR + +%token T_TEST T_AND + +%token T_OR + +%token T_RET + +%token T_NOP + +%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX + +%token T_A + +%token T_SYMBOL + +%token T_NL + +%token T_IF T_ELSE T_ELSE_IF T_ENDIF + +%type reg_symbol address destination source opt_source + +%type expression immediate immediate_or_a + +%type ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne + +%type numerical_value + +%left '|' +%left '&' +%left '+' '-' +%right '~' +%nonassoc UMINUS +%% + +program: + include +| program include +| register +| program register +| constant +| program constant +| scratch_ram +| program scratch_ram +| scb +| program scb +| label +| program label +| critical_section_start +| program critical_section_start +| critical_section_end +| program critical_section_end +| conditional +| program conditional +| code +| program code +; + +include: + T_INCLUDE '<' T_PATH '>' + { include_file($3, BRACKETED_INCLUDE); } +| T_INCLUDE '"' T_PATH '"' + { include_file($3, QUOTED_INCLUDE); } +; + +register: + T_REGISTER { cur_symtype = REGISTER; } reg_definition +; + +reg_definition: + T_SYMBOL '{' + { + if ($1->type != UNINITIALIZED) { + stop("Register multiply defined", EX_DATAERR); + /* NOTREACHED */ + } + cur_symbol = $1; + cur_symbol->type = cur_symtype; + initialize_symbol(cur_symbol); + } + reg_attribute_list + '}' + { + /* + * Default to allowing everything in for registers + * with no bit or mask definitions. + */ + if (cur_symbol->info.rinfo->valid_bitmask == 0) + cur_symbol->info.rinfo->valid_bitmask = 0xFF; + + if (cur_symbol->info.rinfo->size == 0) + cur_symbol->info.rinfo->size = 1; + + /* + * This might be useful for registers too. + */ + if (cur_symbol->type != REGISTER) { + if (cur_symbol->info.rinfo->address == 0) + cur_symbol->info.rinfo->address = + sram_or_scb_offset; + sram_or_scb_offset += + cur_symbol->info.rinfo->size; + } + cur_symbol = NULL; + } +; + +reg_attribute_list: + reg_attribute +| reg_attribute_list reg_attribute +; + +reg_attribute: + reg_address +| size +| access_mode +| bit_defn +| mask_defn +| alias +| accumulator +| allones +| allzeros +| none +| sindex +; + +reg_address: + T_ADDRESS T_NUMBER + { + cur_symbol->info.rinfo->address = $2; + } +; + +size: + T_SIZE T_NUMBER + { + cur_symbol->info.rinfo->size = $2; + } +; + +access_mode: + T_ACCESS_MODE T_MODE + { + cur_symbol->info.rinfo->mode = $2; + } +; + +bit_defn: + T_BIT T_SYMBOL T_NUMBER + { + process_bitmask(BIT, $2, $3); + } +; + +mask_defn: + T_MASK T_SYMBOL expression + { + process_bitmask(MASK, $2, $3.value); + } +; + +alias: + T_ALIAS T_SYMBOL + { + if ($2->type != UNINITIALIZED) { + stop("Re-definition of register alias", + EX_DATAERR); + /* NOTREACHED */ + } + $2->type = ALIAS; + initialize_symbol($2); + $2->info.ainfo->parent = cur_symbol; + } +; + +accumulator: + T_ACCUM + { + if (accumulator != NULL) { + stop("Only one accumulator definition allowed", + EX_DATAERR); + /* NOTREACHED */ + } + accumulator = cur_symbol; + } +; + +allones: + T_ALLONES + { + if (allones.symbol != NULL) { + stop("Only one definition of allones allowed", + EX_DATAERR); + /* NOTREACHED */ + } + allones.symbol = cur_symbol; + } +; + +allzeros: + T_ALLZEROS + { + if (allzeros.symbol != NULL) { + stop("Only one definition of allzeros allowed", + EX_DATAERR); + /* NOTREACHED */ + } + allzeros.symbol = cur_symbol; + } +; + +none: + T_NONE + { + if (none.symbol != NULL) { + stop("Only one definition of none allowed", + EX_DATAERR); + /* NOTREACHED */ + } + none.symbol = cur_symbol; + } +; + +sindex: + T_SINDEX + { + if (sindex.symbol != NULL) { + stop("Only one definition of sindex allowed", + EX_DATAERR); + /* NOTREACHED */ + } + sindex.symbol = cur_symbol; + } +; + +expression: + expression '|' expression + { + $$.value = $1.value | $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } +| expression '&' expression + { + $$.value = $1.value & $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } +| expression '+' expression + { + $$.value = $1.value + $3.value; + symlist_merge(&$$.referenced_syms, + &$1.referenced_syms, + &$3.referenced_syms); + } +| expression '-' expression + { + $$.value = $1.value - $3.value; + symlist_merge(&($$.referenced_syms), + &($1.referenced_syms), + &($3.referenced_syms)); + } +| '(' expression ')' + { + $$ = $2; + } +| '~' expression + { + $$ = $2; + $$.value = (~$$.value) & 0xFF; + } +| '-' expression %prec UMINUS + { + $$ = $2; + $$.value = -$$.value; + } +| T_NUMBER + { + $$.value = $1; + SLIST_INIT(&$$.referenced_syms); + } +| T_SYMBOL + { + symbol_t *symbol; + + symbol = $1; + switch (symbol->type) { + case ALIAS: + symbol = $1->info.ainfo->parent; + case REGISTER: + case SCBLOC: + case SRAMLOC: + $$.value = symbol->info.rinfo->address; + break; + case MASK: + case BIT: + $$.value = symbol->info.minfo->mask; + break; + case DOWNLOAD_CONST: + case CONST: + $$.value = symbol->info.cinfo->value; + break; + case UNINITIALIZED: + default: + { + char buf[255]; + + snprintf(buf, sizeof(buf), + "Undefined symbol %s referenced", + symbol->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + break; + } + } + SLIST_INIT(&$$.referenced_syms); + symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD); + } +; + +constant: + T_CONST T_SYMBOL numerical_value + { + if ($2->type != UNINITIALIZED) { + stop("Re-definition of symbol as a constant", + EX_DATAERR); + /* NOTREACHED */ + } + $2->type = CONST; + initialize_symbol($2); + $2->info.cinfo->value = $3; + $2->info.cinfo->define = $1; + } +| T_CONST T_SYMBOL T_DOWNLOAD + { + if ($1) { + stop("Invalid downloaded constant declaration", + EX_DATAERR); + /* NOTREACHED */ + } + if ($2->type != UNINITIALIZED) { + stop("Re-definition of symbol as a downloaded constant", + EX_DATAERR); + /* NOTREACHED */ + } + $2->type = DOWNLOAD_CONST; + initialize_symbol($2); + $2->info.cinfo->value = download_constant_count++; + $2->info.cinfo->define = FALSE; + } +; + +numerical_value: + T_NUMBER + { + $$ = $1; + } +| '-' T_NUMBER + { + $$ = -$2; + } +; + +scratch_ram: + T_SRAM '{' + { + cur_symbol = symtable_get(SRAM_SYMNAME); + cur_symtype = SRAMLOC; + if (cur_symbol->type != UNINITIALIZED) { + stop("Only one SRAM definition allowed", + EX_DATAERR); + /* NOTREACHED */ + } + cur_symbol->type = SRAMLOC; + initialize_symbol(cur_symbol); + } + reg_address + { + sram_or_scb_offset = cur_symbol->info.rinfo->address; + } + scb_or_sram_reg_list + '}' + { + cur_symbol = NULL; + } +; + +scb: + T_SCB '{' + { + cur_symbol = symtable_get(SCB_SYMNAME); + cur_symtype = SCBLOC; + if (cur_symbol->type != UNINITIALIZED) { + stop("Only one SRAM definition allowed", + EX_SOFTWARE); + /* NOTREACHED */ + } + cur_symbol->type = SCBLOC; + initialize_symbol(cur_symbol); + /* 64 bytes of SCB space */ + cur_symbol->info.rinfo->size = 64; + } + reg_address + { + sram_or_scb_offset = cur_symbol->info.rinfo->address; + } + scb_or_sram_reg_list + '}' + { + cur_symbol = NULL; + } +; + +scb_or_sram_reg_list: + reg_definition +| scb_or_sram_reg_list reg_definition +; + +reg_symbol: + T_SYMBOL + { + process_register(&$1); + $$.symbol = $1; + $$.offset = 0; + } +| T_SYMBOL '[' T_SYMBOL ']' + { + process_register(&$1); + if ($3->type != CONST) { + stop("register offset must be a constant", EX_DATAERR); + /* NOTREACHED */ + } + if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) { + stop("Accessing offset beyond range of register", + EX_DATAERR); + /* NOTREACHED */ + } + $$.symbol = $1; + $$.offset = $3->info.cinfo->value; + } +| T_SYMBOL '[' T_NUMBER ']' + { + process_register(&$1); + if (($3 + 1) > $1->info.rinfo->size) { + stop("Accessing offset beyond range of register", + EX_DATAERR); + /* NOTREACHED */ + } + $$.symbol = $1; + $$.offset = $3; + } +| T_A + { + if (accumulator == NULL) { + stop("No accumulator has been defined", EX_DATAERR); + /* NOTREACHED */ + } + $$.symbol = accumulator; + $$.offset = 0; + } +; + +destination: + reg_symbol + { + test_writable_symbol($1.symbol); + $$ = $1; + } +; + +immediate: + expression + { $$ = $1; } +; + +immediate_or_a: + expression + { + $$ = $1; + } +| T_A + { + SLIST_INIT(&$$.referenced_syms); + $$.value = 0; + } +; + +source: + reg_symbol + { + test_readable_symbol($1.symbol); + $$ = $1; + } +; + +opt_source: + { + $$.symbol = NULL; + $$.offset = 0; + } +| ',' source + { $$ = $2; } +; + +ret: + { $$ = 0; } +| T_RET + { $$ = 1; } +; + +critical_section_start: + T_BEGIN_CS + { + critical_section_t *cs; + + if (in_critical_section != FALSE) { + stop("Critical Section within Critical Section", + EX_DATAERR); + /* NOTREACHED */ + } + cs = cs_alloc(); + cs->begin_addr = instruction_ptr; + in_critical_section = TRUE; + } + +critical_section_end: + T_END_CS + { + critical_section_t *cs; + + if (in_critical_section == FALSE) { + stop("Unballanced 'end_cs'", EX_DATAERR); + /* NOTREACHED */ + } + cs = TAILQ_LAST(&cs_tailq, cs_tailq); + cs->end_addr = instruction_ptr; + in_critical_section = FALSE; + } + +label: + T_SYMBOL ':' + { + if ($1->type != UNINITIALIZED) { + stop("Program label multiply defined", EX_DATAERR); + /* NOTREACHED */ + } + $1->type = LABEL; + initialize_symbol($1); + $1->info.linfo->address = instruction_ptr; + } +; + +address: + T_SYMBOL + { + $$.symbol = $1; + $$.offset = 0; + } +| T_SYMBOL '+' T_NUMBER + { + $$.symbol = $1; + $$.offset = $3; + } +| T_SYMBOL '-' T_NUMBER + { + $$.symbol = $1; + $$.offset = -$3; + } +| '.' + { + $$.symbol = NULL; + $$.offset = 0; + } +| '.' '+' T_NUMBER + { + $$.symbol = NULL; + $$.offset = $3; + } +| '.' '-' T_NUMBER + { + $$.symbol = NULL; + $$.offset = -$3; + } +; + +conditional: + T_IF T_CEXPR '{' + { + scope_t *new_scope; + + add_conditional($2); + new_scope = scope_alloc(); + new_scope->type = SCOPE_IF; + new_scope->begin_addr = instruction_ptr; + new_scope->func_num = $2->info.condinfo->func_num; + } +| T_ELSE T_IF T_CEXPR '{' + { + scope_t *new_scope; + scope_t *scope_context; + scope_t *last_scope; + + /* + * Ensure that the previous scope is either an + * if or and else if. + */ + scope_context = SLIST_FIRST(&scope_stack); + last_scope = TAILQ_LAST(&scope_context->inner_scope, + scope_tailq); + if (last_scope == NULL + || last_scope->type == T_ELSE) { + + stop("'else if' without leading 'if'", EX_DATAERR); + /* NOTREACHED */ + } + add_conditional($3); + new_scope = scope_alloc(); + new_scope->type = SCOPE_ELSE_IF; + new_scope->begin_addr = instruction_ptr; + new_scope->func_num = $3->info.condinfo->func_num; + } +| T_ELSE '{' + { + scope_t *new_scope; + scope_t *scope_context; + scope_t *last_scope; + + /* + * Ensure that the previous scope is either an + * if or and else if. + */ + scope_context = SLIST_FIRST(&scope_stack); + last_scope = TAILQ_LAST(&scope_context->inner_scope, + scope_tailq); + if (last_scope == NULL + || last_scope->type == SCOPE_ELSE) { + + stop("'else' without leading 'if'", EX_DATAERR); + /* NOTREACHED */ + } + new_scope = scope_alloc(); + new_scope->type = SCOPE_ELSE; + new_scope->begin_addr = instruction_ptr; + } +; + +conditional: + '}' + { + scope_t *scope_context; + + scope_context = SLIST_FIRST(&scope_stack); + if (scope_context->type == SCOPE_ROOT) { + stop("Unexpected '}' encountered", EX_DATAERR); + /* NOTREACHED */ + } + + scope_context->end_addr = instruction_ptr; + + /* Pop the scope */ + SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links); + + process_scope(scope_context); + + if (SLIST_FIRST(&scope_stack) == NULL) { + stop("Unexpected '}' encountered", EX_DATAERR); + /* NOTREACHED */ + } + } +; + +f1_opcode: + T_AND { $$ = AIC_OP_AND; } +| T_XOR { $$ = AIC_OP_XOR; } +| T_ADD { $$ = AIC_OP_ADD; } +| T_ADC { $$ = AIC_OP_ADC; } +; + +code: + f1_opcode destination ',' immediate_or_a opt_source ret ';' + { + format_1_instr($1, &$2, &$4, &$5, $6); + } +; + +code: + T_OR reg_symbol ',' immediate_or_a opt_source ret ';' + { + format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6); + } +; + +code: + T_INC destination opt_source ret ';' + { + expression_t immed; + + make_expression(&immed, 1); + format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); + } +; + +code: + T_DEC destination opt_source ret ';' + { + expression_t immed; + + make_expression(&immed, -1); + format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); + } +; + +code: + T_CLC ret ';' + { + expression_t immed; + + make_expression(&immed, -1); + format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2); + } +| T_CLC T_MVI destination ',' immediate_or_a ret ';' + { + format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6); + } +; + +code: + T_STC ret ';' + { + expression_t immed; + + make_expression(&immed, 1); + format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2); + } +| T_STC destination ret ';' + { + expression_t immed; + + make_expression(&immed, 1); + format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3); + } +; + +code: + T_BMOV destination ',' source ',' immediate ret ';' + { + format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7); + } +; + +code: + T_MOV destination ',' source ret ';' + { + expression_t immed; + + make_expression(&immed, 1); + format_1_instr(AIC_OP_BMOV, &$2, &immed, &$4, $5); + } +; + +code: + T_MVI destination ',' immediate_or_a ret ';' + { + format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5); + } +; + +code: + T_NOT destination opt_source ret ';' + { + expression_t immed; + + make_expression(&immed, 0xff); + format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4); + } +; + +code: + T_CLR destination ret ';' + { + expression_t immed; + + make_expression(&immed, 0xff); + format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3); + } +; + +code: + T_NOP ret ';' + { + expression_t immed; + + make_expression(&immed, 0xff); + format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2); + } +; + +code: + T_RET ';' + { + expression_t immed; + + make_expression(&immed, 0xff); + format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE); + } +; + + /* + * This grammer differs from the one in the aic7xxx + * reference manual since the grammer listed there is + * ambiguous and causes a shift/reduce conflict. + * It also seems more logical as the "immediate" + * argument is listed as the second arg like the + * other formats. + */ + +f2_opcode: + T_SHL { $$ = AIC_OP_SHL; } +| T_SHR { $$ = AIC_OP_SHR; } +| T_ROL { $$ = AIC_OP_ROL; } +| T_ROR { $$ = AIC_OP_ROR; } +; + +code: + f2_opcode destination ',' expression opt_source ret ';' + { + format_2_instr($1, &$2, &$4, &$5, $6); + } +; + +jmp_jc_jnc_call: + T_JMP { $$ = AIC_OP_JMP; } +| T_JC { $$ = AIC_OP_JC; } +| T_JNC { $$ = AIC_OP_JNC; } +| T_CALL { $$ = AIC_OP_CALL; } +; + +jz_jnz: + T_JZ { $$ = AIC_OP_JZ; } +| T_JNZ { $$ = AIC_OP_JNZ; } +; + +je_jne: + T_JE { $$ = AIC_OP_JE; } +| T_JNE { $$ = AIC_OP_JNE; } +; + +code: + jmp_jc_jnc_call address ';' + { + expression_t immed; + + make_expression(&immed, 0); + format_3_instr($1, &sindex, &immed, &$2); + } +; + +code: + T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';' + { + format_3_instr($5, &$2, &$4, &$6); + } +; + +code: + T_TEST source ',' immediate_or_a jz_jnz address ';' + { + format_3_instr($5, &$2, &$4, &$6); + } +; + +code: + T_CMP source ',' immediate_or_a je_jne address ';' + { + format_3_instr($5, &$2, &$4, &$6); + } +; + +code: + T_MOV source jmp_jc_jnc_call address ';' + { + expression_t immed; + + make_expression(&immed, 0); + format_3_instr($3, &$2, &immed, &$4); + } +; + +code: + T_MVI immediate jmp_jc_jnc_call address ';' + { + format_3_instr($3, &allzeros, &$2, &$4); + } +; + +%% + +static void +process_bitmask(int mask_type, symbol_t *sym, int mask) +{ + /* + * Add the current register to its + * symbol list, if it already exists, + * warn if we are setting it to a + * different value, or in the bit to + * the "allowed bits" of this register. + */ + if (sym->type == UNINITIALIZED) { + sym->type = mask_type; + initialize_symbol(sym); + if (mask_type == BIT) { + if (mask == 0) { + stop("Bitmask with no bits set", EX_DATAERR); + /* NOTREACHED */ + } + if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) { + stop("Bitmask with more than one bit set", + EX_DATAERR); + /* NOTREACHED */ + } + } + sym->info.minfo->mask = mask; + } else if (sym->type != mask_type) { + stop("Bit definition mirrors a definition of the same " + " name, but a different type", EX_DATAERR); + /* NOTREACHED */ + } else if (mask != sym->info.minfo->mask) { + stop("Bitmask redefined with a conflicting value", EX_DATAERR); + /* NOTREACHED */ + } + /* Fail if this symbol is already listed */ + if (symlist_search(&(sym->info.minfo->symrefs), + cur_symbol->name) != NULL) { + stop("Bitmask defined multiple times for register", EX_DATAERR); + /* NOTREACHED */ + } + symlist_add(&(sym->info.minfo->symrefs), cur_symbol, + SYMLIST_INSERT_HEAD); + cur_symbol->info.rinfo->valid_bitmask |= mask; + cur_symbol->info.rinfo->typecheck_masks = TRUE; +} + +static void +initialize_symbol(symbol_t *symbol) +{ + switch (symbol->type) { + case UNINITIALIZED: + stop("Call to initialize_symbol with type field unset", + EX_SOFTWARE); + /* NOTREACHED */ + break; + case REGISTER: + case SRAMLOC: + case SCBLOC: + symbol->info.rinfo = + (struct reg_info *)malloc(sizeof(struct reg_info)); + if (symbol->info.rinfo == NULL) { + stop("Can't create register info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.rinfo, 0, + sizeof(struct reg_info)); + break; + case ALIAS: + symbol->info.ainfo = + (struct alias_info *)malloc(sizeof(struct alias_info)); + if (symbol->info.ainfo == NULL) { + stop("Can't create alias info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.ainfo, 0, + sizeof(struct alias_info)); + break; + case MASK: + case BIT: + symbol->info.minfo = + (struct mask_info *)malloc(sizeof(struct mask_info)); + if (symbol->info.minfo == NULL) { + stop("Can't create bitmask info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.minfo, 0, sizeof(struct mask_info)); + SLIST_INIT(&(symbol->info.minfo->symrefs)); + break; + case CONST: + case DOWNLOAD_CONST: + symbol->info.cinfo = + (struct const_info *)malloc(sizeof(struct const_info)); + if (symbol->info.cinfo == NULL) { + stop("Can't create alias info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.cinfo, 0, + sizeof(struct const_info)); + break; + case LABEL: + symbol->info.linfo = + (struct label_info *)malloc(sizeof(struct label_info)); + if (symbol->info.linfo == NULL) { + stop("Can't create label info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.linfo, 0, + sizeof(struct label_info)); + break; + case CONDITIONAL: + symbol->info.condinfo = + (struct cond_info *)malloc(sizeof(struct cond_info)); + if (symbol->info.condinfo == NULL) { + stop("Can't create conditional info", EX_SOFTWARE); + /* NOTREACHED */ + } + memset(symbol->info.condinfo, 0, + sizeof(struct cond_info)); + break; + default: + stop("Call to initialize_symbol with invalid symbol type", + EX_SOFTWARE); + /* NOTREACHED */ + break; + } +} + +static void +process_register(symbol_t **p_symbol) +{ + char buf[255]; + symbol_t *symbol = *p_symbol; + + if (symbol->type == UNINITIALIZED) { + snprintf(buf, sizeof(buf), "Undefined register %s", + symbol->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + } else if (symbol->type == ALIAS) { + *p_symbol = symbol->info.ainfo->parent; + } else if ((symbol->type != REGISTER) + && (symbol->type != SCBLOC) + && (symbol->type != SRAMLOC)) { + snprintf(buf, sizeof(buf), + "Specified symbol %s is not a register", + symbol->name); + stop(buf, EX_DATAERR); + } +} + +static void +format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed, + symbol_ref_t *src, int ret) +{ + struct instruction *instr; + struct ins_format1 *f1_instr; + + if (src->symbol == NULL) + src = dest; + + /* Test register permissions */ + test_writable_symbol(dest->symbol); + test_readable_symbol(src->symbol); + + /* Ensure that immediate makes sense for this destination */ + type_check(dest->symbol, immed, opcode); + + /* Allocate sequencer space for the instruction and fill it out */ + instr = seq_alloc(); + f1_instr = &instr->format.format1; + f1_instr->ret = ret ? 1 : 0; + f1_instr->opcode = opcode; + f1_instr->destination = dest->symbol->info.rinfo->address + + dest->offset; + f1_instr->source = src->symbol->info.rinfo->address + + src->offset; + f1_instr->immediate = immed->value; + + if (is_download_const(immed)) + f1_instr->parity = 1; + + symlist_free(&immed->referenced_syms); + instruction_ptr++; +} + +static void +format_2_instr(int opcode, symbol_ref_t *dest, expression_t *places, + symbol_ref_t *src, int ret) +{ + struct instruction *instr; + struct ins_format2 *f2_instr; + uint8_t shift_control; + + if (src->symbol == NULL) + src = dest; + + /* Test register permissions */ + test_writable_symbol(dest->symbol); + test_readable_symbol(src->symbol); + + /* Allocate sequencer space for the instruction and fill it out */ + instr = seq_alloc(); + f2_instr = &instr->format.format2; + f2_instr->ret = ret ? 1 : 0; + f2_instr->opcode = AIC_OP_ROL; + f2_instr->destination = dest->symbol->info.rinfo->address + + dest->offset; + f2_instr->source = src->symbol->info.rinfo->address + + src->offset; + if (places->value > 8 || places->value <= 0) { + stop("illegal shift value", EX_DATAERR); + /* NOTREACHED */ + } + switch (opcode) { + case AIC_OP_SHL: + if (places->value == 8) + shift_control = 0xf0; + else + shift_control = (places->value << 4) | places->value; + break; + case AIC_OP_SHR: + if (places->value == 8) { + shift_control = 0xf8; + } else { + shift_control = (places->value << 4) + | (8 - places->value) + | 0x08; + } + break; + case AIC_OP_ROL: + shift_control = places->value & 0x7; + break; + case AIC_OP_ROR: + shift_control = (8 - places->value) | 0x08; + break; + default: + shift_control = 0; /* Quiet Compiler */ + stop("Invalid shift operation specified", EX_SOFTWARE); + /* NOTREACHED */ + break; + }; + f2_instr->shift_control = shift_control; + symlist_free(&places->referenced_syms); + instruction_ptr++; +} + +static void +format_3_instr(int opcode, symbol_ref_t *src, + expression_t *immed, symbol_ref_t *address) +{ + struct instruction *instr; + struct ins_format3 *f3_instr; + int addr; + + /* Test register permissions */ + test_readable_symbol(src->symbol); + + /* Ensure that immediate makes sense for this source */ + type_check(src->symbol, immed, opcode); + + /* Allocate sequencer space for the instruction and fill it out */ + instr = seq_alloc(); + f3_instr = &instr->format.format3; + if (address->symbol == NULL) { + /* 'dot' referrence. Use the current instruction pointer */ + addr = instruction_ptr + address->offset; + } else if (address->symbol->type == UNINITIALIZED) { + /* forward reference */ + addr = address->offset; + instr->patch_label = address->symbol; + } else + addr = address->symbol->info.linfo->address + address->offset; + f3_instr->opcode = opcode; + f3_instr->address = addr; + f3_instr->source = src->symbol->info.rinfo->address + + src->offset; + f3_instr->immediate = immed->value; + + if (is_download_const(immed)) + f3_instr->parity = 1; + + symlist_free(&immed->referenced_syms); + instruction_ptr++; +} + +static void +test_readable_symbol(symbol_t *symbol) +{ + if (symbol->info.rinfo->mode == WO) { + stop("Write Only register specified as source", + EX_DATAERR); + /* NOTREACHED */ + } +} + +static void +test_writable_symbol(symbol_t *symbol) +{ + if (symbol->info.rinfo->mode == RO) { + stop("Read Only register specified as destination", + EX_DATAERR); + /* NOTREACHED */ + } +} + +static void +type_check(symbol_t *symbol, expression_t *expression, int opcode) +{ + symbol_node_t *node; + int and_op; + char buf[255]; + + and_op = FALSE; + if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ) + and_op = TRUE; + + /* + * Make sure that we aren't attempting to write something + * that hasn't been defined. If this is an and operation, + * this is a mask, so "undefined" bits are okay. + */ + if (and_op == FALSE + && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) { + snprintf(buf, sizeof(buf), + "Invalid bit(s) 0x%x in immediate written to %s", + expression->value & ~symbol->info.rinfo->valid_bitmask, + symbol->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + } + + /* + * Now make sure that all of the symbols referenced by the + * expression are defined for this register. + */ + if(symbol->info.rinfo->typecheck_masks != FALSE) { + for(node = expression->referenced_syms.slh_first; + node != NULL; + node = node->links.sle_next) { + if ((node->symbol->type == MASK + || node->symbol->type == BIT) + && symlist_search(&node->symbol->info.minfo->symrefs, + symbol->name) == NULL) { + snprintf(buf, sizeof(buf), + "Invalid bit or mask %s " + "for register %s", + node->symbol->name, symbol->name); + stop(buf, EX_DATAERR); + /* NOTREACHED */ + } + } + } +} + +static void +make_expression(expression_t *immed, int value) +{ + SLIST_INIT(&immed->referenced_syms); + immed->value = value & 0xff; +} + +static void +add_conditional(symbol_t *symbol) +{ + static int numfuncs; + + if (numfuncs == 0) { + /* add a special conditional, "0" */ + symbol_t *false_func; + + false_func = symtable_get("0"); + if (false_func->type != UNINITIALIZED) { + stop("Conditional expression '0' " + "conflicts with a symbol", EX_DATAERR); + /* NOTREACHED */ + } + false_func->type = CONDITIONAL; + initialize_symbol(false_func); + false_func->info.condinfo->func_num = numfuncs++; + symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD); + } + + /* This condition has occurred before */ + if (symbol->type == CONDITIONAL) + return; + + if (symbol->type != UNINITIALIZED) { + stop("Conditional expression conflicts with a symbol", + EX_DATAERR); + /* NOTREACHED */ + } + + symbol->type = CONDITIONAL; + initialize_symbol(symbol); + symbol->info.condinfo->func_num = numfuncs++; + symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD); +} + +void +yyerror(const char *string) +{ + stop(string, EX_DATAERR); +} + +static int +is_download_const(expression_t *immed) +{ + if ((immed->referenced_syms.slh_first != NULL) + && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST)) + return (TRUE); + + return (FALSE); +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h linux/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,129 @@ +/* + * Instruction formats for the sequencer program downloaded to + * Aic7xxx SCSI host adapters + * + * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aicasm/aicasm_insformat.h#4 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_insformat.h,v 1.3 2000/09/22 22:19:54 gibbs Exp $ + */ + +#if linux +#include +#else +#include +#endif + +struct ins_format1 { +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t immediate : 8, + source : 9, + destination : 9, + ret : 1, + opcode : 4, + parity : 1; +#else + uint32_t parity : 1, + opcode : 4, + ret : 1, + destination : 9, + source : 9, + immediate : 8; +#endif +}; + +struct ins_format2 { +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t shift_control : 8, + source : 9, + destination : 9, + ret : 1, + opcode : 4, + parity : 1; +#else + uint32_t parity : 1, + opcode : 4, + ret : 1, + destination : 9, + source : 9, + shift_control : 8; +#endif +}; + +struct ins_format3 { +#if BYTE_ORDER == LITTLE_ENDIAN + uint32_t immediate : 8, + source : 9, + address : 10, + opcode : 4, + parity : 1; +#else + uint32_t parity : 1, + opcode : 4, + address : 10, + source : 9, + immediate : 8; +#endif +}; + +union ins_formats { + struct ins_format1 format1; + struct ins_format2 format2; + struct ins_format3 format3; + uint8_t bytes[4]; + uint32_t integer; +}; +struct instruction { + union ins_formats format; + u_int srcline; + struct symbol *patch_label; + STAILQ_ENTRY(instruction) links; +}; + +#define AIC_OP_OR 0x0 +#define AIC_OP_AND 0x1 +#define AIC_OP_XOR 0x2 +#define AIC_OP_ADD 0x3 +#define AIC_OP_ADC 0x4 +#define AIC_OP_ROL 0x5 +#define AIC_OP_BMOV 0x6 + +#define AIC_OP_JMP 0x8 +#define AIC_OP_JC 0x9 +#define AIC_OP_JNC 0xa +#define AIC_OP_CALL 0xb +#define AIC_OP_JNE 0xc +#define AIC_OP_JNZ 0xd +#define AIC_OP_JE 0xe +#define AIC_OP_JZ 0xf + +/* Pseudo Ops */ +#define AIC_OP_SHL 0x10 +#define AIC_OP_SHR 0x20 +#define AIC_OP_ROR 0x30 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l --- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l Sun Mar 4 14:30:18 2001 @@ -0,0 +1,302 @@ +%{ +/* + * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler. + * + * Copyright (c) 1997, 1998 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aicasm/aicasm_scan.l#4 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_scan.l,v 1.13 2000/09/22 22:19:54 gibbs Exp $ + */ + +#include + +#include +#include +#include +#include +#ifdef __linux__ +#include "../queue.h" +#else +#include +#endif + +#include "aicasm.h" +#include "aicasm_symbol.h" +#include "y.tab.h" + +#define MAX_STR_CONST 256 +char string_buf[MAX_STR_CONST]; +char *string_buf_ptr; +int parren_count; +%} + +PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]* +WORD [A-Za-z_][-A-Za-z_0-9]* +SPACE [ \t]+ + +%x COMMENT +%x CEXPR +%x INCLUDE + +%% +\n { ++yylineno; } +"/*" { BEGIN COMMENT; /* Enter comment eating state */ } +"/*" { fprintf(stderr, "Warning! Comment within comment."); } +\n { ++yylineno; } +[^*/\n]* ; +"*"+[^*/\n]* ; +"/"+[^*/\n]* ; +"*"+"/" { BEGIN INITIAL; } +if[ \t]*\( { + string_buf_ptr = string_buf; + parren_count = 1; + BEGIN CEXPR; + return T_IF; + } +\( { *string_buf_ptr++ = '('; parren_count++; } +\) { + parren_count--; + if (parren_count == 0) { + /* All done */ + BEGIN INITIAL; + *string_buf_ptr = '\0'; + yylval.sym = symtable_get(string_buf); + return T_CEXPR; + } else { + *string_buf_ptr++ = ')'; + } + } +\n { ++yylineno; } +[^()\n]+ { + char *yptr = yytext; + + while (*yptr != '\0') { + /* Remove duplicate spaces */ + if (*yptr == '\t') + *yptr = ' '; + if (*yptr == ' ' + && string_buf_ptr != string_buf + && string_buf_ptr[-1] == ' ') + yptr++; + else + *string_buf_ptr++ = *yptr++; + } + } + +{SPACE} ; + + /* Register/SCB/SRAM definition keywords */ +register { return T_REGISTER; } +const { yylval.value = FALSE; return T_CONST; } +download { return T_DOWNLOAD; } +address { return T_ADDRESS; } +access_mode { return T_ACCESS_MODE; } +RW|RO|WO { + if (strcmp(yytext, "RW") == 0) + yylval.value = RW; + else if (strcmp(yytext, "RO") == 0) + yylval.value = RO; + else + yylval.value = WO; + return T_MODE; + } +BEGIN_CRITICAL { return T_BEGIN_CS; } +END_CRITICAL { return T_END_CS; } +bit { return T_BIT; } +mask { return T_MASK; } +alias { return T_ALIAS; } +size { return T_SIZE; } +scb { return T_SCB; } +scratch_ram { return T_SRAM; } +accumulator { return T_ACCUM; } +allones { return T_ALLONES; } +allzeros { return T_ALLZEROS; } +none { return T_NONE; } +sindex { return T_SINDEX; } +A { return T_A; } + + /* Opcodes */ +shl { return T_SHL; } +shr { return T_SHR; } +ror { return T_ROR; } +rol { return T_ROL; } +mvi { return T_MVI; } +mov { return T_MOV; } +clr { return T_CLR; } +jmp { return T_JMP; } +jc { return T_JC; } +jnc { return T_JNC; } +je { return T_JE; } +jne { return T_JNE; } +jz { return T_JZ; } +jnz { return T_JNZ; } +call { return T_CALL; } +add { return T_ADD; } +adc { return T_ADC; } +bmov { return T_BMOV; } +inc { return T_INC; } +dec { return T_DEC; } +stc { return T_STC; } +clc { return T_CLC; } +cmp { return T_CMP; } +not { return T_NOT; } +xor { return T_XOR; } +test { return T_TEST;} +and { return T_AND; } +or { return T_OR; } +ret { return T_RET; } +nop { return T_NOP; } +else { return T_ELSE; } + + /* Allowed Symbols */ +[-+,:()~|&."{};<>[\]!] { return yytext[0]; } + + /* Number processing */ +0[0-7]* { + yylval.value = strtol(yytext, NULL, 8); + return T_NUMBER; + } + +0[xX][0-9a-fA-F]+ { + yylval.value = strtoul(yytext + 2, NULL, 16); + return T_NUMBER; + } + +[1-9][0-9]* { + yylval.value = strtol(yytext, NULL, 10); + return T_NUMBER; + } + + /* Include Files */ +#include { return T_INCLUDE; BEGIN INCLUDE;} +[<>\"] { return yytext[0]; } +{PATH} { yylval.str = strdup(yytext); return T_PATH; } +; { BEGIN INITIAL; return yytext[0]; } +. { stop("Invalid include line", EX_DATAERR); } + + /* For parsing C include files with #define foo */ +#define { yylval.value = TRUE; return T_CONST; } + /* Throw away macros */ +#define[^\n]*[()]+[^\n]* ; +{PATH} { yylval.str = strdup(yytext); return T_PATH; } + +{WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; } + +. { + char buf[255]; + + snprintf(buf, sizeof(buf), "Invalid character " + "'%c'", yytext[0]); + stop(buf, EX_DATAERR); + } +%% + +typedef struct include { + YY_BUFFER_STATE buffer; + int lineno; + char *filename; + SLIST_ENTRY(include) links; +}include_t; + +SLIST_HEAD(, include) include_stack; + +void +include_file(char *file_name, include_type type) +{ + FILE *newfile; + include_t *include; + + newfile = NULL; + /* Try the current directory first */ + if (includes_search_curdir != 0 || type == SOURCE_FILE) + newfile = fopen(file_name, "r"); + + if (newfile == NULL && type != SOURCE_FILE) { + path_entry_t include_dir; + for (include_dir = search_path.slh_first; + include_dir != NULL; + include_dir = include_dir->links.sle_next) { + char fullname[PATH_MAX]; + + if ((include_dir->quoted_includes_only == TRUE) + && (type != QUOTED_INCLUDE)) + continue; + + snprintf(fullname, sizeof(fullname), + "%s/%s", include_dir->directory, file_name); + + if ((newfile = fopen(fullname, "r")) != NULL) + break; + } + } + + if (newfile == NULL) { + perror(file_name); + stop("Unable to open input file", EX_SOFTWARE); + /* NOTREACHED */ + } + + if (type != SOURCE_FILE) { + include = (include_t *)malloc(sizeof(include_t)); + if (include == NULL) { + stop("Unable to allocate include stack entry", + EX_SOFTWARE); + /* NOTREACHED */ + } + include->buffer = YY_CURRENT_BUFFER; + include->lineno = yylineno; + include->filename = yyfilename; + SLIST_INSERT_HEAD(&include_stack, include, links); + } + yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); + yylineno = 1; + yyfilename = strdup(file_name); +} + +int +yywrap() +{ + include_t *include; + + yy_delete_buffer(YY_CURRENT_BUFFER); + (void)fclose(yyin); + if (yyfilename != NULL) + free(yyfilename); + yyfilename = NULL; + include = include_stack.slh_first; + if (include != NULL) { + yy_switch_to_buffer(include->buffer); + yylineno = include->lineno; + yyfilename = include->filename; + SLIST_REMOVE_HEAD(&include_stack, links); + free(include); + return (0); + } + return (1); +} diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c --- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c Sun Mar 4 14:30:18 2001 @@ -0,0 +1,468 @@ +/* + * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#4 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $ + */ + +#include + +#ifdef __linux__ +#include +#else +#include +#endif +#include +#include +#include +#include +#include + +#include "aicasm_symbol.h" +#include "aicasm.h" + +static DB *symtable; + +symbol_t * +symbol_create(char *name) +{ + symbol_t *new_symbol; + + new_symbol = (symbol_t *)malloc(sizeof(symbol_t)); + if (new_symbol == NULL) { + perror("Unable to create new symbol"); + exit(EX_SOFTWARE); + } + memset(new_symbol, 0, sizeof(*new_symbol)); + new_symbol->name = strdup(name); + new_symbol->type = UNINITIALIZED; + return (new_symbol); +} + +void +symbol_delete(symbol_t *symbol) +{ + if (symtable != NULL) { + DBT key; + + key.data = symbol->name; + key.size = strlen(symbol->name); + symtable->del(symtable, &key, /*flags*/0); + } + switch(symbol->type) { + case SCBLOC: + case SRAMLOC: + case REGISTER: + if (symbol->info.rinfo != NULL) + free(symbol->info.rinfo); + break; + case ALIAS: + if (symbol->info.ainfo != NULL) + free(symbol->info.ainfo); + break; + case MASK: + case BIT: + if (symbol->info.minfo != NULL) { + symlist_free(&symbol->info.minfo->symrefs); + free(symbol->info.minfo); + } + break; + case DOWNLOAD_CONST: + case CONST: + if (symbol->info.cinfo != NULL) + free(symbol->info.cinfo); + break; + case LABEL: + if (symbol->info.linfo != NULL) + free(symbol->info.linfo); + break; + case UNINITIALIZED: + default: + break; + } + free(symbol->name); + free(symbol); +} + +void +symtable_open() +{ + symtable = dbopen(/*filename*/NULL, + O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH, + /*openinfo*/NULL); + + if (symtable == NULL) { + perror("Symbol table creation failed"); + exit(EX_SOFTWARE); + /* NOTREACHED */ + } +} + +void +symtable_close() +{ + if (symtable != NULL) { + DBT key; + DBT data; + + while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { + symbol_t *stored_ptr; + + memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); + symbol_delete(stored_ptr); + } + symtable->close(symtable); + } +} + +/* + * The semantics of get is to return an uninitialized symbol entry + * if a lookup fails. + */ +symbol_t * +symtable_get(char *name) +{ + symbol_t *stored_ptr; + DBT key; + DBT data; + int retval; + + key.data = (void *)name; + key.size = strlen(name); + + if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) { + if (retval == -1) { + perror("Symbol table get operation failed"); + exit(EX_SOFTWARE); + /* NOTREACHED */ + } else if (retval == 1) { + /* Symbol wasn't found, so create a new one */ + symbol_t *new_symbol; + + new_symbol = symbol_create(name); + data.data = &new_symbol; + data.size = sizeof(new_symbol); + if (symtable->put(symtable, &key, &data, + /*flags*/0) !=0) { + perror("Symtable put failed"); + exit(EX_SOFTWARE); + } + return (new_symbol); + } else { + perror("Unexpected return value from db get routine"); + exit(EX_SOFTWARE); + /* NOTREACHED */ + } + } + memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); + return (stored_ptr); +} + +symbol_node_t * +symlist_search(symlist_t *symlist, char *symname) +{ + symbol_node_t *curnode; + + curnode = symlist->slh_first; + while(curnode != NULL) { + if (strcmp(symname, curnode->symbol->name) == 0) + break; + curnode = curnode->links.sle_next; + } + return (curnode); +} + +void +symlist_add(symlist_t *symlist, symbol_t *symbol, int how) +{ + symbol_node_t *newnode; + + newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t)); + if (newnode == NULL) { + stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE); + /* NOTREACHED */ + } + newnode->symbol = symbol; + if (how == SYMLIST_SORT) { + symbol_node_t *curnode; + int mask; + + mask = FALSE; + switch(symbol->type) { + case REGISTER: + case SCBLOC: + case SRAMLOC: + break; + case BIT: + case MASK: + mask = TRUE; + break; + default: + stop("symlist_add: Invalid symbol type for sorting", + EX_SOFTWARE); + /* NOTREACHED */ + } + + curnode = symlist->slh_first; + if (curnode == NULL + || (mask && (curnode->symbol->info.minfo->mask > + newnode->symbol->info.minfo->mask)) + || (!mask && (curnode->symbol->info.rinfo->address > + newnode->symbol->info.rinfo->address))) { + SLIST_INSERT_HEAD(symlist, newnode, links); + return; + } + + while (1) { + if (curnode->links.sle_next == NULL) { + SLIST_INSERT_AFTER(curnode, newnode, + links); + break; + } else { + symbol_t *cursymbol; + + cursymbol = curnode->links.sle_next->symbol; + if ((mask && (cursymbol->info.minfo->mask > + symbol->info.minfo->mask)) + || (!mask &&(cursymbol->info.rinfo->address > + symbol->info.rinfo->address))){ + SLIST_INSERT_AFTER(curnode, newnode, + links); + break; + } + } + curnode = curnode->links.sle_next; + } + } else { + SLIST_INSERT_HEAD(symlist, newnode, links); + } +} + +void +symlist_free(symlist_t *symlist) +{ + symbol_node_t *node1, *node2; + + node1 = symlist->slh_first; + while (node1 != NULL) { + node2 = node1->links.sle_next; + free(node1); + node1 = node2; + } + SLIST_INIT(symlist); +} + +void +symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1, + symlist_t *symlist_src2) +{ + symbol_node_t *node; + + *symlist_dest = *symlist_src1; + while((node = symlist_src2->slh_first) != NULL) { + SLIST_REMOVE_HEAD(symlist_src2, links); + SLIST_INSERT_HEAD(symlist_dest, node, links); + } + + /* These are now empty */ + SLIST_INIT(symlist_src1); + SLIST_INIT(symlist_src2); +} + +void +symtable_dump(FILE *ofile) +{ + /* + * Sort the registers by address with a simple insertion sort. + * Put bitmasks next to the first register that defines them. + * Put constants at the end. + */ + symlist_t registers; + symlist_t masks; + symlist_t constants; + symlist_t download_constants; + symlist_t aliases; + + SLIST_INIT(®isters); + SLIST_INIT(&masks); + SLIST_INIT(&constants); + SLIST_INIT(&download_constants); + SLIST_INIT(&aliases); + + if (symtable != NULL) { + DBT key; + DBT data; + int flag = R_FIRST; + + while (symtable->seq(symtable, &key, &data, flag) == 0) { + symbol_t *cursym; + + memcpy(&cursym, data.data, sizeof(cursym)); + switch(cursym->type) { + case REGISTER: + case SCBLOC: + case SRAMLOC: + symlist_add(®isters, cursym, SYMLIST_SORT); + break; + case MASK: + case BIT: + symlist_add(&masks, cursym, SYMLIST_SORT); + break; + case CONST: + if (cursym->info.cinfo->define == FALSE) { + symlist_add(&constants, cursym, + SYMLIST_INSERT_HEAD); + } + break; + case DOWNLOAD_CONST: + symlist_add(&download_constants, cursym, + SYMLIST_INSERT_HEAD); + break; + case ALIAS: + symlist_add(&aliases, cursym, + SYMLIST_INSERT_HEAD); + break; + default: + break; + } + flag = R_NEXT; + } + + /* Put in the masks and bits */ + while (masks.slh_first != NULL) { + symbol_node_t *curnode; + symbol_node_t *regnode; + char *regname; + + curnode = masks.slh_first; + SLIST_REMOVE_HEAD(&masks, links); + + regnode = + curnode->symbol->info.minfo->symrefs.slh_first; + regname = regnode->symbol->name; + regnode = symlist_search(®isters, regname); + SLIST_INSERT_AFTER(regnode, curnode, links); + } + + /* Add the aliases */ + while (aliases.slh_first != NULL) { + symbol_node_t *curnode; + symbol_node_t *regnode; + char *regname; + + curnode = aliases.slh_first; + SLIST_REMOVE_HEAD(&aliases, links); + + regname = curnode->symbol->info.ainfo->parent->name; + regnode = symlist_search(®isters, regname); + SLIST_INSERT_AFTER(regnode, curnode, links); + } + + /* Output what we have */ + fprintf(ofile, +"/* + * DO NOT EDIT - This file is automatically generated. + */\n"); + while (registers.slh_first != NULL) { + symbol_node_t *curnode; + u_int8_t value; + char *tab_str; + char *tab_str2; + + curnode = registers.slh_first; + SLIST_REMOVE_HEAD(®isters, links); + switch(curnode->symbol->type) { + case REGISTER: + case SCBLOC: + case SRAMLOC: + fprintf(ofile, "\n"); + value = curnode->symbol->info.rinfo->address; + tab_str = "\t"; + tab_str2 = "\t\t"; + break; + case ALIAS: + { + symbol_t *parent; + + parent = curnode->symbol->info.ainfo->parent; + value = parent->info.rinfo->address; + tab_str = "\t"; + tab_str2 = "\t\t"; + break; + } + case MASK: + case BIT: + value = curnode->symbol->info.minfo->mask; + tab_str = "\t\t"; + tab_str2 = "\t"; + break; + default: + value = 0; /* Quiet compiler */ + tab_str = NULL; + tab_str2 = NULL; + stop("symtable_dump: Invalid symbol type " + "encountered", EX_SOFTWARE); + break; + } + fprintf(ofile, "#define%s%-16s%s0x%02x\n", + tab_str, curnode->symbol->name, tab_str2, + value); + free(curnode); + } + fprintf(ofile, "\n\n"); + + while (constants.slh_first != NULL) { + symbol_node_t *curnode; + + curnode = constants.slh_first; + SLIST_REMOVE_HEAD(&constants, links); + fprintf(ofile, "#define\t%-8s\t0x%02x\n", + curnode->symbol->name, + curnode->symbol->info.cinfo->value); + free(curnode); + } + + + fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); + + while (download_constants.slh_first != NULL) { + symbol_node_t *curnode; + + curnode = download_constants.slh_first; + SLIST_REMOVE_HEAD(&download_constants, links); + fprintf(ofile, "#define\t%-8s\t0x%02x\n", + curnode->symbol->name, + curnode->symbol->info.cinfo->value); + free(curnode); + } + } +} + diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h --- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,177 @@ +/* + * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions + * + * Copyright (c) 1997 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.h#4 $ + * + * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.h,v 1.11 2000/09/22 22:19:55 gibbs Exp $ + */ + +#ifdef __linux__ +#include "../queue.h" +#else +#include +#endif + +typedef enum { + UNINITIALIZED, + REGISTER, + ALIAS, + SCBLOC, + SRAMLOC, + MASK, + BIT, + CONST, + DOWNLOAD_CONST, + LABEL, + CONDITIONAL +}symtype; + +typedef enum { + RO = 0x01, + WO = 0x02, + RW = 0x03 +}amode_t; + +struct reg_info { + u_int8_t address; + int size; + amode_t mode; + u_int8_t valid_bitmask; + int typecheck_masks; +}; + +typedef SLIST_HEAD(symlist, symbol_node) symlist_t; + +struct mask_info { + symlist_t symrefs; + u_int8_t mask; +}; + +struct const_info { + u_int8_t value; + int define; +}; + +struct alias_info { + struct symbol *parent; +}; + +struct label_info { + int address; +}; + +struct cond_info { + int func_num; +}; + +typedef struct expression_info { + symlist_t referenced_syms; + int value; +} expression_t; + +typedef struct symbol { + char *name; + symtype type; + union { + struct reg_info *rinfo; + struct mask_info *minfo; + struct const_info *cinfo; + struct alias_info *ainfo; + struct label_info *linfo; + struct cond_info *condinfo; + }info; +} symbol_t; + +typedef struct symbol_ref { + symbol_t *symbol; + int offset; +} symbol_ref_t; + +typedef struct symbol_node { + SLIST_ENTRY(symbol_node) links; + symbol_t *symbol; +} symbol_node_t; + +typedef struct critical_section { + TAILQ_ENTRY(critical_section) links; + int begin_addr; + int end_addr; +} critical_section_t; + +typedef enum { + SCOPE_ROOT, + SCOPE_IF, + SCOPE_ELSE_IF, + SCOPE_ELSE +} scope_type; + +typedef struct patch_info { + int skip_patch; + int skip_instr; +} patch_info_t; + +typedef struct scope { + SLIST_ENTRY(scope) scope_stack_links; + TAILQ_ENTRY(scope) scope_links; + TAILQ_HEAD(, scope) inner_scope; + scope_type type; + int inner_scope_patches; + int begin_addr; + int end_addr; + patch_info_t patches[2]; + int func_num; +} scope_t; + +TAILQ_HEAD(cs_tailq, critical_section); +SLIST_HEAD(scope_list, scope); +TAILQ_HEAD(scope_tailq, scope); + +void symbol_delete __P((symbol_t *symbol)); + +void symtable_open __P((void)); + +void symtable_close __P((void)); + +symbol_t * + symtable_get __P((char *name)); + +symbol_node_t * + symlist_search __P((symlist_t *symlist, char *symname)); + +void + symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how)); +#define SYMLIST_INSERT_HEAD 0x00 +#define SYMLIST_SORT 0x01 + +void symlist_free __P((symlist_t *symlist)); + +void symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1, + symlist_t *symlist_src2)); +void symtable_dump __P((FILE *ofile)); diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/cam.h linux/drivers/scsi/aic7xxx/cam.h --- v2.4.2/linux/drivers/scsi/aic7xxx/cam.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/cam.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,142 @@ +/* + * Data structures and definitions for the CAM system. + * + * Copyright (c) 1997 Justin T. Gibbs. + * Copyright (c) 2000 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: //depot/src/linux/drivers/scsi/aic7xxx/cam.h#9 $ + */ + +#ifndef _AIC7XXX_CAM_H +#define _AIC7XXX_CAM_H 1 + +/* Provide a mapping from CAM constructs to Linux SCSI constructs */ + +#define CAM_BUS_WILDCARD ((u_int)~0) +#define CAM_TARGET_WILDCARD ((u_int)~0) +#define CAM_LUN_WILDCARD ((u_int)~0) + +/* CAM Status field values */ +typedef enum { + /* CCB request is in progress */ + CAM_REQ_INPROG = 0x3F, /* Some value unused by Linux */ + /* CCB request completed without error */ + CAM_REQ_CMP = DID_OK, + /* CCB request aborted by the host */ + CAM_REQ_ABORTED = DID_ABORT, + /* Unable to abort CCB request */ + CAM_UA_ABORT = DID_ERROR, + /* CCB request completed with an error */ + CAM_REQ_CMP_ERR = DID_ERROR, + /* CAM subsytem is busy */ + CAM_BUSY = DID_BUS_BUSY, + /* CCB request was invalid */ + CAM_REQ_INVALID = DID_BAD_TARGET, + /* Supplied Path ID is invalid */ + CAM_PATH_INVALID = DID_BAD_TARGET, + /* Target Selection Timeout */ + CAM_SEL_TIMEOUT = DID_NO_CONNECT, + /* Command timeout */ + CAM_CMD_TIMEOUT = DID_ERROR, /* + * Should never occur in Linux + * as the upper level code + * handles all timeout processing. + */ + /* SCSI error, look at error code in CCB */ + CAM_SCSI_STATUS_ERROR = DID_OK, /* Linux looks at status byte */ + /* SCSI Bus Reset Sent/Received */ + CAM_SCSI_BUS_RESET = DID_RESET, + /* Uncorrectable parity error occurred */ + CAM_UNCOR_PARITY = DID_PARITY, + /* Autosense: request sense cmd fail */ + CAM_AUTOSENSE_FAIL = DID_ERROR, + /* No HBA Detected Error */ + CAM_NO_HBA = DID_ERROR, + /* Data Overrun error */ + CAM_DATA_RUN_ERR = DID_ERROR, + /* Unexpected Bus Free */ + CAM_UNEXP_BUSFREE = DID_ERROR, + /* CCB length supplied is inadequate */ + CAM_CCB_LEN_ERR = DID_ERROR, + /* Unable to provide requested capability */ + CAM_PROVIDE_FAIL = DID_ERROR, + /* A SCSI BDR msg was sent to target */ + CAM_BDR_SENT = DID_RESET, + /* CCB request terminated by the host */ + CAM_REQ_TERMIO = DID_ERROR, + /* Unrecoverable Host Bus Adapter Error */ + CAM_UNREC_HBA_ERROR = DID_ERROR, + /* The request was too large for this host */ + CAM_REQ_TOO_BIG = DID_ERROR, + /* + * This request should be requeued to preserve + * transaction ordering. This typically occurs + * when the SIM recognizes an error that should + * freeze the queue and must place additional + * requests for the target at the sim level + * back into the XPT queue. + */ + CAM_REQUEUE_REQ = DID_BUS_BUSY, + /* + * The transaction has made it through our queue routine. + */ + CAM_SIM_QUEUED = 0x200, + + CAM_STATUS_MASK = 0x3F +} cam_status; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +#define SCSI_DATA_READ 1 +#define SCSI_DATA_WRITE 2 +#define SCSI_DATA_NONE 3 +#endif + +/* + * Definitions for the asynchronous callback CCB fields. + */ +typedef enum { + AC_GETDEV_CHANGED = 0x800,/* Getdev info might have changed */ + AC_INQ_CHANGED = 0x400,/* Inquiry info might have changed */ + AC_TRANSFER_NEG = 0x200,/* New transfer settings in effect */ + AC_LOST_DEVICE = 0x100,/* A device went away */ + AC_FOUND_DEVICE = 0x080,/* A new device was found */ + AC_PATH_DEREGISTERED = 0x040,/* A path has de-registered */ + AC_PATH_REGISTERED = 0x020,/* A new path has been registered */ + AC_SENT_BDR = 0x010,/* A BDR message was sent to target */ + AC_SCSI_AEN = 0x008,/* A SCSI AEN has been received */ + AC_UNSOL_RESEL = 0x002,/* Unsolicited reselection occurred */ + AC_BUS_RESET = 0x001 /* A SCSI bus reset occurred */ +} ac_code; + +typedef enum { + CAM_DIR_IN = SCSI_DATA_READ, + CAM_DIR_OUT = SCSI_DATA_WRITE, + CAM_DIR_NONE = SCSI_DATA_NONE +} ccb_flags; + +#endif /* _AIC7XXX_CAM_H */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/queue.h linux/drivers/scsi/aic7xxx/queue.h --- v2.4.2/linux/drivers/scsi/aic7xxx/queue.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx/queue.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,501 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.38 2000/05/26 02:06:56 jake Exp $ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * singly-linked tail queues, lists, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ CIRCLEQ + * _HEAD + + + + + + * _HEAD_INITIALIZER + + + + + + * _ENTRY + + + + + + * _INIT + + + + + + * _EMPTY + + + + + + * _FIRST + + + + + + * _NEXT + + + + + + * _PREV - - - + + + * _LAST - - + + + + * _FOREACH + + + + + + * _FOREACH_REVERSE - - - + + + * _INSERT_HEAD + + + + + + * _INSERT_BEFORE - + - + + + * _INSERT_AFTER + + + + + + * _INSERT_TAIL - - + + + + * _REMOVE_HEAD + - + - - + * _REMOVE + + + + + + * + */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + STAILQ_LAST((head)) = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head) (*(head)->stqh_last) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD(head, field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) + +/* + * Circular queue declarations. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&(head), (void *)&(head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) + +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = CIRCLEQ_FIRST((head)); \ + (var) != (void *)(head); \ + (var) = CIRCLEQ_NEXT((var), field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = CIRCLEQ_LAST((head)); \ + (var) != (void *)(head); \ + (var) = CIRCLEQ_PREV((var), field)) + +#define CIRCLEQ_INIT(head) do { \ + CIRCLEQ_FIRST((head)) = (void *)(head); \ + CIRCLEQ_LAST((head)) = (void *)(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \ + CIRCLEQ_PREV((elm), field) = (listelm); \ + if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = (elm); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\ + CIRCLEQ_NEXT((listelm), field) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = (listelm); \ + CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \ + if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = (elm); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\ + CIRCLEQ_PREV((listelm), field) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \ + CIRCLEQ_PREV((elm), field) = (void *)(head); \ + if (CIRCLEQ_LAST((head)) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = (elm); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \ + CIRCLEQ_FIRST((head)) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = (void *)(head); \ + CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \ + if (CIRCLEQ_FIRST((head)) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = (elm); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \ + CIRCLEQ_LAST((head)) = (elm); \ +} while (0) + +#define CIRCLEQ_LAST(head) ((head)->cqh_last) + +#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next) + +#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \ + CIRCLEQ_PREV((elm), field); \ + if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \ + CIRCLEQ_NEXT((elm), field); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/scsi_message.h linux/drivers/scsi/aic7xxx/scsi_message.h --- v2.4.2/linux/drivers/scsi/aic7xxx/scsi_message.h Wed Jun 9 16:59:15 1999 +++ linux/drivers/scsi/aic7xxx/scsi_message.h Sun Mar 4 14:30:18 2001 @@ -1,34 +1,52 @@ +/* + * This file is in the public domain. + * $FreeBSD: src/sys/cam/scsi/scsi_message.h,v 1.2 2000/05/01 20:21:29 peter Exp $ + */ + /* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */ #define MSG_CMDCOMPLETE 0x00 /* M/M */ +#define MSG_TASK_COMPLETE 0x00 /* M/M */ /* SPI3 Terminology */ #define MSG_EXTENDED 0x01 /* O/O */ #define MSG_SAVEDATAPOINTER 0x02 /* O/O */ #define MSG_RESTOREPOINTERS 0x03 /* O/O */ #define MSG_DISCONNECT 0x04 /* O/O */ #define MSG_INITIATOR_DET_ERR 0x05 /* M/M */ #define MSG_ABORT 0x06 /* O/M */ +#define MSG_ABORT_TASK_SET 0x06 /* O/M */ /* SPI3 Terminology */ #define MSG_MESSAGE_REJECT 0x07 /* M/M */ #define MSG_NOOP 0x08 /* M/M */ #define MSG_PARITY_ERROR 0x09 /* M/M */ #define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */ #define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */ #define MSG_BUS_DEV_RESET 0x0c /* O/M */ +#define MSG_TARGET_RESET 0x0c /* O/M */ /* SPI3 Terminology */ #define MSG_ABORT_TAG 0x0d /* O/O */ +#define MSG_ABORT_TASK 0x0d /* O/O */ /* SPI3 Terminology */ #define MSG_CLEAR_QUEUE 0x0e /* O/O */ -#define MSG_INIT_RECOVERY 0x0f /* O/O */ -#define MSG_REL_RECOVERY 0x10 /* O/O */ -#define MSG_TERM_IO_PROC 0x11 /* O/O */ +#define MSG_CLEAR_TASK_SET 0x0e /* O/O */ /* SPI3 Terminology */ +#define MSG_INIT_RECOVERY 0x0f /* O/O */ /* Deprecated in SPI3 */ +#define MSG_REL_RECOVERY 0x10 /* O/O */ /* Deprecated in SPI3 */ +#define MSG_TERM_IO_PROC 0x11 /* O/O */ /* Deprecated in SPI3 */ +#define MSG_CLEAR_ACA 0x16 /* O/O */ /* SPI3 */ +#define MSG_LOGICAL_UNIT_RESET 0x17 /* O/O */ /* SPI3 */ +#define MSG_QAS_REQUEST 0x55 /* O/O */ /* SPI3 */ /* Messages (2 byte) */ #define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ +#define MSG_SIMPLE_TASK 0x20 /* O/O */ /* SPI3 Terminology */ #define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */ +#define MSG_HEAD_OF_QUEUE_TASK 0x21 /* O/O */ /* SPI3 Terminology */ #define MSG_ORDERED_Q_TAG 0x22 /* O/O */ +#define MSG_ORDERED_TASK 0x22 /* O/O */ /* SPI3 Terminology */ #define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */ +#define MSG_ACA_TASK 0x24 /* 0/0 */ /* SPI3 */ /* Identify message */ /* M/M */ #define MSG_IDENTIFYFLAG 0x80 #define MSG_IDENTIFY_DISCFLAG 0x40 #define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun)) #define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG) +#define MSG_IDENTIFY_LUNMASK 0x03F /* Extended messages (opcode and length) */ #define MSG_EXT_SDTR 0x01 @@ -38,12 +56,10 @@ #define MSG_EXT_WDTR_LEN 0x02 #define MSG_EXT_WDTR_BUS_8_BIT 0x00 #define MSG_EXT_WDTR_BUS_16_BIT 0x01 -#define MSG_EXT_WDTR_BUS_32_BIT 0x02 +#define MSG_EXT_WDTR_BUS_32_BIT 0x02 /* Deprecated in SPI3 */ -#define MSG_EXT_PPR 0x04 -#define MSG_EXT_PPR_LEN 0x06 -#define MSG_EXT_PPR_OPTION_ST 0x00 -#define MSG_EXT_PPR_OPTION_DT_CRC 0x02 -#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03 -#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04 -#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05 +#define MSG_EXT_PPR 0x04 /* SPI3 */ +#define MSG_EXT_PPR_LEN 0x06 +#define MSG_EXT_PPR_QAS_REQ 0x04 +#define MSG_EXT_PPR_DT_REQ 0x02 +#define MSG_EXT_PPR_IU_REQ 0x01 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/sequencer.h linux/drivers/scsi/aic7xxx/sequencer.h --- v2.4.2/linux/drivers/scsi/aic7xxx/sequencer.h Sun Nov 8 13:20:14 1998 +++ linux/drivers/scsi/aic7xxx/sequencer.h Wed Dec 31 16:00:00 1969 @@ -1,135 +0,0 @@ -/* - * Instruction formats for the sequencer program downloaded to - * Aic7xxx SCSI host adapters - * - * Copyright (c) 1997, 1998 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $ - */ - -#ifdef __LITTLE_ENDIAN_BITFIELD -struct ins_format1 { - unsigned int - immediate : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -}; - -struct ins_format2 { - unsigned int - shift_control : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -}; - -struct ins_format3 { - unsigned int - immediate : 8, - source : 9, - address : 10, - opcode : 4, - parity : 1; -}; -#elif defined(__BIG_ENDIAN_BITFIELD) -struct ins_format1 { - unsigned int - parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - immediate : 8; -}; - -struct ins_format2 { - unsigned int - parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - shift_control : 8; -}; - -struct ins_format3 { - unsigned int - parity : 1, - opcode : 4, - address : 10, - source : 9, - immediate : 8; -}; -#endif - -union ins_formats { - struct ins_format1 format1; - struct ins_format2 format2; - struct ins_format3 format3; - unsigned char bytes[4]; - unsigned int integer; -}; -struct instruction { - union ins_formats format; - unsigned int srcline; - struct symbol *patch_label; - struct { - struct instruction *stqe_next; - } links; -}; - -#define AIC_OP_OR 0x0 -#define AIC_OP_AND 0x1 -#define AIC_OP_XOR 0x2 -#define AIC_OP_ADD 0x3 -#define AIC_OP_ADC 0x4 -#define AIC_OP_ROL 0x5 -#define AIC_OP_BMOV 0x6 - -#define AIC_OP_JMP 0x8 -#define AIC_OP_JC 0x9 -#define AIC_OP_JNC 0xa -#define AIC_OP_CALL 0xb -#define AIC_OP_JNE 0xc -#define AIC_OP_JNZ 0xd -#define AIC_OP_JE 0xe -#define AIC_OP_JZ 0xf - -/* Pseudo Ops */ -#define AIC_OP_SHL 0x10 -#define AIC_OP_SHR 0x20 -#define AIC_OP_ROR 0x30 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.4.2/linux/drivers/scsi/aic7xxx.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/aic7xxx.c Wed Dec 31 16:00:00 1969 @@ -1,12242 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F - * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA - * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide, - * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux, - * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file - * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual, - * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the - * ANSI SCSI-2 specification (draft 10c), ... - * - * -------------------------------------------------------------------------- - * - * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org): - * - * Substantially modified to include support for wide and twin bus - * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, - * SCB paging, and other rework of the code. - * - * Parts of this driver were also based on the FreeBSD driver by - * Justin T. Gibbs. His copyright follows: - * - * -------------------------------------------------------------------------- - * Copyright (c) 1994-1997 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $ - *--------------------------------------------------------------------------- - * - * Thanks also go to (in alphabetical order) the following: - * - * Rory Bolt - Sequencer bug fixes - * Jay Estabrook - Initial DEC Alpha support - * Doug Ledford - Much needed abort/reset bug fixes - * Kai Makisara - DMAing of SCBs - * - * A Boot time option was also added for not resetting the scsi bus. - * - * Form: aic7xxx=extended - * aic7xxx=no_reset - * aic7xxx=ultra - * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level - * aic7xxx=verbose - * - * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97 - * - * $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $ - *-M*************************************************************************/ - -/*+M************************************************************************** - * - * Further driver modifications made by Doug Ledford - * - * Copyright (c) 1997-1999 Doug Ledford - * - * These changes are released under the same licensing terms as the FreeBSD - * driver written by Justin Gibbs. Please see his Copyright notice above - * for the exact terms and conditions covering my changes as well as the - * warranty statement. - * - * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include - * but are not limited to: - * - * 1: Import of the latest FreeBSD sequencer code for this driver - * 2: Modification of kernel code to accomodate different sequencer semantics - * 3: Extensive changes throughout kernel portion of driver to improve - * abort/reset processing and error hanndling - * 4: Other work contributed by various people on the Internet - * 5: Changes to printk information and verbosity selection code - * 6: General reliability related changes, especially in IRQ management - * 7: Modifications to the default probe/attach order for supported cards - * 8: SMP friendliness has been improved - * - * Overall, this driver represents a significant departure from the official - * aic7xxx driver released by Dan Eischen in two ways. First, in the code - * itself. A diff between the two version of the driver is now a several - * thousand line diff. Second, in approach to solving the same problem. The - * problem is importing the FreeBSD aic7xxx driver code to linux can be a - * difficult and time consuming process, that also can be error prone. Dan - * Eischen's official driver uses the approach that the linux and FreeBSD - * drivers should be as identical as possible. To that end, his next version - * of this driver will be using a mid-layer code library that he is developing - * to moderate communications between the linux mid-level SCSI code and the - * low level FreeBSD driver. He intends to be able to essentially drop the - * FreeBSD driver into the linux kernel with only a few minor tweaks to some - * include files and the like and get things working, making for fast easy - * imports of the FreeBSD code into linux. - * - * I disagree with Dan's approach. Not that I don't think his way of doing - * things would be nice, easy to maintain, and create a more uniform driver - * between FreeBSD and Linux. I have no objection to those issues. My - * disagreement is on the needed functionality. There simply are certain - * things that are done differently in FreeBSD than linux that will cause - * problems for this driver regardless of any middle ware Dan implements. - * The biggest example of this at the moment is interrupt semantics. Linux - * doesn't provide the same protection techniques as FreeBSD does, nor can - * they be easily implemented in any middle ware code since they would truly - * belong in the kernel proper and would effect all drivers. For the time - * being, I see issues such as these as major stumbling blocks to the - * reliability of code based upon such middle ware. Therefore, I choose to - * use a different approach to importing the FreeBSD code that doesn't - * involve any middle ware type code. My approach is to import the sequencer - * code from FreeBSD wholesale. Then, to only make changes in the kernel - * portion of the driver as they are needed for the new sequencer semantics. - * In this way, the portion of the driver that speaks to the rest of the - * linux kernel is fairly static and can be changed/modified to solve - * any problems one might encounter without concern for the FreeBSD driver. - * - * Note: If time and experience should prove me wrong that the middle ware - * code Dan writes is reliable in its operation, then I'll retract my above - * statements. But, for those that don't know, I'm from Missouri (in the US) - * and our state motto is "The Show-Me State". Well, before I will put - * faith into it, you'll have to show me that it works :) - * - *_M*************************************************************************/ - -/* - * The next three defines are user configurable. These should be the only - * defines a user might need to get in here and change. There are other - * defines buried deeper in the code, but those really shouldn't need touched - * under normal conditions. - */ - -/* - * AIC7XXX_STRICT_PCI_SETUP - * Should we assume the PCI config options on our controllers are set with - * sane and proper values, or should we be anal about our PCI config - * registers and force them to what we want? The main advantage to - * defining this option is on non-Intel hardware where the BIOS may not - * have been run to set things up, or if you have one of the BIOSless - * Adaptec controllers, such as a 2910, that don't get set up by the - * BIOS. However, keep in mind that we really do set the most important - * items in the driver regardless of this setting, this only controls some - * of the more esoteric PCI options on these cards. In that sense, I - * would default to leaving this off. However, if people wish to try - * things both ways, that would also help me to know if there are some - * machines where it works one way but not another. - * - * -- July 7, 17:09 - * OK...I need this on my machine for testing, so the default is to - * leave it defined. - * - * -- July 7, 18:49 - * I needed it for testing, but it didn't make any difference, so back - * off she goes. - * - * -- July 16, 23:04 - * I turned it back on to try and compensate for the 2.1.x PCI code - * which no longer relies solely on the BIOS and now tries to set - * things itself. - */ - -#define AIC7XXX_STRICT_PCI_SETUP - -/* - * AIC7XXX_VERBOSE_DEBUGGING - * This option enables a lot of extra printk();s in the code, surrounded - * by if (aic7xxx_verbose ...) statements. Executing all of those if - * statements and the extra checks can get to where it actually does have - * an impact on CPU usage and such, as well as code size. Disabling this - * define will keep some of those from becoming part of the code. - * - * NOTE: Currently, this option has no real effect, I will be adding the - * various #ifdef's in the code later when I've decided a section is - * complete and no longer needs debugging. OK...a lot of things are now - * surrounded by this define, so turning this off does have an impact. - */ - -/* - * #define AIC7XXX_VERBOSE_DEBUGGING - */ - -#if defined(MODULE) || defined(PCMCIA) -#include -#endif - -#if defined(PCMCIA) -# undef MODULE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sd.h" -#include "scsi.h" -#include "hosts.h" -#include "aic7xxx.h" - -#include "aic7xxx/sequencer.h" -#include "aic7xxx/scsi_message.h" -#include "aic7xxx_reg.h" -#include - -#include -#include /* for kmalloc() */ - -#include /* for CONFIG_PCI */ - -/* - * To generate the correct addresses for the controller to issue - * on the bus. Originally added for DEC Alpha support. - */ -#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a)) - -#define AIC7XXX_C_VERSION "5.2.1" - -#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define ALL_TARGETS -1 -#define ALL_CHANNELS -1 -#define ALL_LUNS -1 -#define MAX_TARGETS 16 -#define MAX_LUNS 8 -#ifndef TRUE -# define TRUE 1 -#endif -#ifndef FALSE -# define FALSE 0 -#endif - -#if defined(__powerpc__) || defined(__i386__) -# define MMAPIO -#endif - -# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) -# define cpuid smp_processor_id() -# define DRIVER_LOCK_INIT \ - spin_lock_init(&p->spin_lock); -# define DRIVER_LOCK \ - if(!p->cpu_lock_count[cpuid]) { \ - spin_lock_irqsave(&p->spin_lock, cpu_flags); \ - p->cpu_lock_count[cpuid]++; \ - } else { \ - p->cpu_lock_count[cpuid]++; \ - } -# define DRIVER_UNLOCK \ - if(--p->cpu_lock_count[cpuid] == 0) \ - spin_unlock_irqrestore(&p->spin_lock, cpu_flags); -# else -# define DRIVER_LOCK_INIT -# define DRIVER_LOCK -# define DRIVER_UNLOCK -# endif - -/* - * You can try raising me if tagged queueing is enabled, or lowering - * me if you only have 4 SCBs. - */ -#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE -#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE -#else -#define AIC7XXX_CMDS_PER_DEVICE 8 -#endif - -/* - * Control collection of SCSI transfer statistics for the /proc filesystem. - * - * NOTE: Do NOT enable this when running on kernels version 1.2.x and below. - * NOTE: This does affect performance since it has to maintain statistics. - */ -#ifdef CONFIG_AIC7XXX_PROC_STATS -#define AIC7XXX_PROC_STATS -#endif - -/* - * *** Determining commands per LUN *** - * - * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its - * own algorithm to determine the commands/LUN. If SCB paging is - * enabled, which is always now, the default is 8 commands per lun - * that indicates it supports tagged queueing. All non-tagged devices - * use an internal queue depth of 3, with no more than one of those - * three commands active at one time. - */ - -typedef struct -{ - unsigned char tag_commands[16]; /* Allow for wide/twin adapters. */ -} adapter_tag_info_t; - -/* - * Make a define that will tell the driver not to use tagged queueing - * by default. - */ -#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT -#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ - 0, 0, 0, 0, 0, 0, 0, 0} -#else -#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\ - 255, 255, 255, 255, 255, 255, 255, 255} -#endif - -/* - * Modify this as you see fit for your system. By setting tag_commands - * to 0, the driver will use it's own algorithm for determining the - * number of commands to use (see above). When 255, the driver will - * not enable tagged queueing for that particular device. When positive - * (> 0) and (< 255) the values in the array are used for the queue_depth. - * Note that the maximum value for an entry is 254, but you're insane if - * you try to use that many commands on one device. - * - * In this example, the first line will disable tagged queueing for all - * the devices on the first probed aic7xxx adapter. - * - * The second line enables tagged queueing with 4 commands/LUN for IDs - * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the - * driver to use its own algorithm for ID 1. - * - * The third line is the same as the first line. - * - * The fourth line disables tagged queueing for devices 0 and 3. It - * enables tagged queueing for the other IDs, with 16 commands/LUN - * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for - * IDs 2, 5-7, and 9-15. - */ - -/* - * NOTE: The below structure is for reference only, the actual structure - * to modify in order to change things is found after this fake one. - * -adapter_tag_info_t aic7xxx_tag_info[] = -{ - {DEFAULT_TAG_COMMANDS}, - {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}}, - {DEFAULT_TAG_COMMANDS}, - {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} -}; -*/ - -static adapter_tag_info_t aic7xxx_tag_info[] = -{ - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS} -}; - - -/* - * Define an array of board names that can be indexed by aha_type. - * Don't forget to change this when changing the types! - */ -static const char *board_names[] = { - "AIC-7xxx Unknown", /* AIC_NONE */ - "Adaptec AIC-7810 Hardware RAID Controller", /* AIC_7810 */ - "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */ - "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */ - "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */ - "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */ - "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */ - "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */ - "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */ - "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */ - "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */ - "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */ - "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */ - "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */ - "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */ - "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */ - "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */ - "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */ - "Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */ - "Adaptec AHA-2940UW Pro Ultra SCSI host adapter", /* AIC_7887 */ - "Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */ - "Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */ - "Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */ - "Adaptec AHA-395X Ultra2 SCSI host adapter", /* AIC_7897 */ - "Adaptec PCMCIA SCSI controller", /* card bus stuff */ - "Adaptec AIC-7892 Ultra 160/m SCSI host adapter", /* AIC_7892 */ - "Adaptec AIC-7899 Ultra 160/m SCSI host adapter", /* AIC_7899 */ -}; - -/* - * There should be a specific return value for this in scsi.h, but - * it seems that most drivers ignore it. - */ -#define DID_UNDERFLOW DID_ERROR - -/* - * What we want to do is have the higher level scsi driver requeue - * the command to us. There is no specific driver status for this - * condition, but the higher level scsi driver will requeue the - * command on a DID_BUS_BUSY error. - * - * Upon further inspection and testing, it seems that DID_BUS_BUSY - * will *always* retry the command. We can get into an infinite loop - * if this happens when we really want some sort of counter that - * will automatically abort/reset the command after so many retries. - * Using DID_ERROR will do just that. (Made by a suggestion by - * Doug Ledford 8/1/96) - */ -#define DID_RETRY_COMMAND DID_ERROR - -#define HSCSIID 0x07 -#define SCSI_RESET 0x040 - -/* - * EISA/VL-bus stuff - */ -#define MINSLOT 1 -#define MAXSLOT 15 -#define SLOTBASE(x) ((x) << 12) -#define BASE_TO_SLOT(x) ((x) >> 12) - -/* - * Standard EISA Host ID regs (Offset from slot base) - */ -#define AHC_HID0 0x80 /* 0,1: msb of ID2, 2-7: ID1 */ -#define AHC_HID1 0x81 /* 0-4: ID3, 5-7: LSB ID2 */ -#define AHC_HID2 0x82 /* product */ -#define AHC_HID3 0x83 /* firmware revision */ - -/* - * AIC-7770 I/O range to reserve for a card - */ -#define MINREG 0xC00 -#define MAXREG 0xCFF - -#define INTDEF 0x5C /* Interrupt Definition Register */ - -/* - * AIC-78X0 PCI registers - */ -#define CLASS_PROGIF_REVID 0x08 -#define DEVREVID 0x000000FFul -#define PROGINFC 0x0000FF00ul -#define SUBCLASS 0x00FF0000ul -#define BASECLASS 0xFF000000ul - -#define CSIZE_LATTIME 0x0C -#define CACHESIZE 0x0000003Ful /* only 5 bits */ -#define LATTIME 0x0000FF00ul - -#define DEVCONFIG 0x40 -#define SCBSIZE32 0x00010000ul /* aic789X only */ -#define MPORTMODE 0x00000400ul /* aic7870 only */ -#define RAMPSM 0x00000200ul /* aic7870 only */ -#define RAMPSM_ULTRA2 0x00000004 -#define VOLSENSE 0x00000100ul -#define SCBRAMSEL 0x00000080ul -#define SCBRAMSEL_ULTRA2 0x00000008 -#define MRDCEN 0x00000040ul -#define EXTSCBTIME 0x00000020ul /* aic7870 only */ -#define EXTSCBPEN 0x00000010ul /* aic7870 only */ -#define BERREN 0x00000008ul -#define DACEN 0x00000004ul -#define STPWLEVEL 0x00000002ul -#define DIFACTNEGEN 0x00000001ul /* aic7870 only */ - -#define SCAMCTL 0x1a /* Ultra2 only */ -#define CCSCBBADDR 0xf0 /* aic7895/6/7 */ - -/* - * Define the different types of SEEPROMs on aic7xxx adapters - * and make it also represent the address size used in accessing - * its registers. The 93C46 chips have 1024 bits organized into - * 64 16-bit words, while the 93C56 chips have 2048 bits organized - * into 128 16-bit words. The C46 chips use 6 bits to address - * each word, while the C56 and C66 (4096 bits) use 8 bits to - * address each word. - */ -typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type; - -/* - * - * Define the format of the SEEPROM registers (16 bits). - * - */ -struct seeprom_config { - -/* - * SCSI ID Configuration Flags - */ -#define CFXFER 0x0007 /* synchronous transfer rate */ -#define CFSYNCH 0x0008 /* enable synchronous transfer */ -#define CFDISC 0x0010 /* enable disconnection */ -#define CFWIDEB 0x0020 /* wide bus device (wide card) */ -#define CFSYNCHISULTRA 0x0040 /* CFSYNC is an ultra offset */ -#define CFNEWULTRAFORMAT 0x0080 /* Use the Ultra2 SEEPROM format */ -#define CFSTART 0x0100 /* send start unit SCSI command */ -#define CFINCBIOS 0x0200 /* include in BIOS scan */ -#define CFRNFOUND 0x0400 /* report even if not found */ -#define CFMULTILUN 0x0800 /* probe mult luns in BIOS scan */ -#define CFWBCACHEYES 0x4000 /* Enable W-Behind Cache on drive */ -#define CFWBCACHENC 0xc000 /* Don't change W-Behind Cache */ -/* UNUSED 0x3000 */ - unsigned short device_flags[16]; /* words 0-15 */ - -/* - * BIOS Control Bits - */ -#define CFSUPREM 0x0001 /* support all removable drives */ -#define CFSUPREMB 0x0002 /* support removable drives for boot only */ -#define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ -#define CFSM2DRV 0x0010 /* support more than two drives */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ -/* UNUSED 0x0040 */ -#define CFEXTEND 0x0080 /* extended translation enabled */ -/* UNUSED 0xFF00 */ - unsigned short bios_control; /* word 16 */ - -/* - * Host Adapter Control Bits - */ -#define CFAUTOTERM 0x0001 /* Perform Auto termination */ -#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */ -#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */ -#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */ -#define CFSTERM 0x0004 /* SCSI low byte termination */ -#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */ -#define CFSPARITY 0x0010 /* SCSI parity */ -#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */ -#define CFRESETB 0x0040 /* reset SCSI bus at boot */ -#define CFBPRIMARY 0x0100 /* Channel B primary on 7895 chipsets */ -#define CFSEAUTOTERM 0x0400 /* aic7890 Perform SE Auto Term */ -#define CFLVDSTERM 0x0800 /* aic7890 LVD Termination */ -/* UNUSED 0xF280 */ - unsigned short adapter_control; /* word 17 */ - -/* - * Bus Release, Host Adapter ID - */ -#define CFSCSIID 0x000F /* host adapter SCSI ID */ -/* UNUSED 0x00F0 */ -#define CFBRTIME 0xFF00 /* bus release time */ - unsigned short brtime_id; /* word 18 */ - -/* - * Maximum targets - */ -#define CFMAXTARG 0x00FF /* maximum targets */ -/* UNUSED 0xFF00 */ - unsigned short max_targets; /* word 19 */ - - unsigned short res_1[11]; /* words 20-30 */ - unsigned short checksum; /* word 31 */ -}; - -#define SELBUS_MASK 0x0a -#define SELNARROW 0x00 -#define SELBUSB 0x08 -#define SINGLE_BUS 0x00 - -#define SCB_TARGET(scb) \ - (((scb)->hscb->target_channel_lun & TID) >> 4) -#define SCB_LUN(scb) \ - ((scb)->hscb->target_channel_lun & LID) -#define SCB_IS_SCSIBUS_B(scb) \ - (((scb)->hscb->target_channel_lun & SELBUSB) != 0) - -/* - * If an error occurs during a data transfer phase, run the command - * to completion - it's easier that way - making a note of the error - * condition in this location. This then will modify a DID_OK status - * into an appropriate error for the higher-level SCSI code. - */ -#define aic7xxx_error(cmd) ((cmd)->SCp.Status) - -/* - * Keep track of the targets returned status. - */ -#define aic7xxx_status(cmd) ((cmd)->SCp.sent_command) - -/* - * The position of the SCSI commands scb within the scb array. - */ -#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in) - -/* - * The stored DMA mapping for single-buffer data transfers. - */ -#define aic7xxx_mapping(cmd) ((cmd)->SCp.phase) - -/* - * So we can keep track of our host structs - */ -static struct aic7xxx_host *first_aic7xxx = NULL; - -/* - * As of Linux 2.1, the mid-level SCSI code uses virtual addresses - * in the scatter-gather lists. We need to convert the virtual - * addresses to physical addresses. - */ -struct hw_scatterlist { - unsigned int address; - unsigned int length; -}; - -/* - * Maximum number of SG segments these cards can support. - */ -#define AIC7XXX_MAX_SG 128 - -/* - * The maximum number of SCBs we could have for ANY type - * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE - * SEQUENCER CODE IF THIS IS MODIFIED! - */ -#define AIC7XXX_MAXSCB 255 - - -struct aic7xxx_hwscb { -/* ------------ Begin hardware supported fields ---------------- */ -/* 0*/ unsigned char control; -/* 1*/ unsigned char target_channel_lun; /* 4/1/3 bits */ -/* 2*/ unsigned char target_status; -/* 3*/ unsigned char SG_segment_count; -/* 4*/ unsigned int SG_list_pointer; -/* 8*/ unsigned char residual_SG_segment_count; -/* 9*/ unsigned char residual_data_count[3]; -/*12*/ unsigned int data_pointer; -/*16*/ unsigned int data_count; -/*20*/ unsigned int SCSI_cmd_pointer; -/*24*/ unsigned char SCSI_cmd_length; -/*25*/ unsigned char tag; /* Index into our kernel SCB array. - * Also used as the tag for tagged I/O - */ -#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download - * via PIO to initialize a transaction. - */ -/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection - * or disconnected down in the sequencer. - */ -/*27*/ unsigned char prev; -/*28*/ unsigned int pad; /* - * Unused by the kernel, but we require - * the padding so that the array of - * hardware SCBs is alligned on 32 byte - * boundaries so the sequencer can index - */ -}; - -typedef enum { - SCB_FREE = 0x0000, - SCB_WAITINGQ = 0x0002, - SCB_ACTIVE = 0x0004, - SCB_SENSE = 0x0008, - SCB_ABORT = 0x0010, - SCB_DEVICE_RESET = 0x0020, - SCB_RESET = 0x0040, - SCB_RECOVERY_SCB = 0x0080, - SCB_MSGOUT_PPR = 0x0100, - SCB_MSGOUT_SENT = 0x0200, - SCB_MSGOUT_SDTR = 0x0400, - SCB_MSGOUT_WDTR = 0x0800, - SCB_MSGOUT_BITS = SCB_MSGOUT_PPR | - SCB_MSGOUT_SENT | - SCB_MSGOUT_SDTR | - SCB_MSGOUT_WDTR, - SCB_QUEUED_ABORT = 0x1000, - SCB_QUEUED_FOR_DONE = 0x2000, - SCB_WAS_BUSY = 0x4000 -} scb_flag_type; - -typedef enum { - AHC_FNONE = 0x00000000, - AHC_PAGESCBS = 0x00000001, - AHC_CHANNEL_B_PRIMARY = 0x00000002, - AHC_USEDEFAULTS = 0x00000004, - AHC_INDIRECT_PAGING = 0x00000008, - AHC_CHNLB = 0x00000020, - AHC_CHNLC = 0x00000040, - AHC_EXTEND_TRANS_A = 0x00000100, - AHC_EXTEND_TRANS_B = 0x00000200, - AHC_TERM_ENB_A = 0x00000400, - AHC_TERM_ENB_SE_LOW = 0x00000400, - AHC_TERM_ENB_B = 0x00000800, - AHC_TERM_ENB_SE_HIGH = 0x00000800, - AHC_HANDLING_REQINITS = 0x00001000, - AHC_TARGETMODE = 0x00002000, - AHC_NEWEEPROM_FMT = 0x00004000, - /* - * Here ends the FreeBSD defined flags and here begins the linux defined - * flags. NOTE: I did not preserve the old flag name during this change - * specifically to force me to evaluate what flags were being used properly - * and what flags weren't. This way, I could clean up the flag usage on - * a use by use basis. Doug Ledford - */ - AHC_MOTHERBOARD = 0x00020000, - AHC_NO_STPWEN = 0x00040000, - AHC_RESET_DELAY = 0x00080000, - AHC_A_SCANNED = 0x00100000, - AHC_B_SCANNED = 0x00200000, - AHC_MULTI_CHANNEL = 0x00400000, - AHC_BIOS_ENABLED = 0x00800000, - AHC_SEEPROM_FOUND = 0x01000000, - AHC_TERM_ENB_LVD = 0x02000000, - AHC_ABORT_PENDING = 0x04000000, - AHC_RESET_PENDING = 0x08000000, -#define AHC_IN_ISR_BIT 28 - AHC_IN_ISR = 0x10000000, - AHC_IN_ABORT = 0x20000000, - AHC_IN_RESET = 0x40000000, - AHC_EXTERNAL_SRAM = 0x80000000 -} ahc_flag_type; - -typedef enum { - AHC_NONE = 0x0000, - AHC_CHIPID_MASK = 0x00ff, - AHC_AIC7770 = 0x0001, - AHC_AIC7850 = 0x0002, - AHC_AIC7860 = 0x0003, - AHC_AIC7870 = 0x0004, - AHC_AIC7880 = 0x0005, - AHC_AIC7890 = 0x0006, - AHC_AIC7895 = 0x0007, - AHC_AIC7896 = 0x0008, - AHC_AIC7892 = 0x0009, - AHC_AIC7899 = 0x000a, - AHC_VL = 0x0100, - AHC_EISA = 0x0200, - AHC_PCI = 0x0400, -} ahc_chip; - -typedef enum { - AHC_FENONE = 0x0000, - AHC_ULTRA = 0x0001, - AHC_ULTRA2 = 0x0002, - AHC_WIDE = 0x0004, - AHC_TWIN = 0x0008, - AHC_MORE_SRAM = 0x0010, - AHC_CMD_CHAN = 0x0020, - AHC_QUEUE_REGS = 0x0040, - AHC_SG_PRELOAD = 0x0080, - AHC_SPIOCAP = 0x0100, - AHC_ULTRA3 = 0x0200, - AHC_NEW_AUTOTERM = 0x0400, - AHC_AIC7770_FE = AHC_FENONE, - AHC_AIC7850_FE = AHC_SPIOCAP, - AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP, - AHC_AIC7870_FE = AHC_FENONE, - AHC_AIC7880_FE = AHC_ULTRA, - AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2| - AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM, - AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA, - AHC_AIC7896_FE = AHC_AIC7890_FE, - AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA3, - AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3, -} ahc_feature; - -#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset) - -struct aic7xxx_scb_dma { - unsigned long dma_offset; /* Correction you have to add - * to virtual address to get - * dma handle in this region */ - dma_addr_t dma_address; /* DMA handle of the start, - * for unmap */ - unsigned int dma_len; /* DMA length */ -}; - -struct aic7xxx_scb { - struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ - Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */ - struct aic7xxx_scb *q_next; /* next scb in queue */ - volatile scb_flag_type flags; /* current state of scb */ - struct hw_scatterlist *sg_list; /* SG list in adapter format */ - unsigned char tag_action; - unsigned char sg_count; - unsigned char *sense_cmd; /* - * Allocate 6 characters for - * sense command. - */ - unsigned char *cmnd; - unsigned int sg_length; /* We init this during buildscb so we - * don't have to calculate anything - * during underflow/overflow/stat code - */ - void *kmalloc_ptr; - struct aic7xxx_scb_dma *scb_dma; -}; - -/* - * Define a linked list of SCBs. - */ -typedef struct { - struct aic7xxx_scb *head; - struct aic7xxx_scb *tail; -} scb_queue_type; - -static struct { - unsigned char errno; - const char *errmesg; -} hard_error[] = { - { ILLHADDR, "Illegal Host Access" }, - { ILLSADDR, "Illegal Sequencer Address referenced" }, - { ILLOPCODE, "Illegal Opcode in sequencer program" }, - { SQPARERR, "Sequencer Ram Parity Error" }, - { DPARERR, "Data-Path Ram Parity Error" }, - { MPARERR, "Scratch Ram/SCB Array Ram Parity Error" }, - { PCIERRSTAT,"PCI Error detected" }, - { CIOPARERR, "CIOBUS Parity Error" } -}; - -static unsigned char -generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 }; - -typedef struct { - scb_queue_type free_scbs; /* - * SCBs assigned to free slot on - * card (no paging required) - */ - struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; - struct aic7xxx_hwscb *hscbs; - unsigned char numscbs; /* current number of scbs */ - unsigned char maxhscbs; /* hardware scbs */ - unsigned char maxscbs; /* max scbs including pageable scbs */ - dma_addr_t hscbs_dma; /* DMA handle to hscbs */ - unsigned int hscbs_dma_len; /* length of the above DMA area */ - void *hscb_kmalloc_ptr; -} scb_data_type; - -struct target_cmd { - unsigned char mesg_bytes[4]; - unsigned char command[28]; -}; - -#define AHC_TRANS_CUR 0x0001 -#define AHC_TRANS_ACTIVE 0x0002 -#define AHC_TRANS_GOAL 0x0004 -#define AHC_TRANS_USER 0x0008 -#define AHC_TRANS_QUITE 0x0010 -typedef struct { - unsigned char cur_width; - unsigned char goal_width; - unsigned char cur_period; - unsigned char goal_period; - unsigned char cur_offset; - unsigned char goal_offset; - unsigned char cur_options; - unsigned char goal_options; - unsigned char user_width; - unsigned char user_period; - unsigned char user_offset; - unsigned char user_options; -} transinfo_type; - -/* - * Define a structure used for each host adapter. Note, in order to avoid - * problems with architectures I can't test on (because I don't have one, - * such as the Alpha based systems) which happen to give faults for - * non-aligned memory accesses, care was taken to align this structure - * in a way that gauranteed all accesses larger than 8 bits were aligned - * on the appropriate boundary. It's also organized to try and be more - * cache line efficient. Be careful when changing this lest you might hurt - * overall performance and bring down the wrath of the masses. - */ -struct aic7xxx_host { - /* - * This is the first 64 bytes in the host struct - */ - - /* - * We are grouping things here....first, items that get either read or - * written with nearly every interrupt - */ - volatile ahc_flag_type flags; - ahc_feature features; /* chip features */ - unsigned long base; /* card base address */ - volatile unsigned char *maddr; /* memory mapped address */ - unsigned long isr_count; /* Interrupt count */ - unsigned long spurious_int; - scb_data_type *scb_data; - volatile unsigned short needdv; - volatile unsigned short needppr; - volatile unsigned short needsdtr; - volatile unsigned short needwdtr; - volatile unsigned short dtr_pending; - struct aic7xxx_cmd_queue { - Scsi_Cmnd *head; - Scsi_Cmnd *tail; - } completeq; - - /* - * Things read/written on nearly every entry into aic7xxx_queue() - */ - volatile scb_queue_type waiting_scbs; - unsigned short discenable; /* Targets allowed to disconnect */ - unsigned short tagenable; /* Targets using tagged I/O */ - unsigned short orderedtag; /* Ordered Q tags allowed */ - unsigned char unpause; /* unpause value for HCNTRL */ - unsigned char pause; /* pause value for HCNTRL */ - volatile unsigned char qoutfifonext; - volatile unsigned char activescbs; /* active scbs */ - volatile unsigned char max_activescbs; - volatile unsigned char qinfifonext; - volatile unsigned char *untagged_scbs; - volatile unsigned char *qoutfifo; - volatile unsigned char *qinfifo; - -#define DEVICE_PRESENT 0x01 -#define BUS_DEVICE_RESET_PENDING 0x02 -#define DEVICE_RESET_DELAY 0x04 -#define DEVICE_PRINT_DTR 0x08 -#define DEVICE_PARITY_ERROR 0x10 -#define DEVICE_WAS_BUSY 0x20 -#define DEVICE_SCSI_3 0x40 -#define DEVICE_SCANNED 0x80 - volatile unsigned char dev_flags[MAX_TARGETS]; - volatile unsigned char dev_active_cmds[MAX_TARGETS]; - volatile unsigned char dev_temp_queue_depth[MAX_TARGETS]; - unsigned char dev_commands_sent[MAX_TARGETS]; - - unsigned int dev_timer_active; /* Which devs have a timer set */ - struct timer_list dev_timer; - unsigned long dev_expires[MAX_TARGETS]; - - spinlock_t spin_lock; - volatile unsigned char cpu_lock_count[NR_CPUS]; - - Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS]; - - unsigned int dev_checksum[MAX_TARGETS]; - - unsigned char dev_last_queue_full[MAX_TARGETS]; - unsigned char dev_last_queue_full_count[MAX_TARGETS]; - unsigned char dev_max_queue_depth[MAX_TARGETS]; - - volatile scb_queue_type delayed_scbs[MAX_TARGETS]; - - - unsigned char msg_buf[13]; /* The message for the target */ - unsigned char msg_type; -#define MSG_TYPE_NONE 0x00 -#define MSG_TYPE_INITIATOR_MSGOUT 0x01 -#define MSG_TYPE_INITIATOR_MSGIN 0x02 - unsigned char msg_len; /* Length of message */ - unsigned char msg_index; /* Index into msg_buf array */ - transinfo_type transinfo[MAX_TARGETS]; - - - /* - * We put the less frequently used host structure items after the more - * frequently used items to try and ease the burden on the cache subsystem. - * These entries are not *commonly* accessed, whereas the preceding entries - * are accessed very often. - */ - - unsigned int irq; /* IRQ for this adapter */ - int instance; /* aic7xxx instance number */ - int scsi_id; /* host adapter SCSI ID */ - int scsi_id_b; /* channel B for twin adapters */ - unsigned int bios_address; - int board_name_index; - unsigned short needppr_copy; /* default config */ - unsigned short needsdtr_copy; /* default config */ - unsigned short needwdtr_copy; /* default config */ - unsigned short ultraenb; /* Ultra mode target list */ - unsigned short bios_control; /* bios control - SEEPROM */ - unsigned short adapter_control; /* adapter control - SEEPROM */ - struct pci_dev *pdev; - unsigned char pci_bus; - unsigned char pci_device_fn; - struct seeprom_config sc; - unsigned short sc_type; - unsigned short sc_size; - struct aic7xxx_host *next; /* allow for multiple IRQs */ - struct Scsi_Host *host; /* pointer to scsi host */ - int host_no; /* SCSI host number */ - unsigned long mbase; /* I/O memory address */ - ahc_chip chip; /* chip type */ - dma_addr_t fifo_dma; /* DMA handle for fifo arrays */ - - /* - * Statistics Kept: - * - * Total Xfers (count for each command that has a data xfer), - * broken down further by reads && writes. - * - * Binned sizes, writes && reads: - * < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K - * - * Total amounts read/written above 512 bytes (amts under ignored) - * - * NOTE: Enabling this feature is likely to cause a noticeable performance - * decrease as the accesses into the stats structures blows apart multiple - * cache lines and is CPU time consuming. - * - * NOTE: Since it doesn't really buy us much, but consumes *tons* of RAM - * and blows apart all sorts of cache lines, I modified this so that we - * no longer look at the LUN. All LUNs now go into the same bin on each - * device for stats purposes. - */ - struct aic7xxx_xferstats { - long w_total; /* total writes */ - long r_total; /* total reads */ -#ifdef AIC7XXX_PROC_STATS - long w_bins[8]; /* binned write */ - long r_bins[8]; /* binned reads */ -#endif /* AIC7XXX_PROC_STATS */ - } stats[MAX_TARGETS]; /* [(channel << 3)|target] */ - -#if 0 - struct target_cmd *targetcmds; - unsigned int num_targetcmds; -#endif - -}; - -/* - * Valid SCSIRATE values. (p. 3-17) - * Provides a mapping of transfer periods in ns/4 to the proper value to - * stick in the SCSIRATE reg to use that transfer rate. - */ -#define AHC_SYNCRATE_ULTRA3 0 -#define AHC_SYNCRATE_ULTRA2 1 -#define AHC_SYNCRATE_ULTRA 3 -#define AHC_SYNCRATE_FAST 6 -#define AHC_SYNCRATE_CRC 0x40 -#define AHC_SYNCRATE_SE 0x10 -static struct aic7xxx_syncrate { - /* Rates in Ultra mode have bit 8 of sxfr set */ -#define ULTRA_SXFR 0x100 - int sxfr_ultra2; - int sxfr; - unsigned char period; - const char *rate[2]; -} aic7xxx_syncrates[] = { - { 0x42, 0x000, 9, {"80.0", "160.0"} }, - { 0x13, 0x000, 10, {"40.0", "80.0"} }, - { 0x14, 0x000, 11, {"33.0", "66.6"} }, - { 0x15, 0x100, 12, {"20.0", "40.0"} }, - { 0x16, 0x110, 15, {"16.0", "32.0"} }, - { 0x17, 0x120, 18, {"13.4", "26.8"} }, - { 0x18, 0x000, 25, {"10.0", "20.0"} }, - { 0x19, 0x010, 31, {"8.0", "16.0"} }, - { 0x1a, 0x020, 37, {"6.67", "13.3"} }, - { 0x1b, 0x030, 43, {"5.7", "11.4"} }, - { 0x10, 0x040, 50, {"5.0", "10.0"} }, - { 0x00, 0x050, 56, {"4.4", "8.8" } }, - { 0x00, 0x060, 62, {"4.0", "8.0" } }, - { 0x00, 0x070, 68, {"3.6", "7.2" } }, - { 0x00, 0x000, 0, {NULL, NULL} }, -}; - -#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1), \ - (((scb->hscb)->target_channel_lun >> 4) & 0xf), \ - ((scb->hscb)->target_channel_lun & 0x07) - -#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01), \ - ((cmd->target) & 0x0f), \ - ((cmd->lun) & 0x07) - -#define TARGET_INDEX(cmd) ((cmd)->target | ((cmd)->channel << 3)) - -/* - * A nice little define to make doing our printks a little easier - */ - -#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) " -#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) " - -/* - * XXX - these options apply unilaterally to _all_ 274x/284x/294x - * cards in the system. This should be fixed. Exceptions to this - * rule are noted in the comments. - */ - - -/* - * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This - * has no effect on any later resets that might occur due to things like - * SCSI bus timeouts. - */ -static unsigned int aic7xxx_no_reset = 0; -/* - * Certain PCI motherboards will scan PCI devices from highest to lowest, - * others scan from lowest to highest, and they tend to do all kinds of - * strange things when they come into contact with PCI bridge chips. The - * net result of all this is that the PCI card that is actually used to boot - * the machine is very hard to detect. Most motherboards go from lowest - * PCI slot number to highest, and the first SCSI controller found is the - * one you boot from. The only exceptions to this are when a controller - * has its BIOS disabled. So, we by default sort all of our SCSI controllers - * from lowest PCI slot number to highest PCI slot number. We also force - * all controllers with their BIOS disabled to the end of the list. This - * works on *almost* all computers. Where it doesn't work, we have this - * option. Setting this option to non-0 will reverse the order of the sort - * to highest first, then lowest, but will still leave cards with their BIOS - * disabled at the very end. That should fix everyone up unless there are - * really strange cirumstances. - */ -static int aic7xxx_reverse_scan = 0; -/* - * Should we force EXTENDED translation on a controller. - * 0 == Use whatever is in the SEEPROM or default to off - * 1 == Use whatever is in the SEEPROM or default to on - */ -static unsigned int aic7xxx_extended = 0; -/* - * The IRQ trigger method used on EISA controllers. Does not effect PCI cards. - * -1 = Use detected settings. - * 0 = Force Edge triggered mode. - * 1 = Force Level triggered mode. - */ -static int aic7xxx_irq_trigger = -1; -/* - * This variable is used to override the termination settings on a controller. - * This should not be used under normal conditions. However, in the case - * that a controller does not have a readable SEEPROM (so that we can't - * read the SEEPROM settings directly) and that a controller has a buggered - * version of the cable detection logic, this can be used to force the - * correct termination. It is preferable to use the manual termination - * settings in the BIOS if possible, but some motherboard controllers store - * those settings in a format we can't read. In other cases, auto term - * should also work, but the chipset was put together with no auto term - * logic (common on motherboard controllers). In those cases, we have - * 32 bits here to work with. That's good for 8 controllers/channels. The - * bits are organized as 4 bits per channel, with scsi0 getting the lowest - * 4 bits in the int. A 1 in a bit position indicates the termination setting - * that corresponds to that bit should be enabled, a 0 is disabled. - * It looks something like this: - * - * 0x0f = 1111-Single Ended Low Byte Termination on/off - * ||\-Single Ended High Byte Termination on/off - * |\-LVD Low Byte Termination on/off - * \-LVD High Byte Termination on/off - * - * For non-Ultra2 controllers, the upper 2 bits are not important. So, to - * enable both high byte and low byte termination on scsi0, I would need to - * make sure that the override_term variable was set to 0x03 (bits 0011). - * To make sure that all termination is enabled on an Ultra2 controller at - * scsi2 and only high byte termination on scsi1 and high and low byte - * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011) - * - * For the most part, users should never have to use this, that's why I - * left it fairly cryptic instead of easy to understand. If you need it, - * most likely someone will be telling you what your's needs to be set to. - */ -static int aic7xxx_override_term = -1; -/* - * Certain motherboard chipset controllers tend to screw - * up the polarity of the term enable output pin. Use this variable - * to force the correct polarity for your system. This is a bitfield variable - * similar to the previous one, but this one has one bit per channel instead - * of four. - * 0 = Force the setting to active low. - * 1 = Force setting to active high. - * Most Adaptec cards are active high, several motherboards are active low. - * To force a 2940 card at SCSI 0 to active high and a motherboard 7895 - * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3 - * to active high, you would need to set stpwlev=0x9 (bits 1001). - * - * People shouldn't need to use this, but if you are experiencing lots of - * SCSI timeout problems, this may help. There is one sure way to test what - * this option needs to be. Using a boot floppy to boot the system, configure - * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and - * if needed then also pass a value to override_term to make sure that the - * driver is enabling SCSI termination, then set this variable to either 0 - * or 1. When the driver boots, make sure there are *NO* SCSI cables - * connected to your controller. If it finds and inits the controller - * without problem, then the setting you passed to stpwlev was correct. If - * the driver goes into a reset loop and hangs the system, then you need the - * other setting for this variable. If neither setting lets the machine - * boot then you have definite termination problems that may not be fixable. - */ -static int aic7xxx_stpwlev = -1; -/* - * Set this to non-0 in order to force the driver to panic the kernel - * and print out debugging info on a SCSI abort or reset cycle. - */ -static int aic7xxx_panic_on_abort = 0; -/* - * PCI bus parity checking of the Adaptec controllers. This is somewhat - * dubious at best. To my knowledge, this option has never actually - * solved a PCI parity problem, but on certain machines with broken PCI - * chipset configurations, it can generate tons of false error messages. - * It's included in the driver for completeness. - * 0 = Shut off PCI parity check - * -1 = Normal polarity pci parity checking - * 1 = reverse polarity pci parity checking - * - * NOTE: you can't actually pass -1 on the lilo prompt. So, to set this - * variable to -1 you would actually want to simply pass the variable - * name without a number. That will invert the 0 which will result in - * -1. - */ -static int aic7xxx_pci_parity = 0; -/* - * Set this to any non-0 value to cause us to dump the contents of all - * the card's registers in a hex dump format tailored to each model of - * controller. - * - * NOTE: THE CONTROLLER IS LEFT IN AN UNUSEABLE STATE BY THIS OPTION. - * YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES - * ONLY - */ -static int aic7xxx_dump_card = 0; -/* - * Set this to a non-0 value to make us dump out the 32 bit instruction - * registers on the card after completing the sequencer download. This - * allows the actual sequencer download to be verified. It is possible - * to use this option and still boot up and run your system. This is - * only intended for debugging purposes. - */ -static int aic7xxx_dump_sequencer = 0; -/* - * Certain newer motherboards have put new PCI based devices into the - * IO spaces that used to typically be occupied by VLB or EISA cards. - * This overlap can cause these newer motherboards to lock up when scanned - * for older EISA and VLB devices. Setting this option to non-0 will - * cause the driver to skip scanning for any VLB or EISA controllers and - * only support the PCI controllers. NOTE: this means that if the kernel - * os compiled with PCI support disabled, then setting this to non-0 - * would result in never finding any devices :) - */ -static int aic7xxx_no_probe = 0; -/* - * On some machines, enabling the external SCB RAM isn't reliable yet. I - * haven't had time to make test patches for things like changing the - * timing mode on that external RAM either. Some of those changes may - * fix the problem. Until then though, we default to external SCB RAM - * off and give a command line option to enable it. - */ -static int aic7xxx_scbram = 0; -/* - * So that we can set how long each device is given as a selection timeout. - * The table of values goes like this: - * 0 - 256ms - * 1 - 128ms - * 2 - 64ms - * 3 - 32ms - * We default to 64ms because it's fast. Some old SCSI-I devices need a - * longer time. The final value has to be left shifted by 3, hence 0x10 - * is the final value. - */ -static int aic7xxx_seltime = 0x10; -/* - * So that insmod can find the variable and make it point to something - */ -#ifdef MODULE -static char * aic7xxx = NULL; -MODULE_PARM(aic7xxx, "s"); - -/* - * Just in case someone uses commas to separate items on the insmod - * command line, we define a dummy buffer here to avoid having insmod - * write wild stuff into our code segment - */ -static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n"; - -#endif - -#define VERBOSE_NORMAL 0x0000 -#define VERBOSE_NEGOTIATION 0x0001 -#define VERBOSE_SEQINT 0x0002 -#define VERBOSE_SCSIINT 0x0004 -#define VERBOSE_PROBE 0x0008 -#define VERBOSE_PROBE2 0x0010 -#define VERBOSE_NEGOTIATION2 0x0020 -#define VERBOSE_MINOR_ERROR 0x0040 -#define VERBOSE_TRACING 0x0080 -#define VERBOSE_ABORT 0x0f00 -#define VERBOSE_ABORT_MID 0x0100 -#define VERBOSE_ABORT_FIND 0x0200 -#define VERBOSE_ABORT_PROCESS 0x0400 -#define VERBOSE_ABORT_RETURN 0x0800 -#define VERBOSE_RESET 0xf000 -#define VERBOSE_RESET_MID 0x1000 -#define VERBOSE_RESET_FIND 0x2000 -#define VERBOSE_RESET_PROCESS 0x4000 -#define VERBOSE_RESET_RETURN 0x8000 -static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION | - VERBOSE_PROBE; /* verbose messages */ - - -/**************************************************************************** - * - * We're going to start putting in function declarations so that order of - * functions is no longer important. As needed, they are added here. - * - ***************************************************************************/ - -static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd); -static void aic7xxx_print_card(struct aic7xxx_host *p); -static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p); -static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded); -#ifdef AIC7XXX_VERBOSE_DEBUGGING -static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer); -#endif - -/**************************************************************************** - * - * These functions are now used. They happen to be wrapped in useless - * inb/outb port read/writes around the real reads and writes because it - * seems that certain very fast CPUs have a problem dealing with us when - * going at full speed. - * - ***************************************************************************/ - -static inline unsigned char -aic_inb(struct aic7xxx_host *p, long port) -{ -#ifdef MMAPIO - unsigned char x; - if(p->maddr) - { - x = readb(p->maddr + port); - } - else - { - x = inb(p->base + port); - } - return(x); -#else - return(inb(p->base + port)); -#endif -} - -static inline void -aic_outb(struct aic7xxx_host *p, unsigned char val, long port) -{ -#ifdef MMAPIO - if(p->maddr) - { - writeb(val, p->maddr + port); - mb(); /* locked operation in order to force CPU ordering */ - readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */ - } - else - { - outb(val, p->base + port); - mb(); /* locked operation in order to force CPU ordering */ - } -#else - outb(val, p->base + port); - mb(); /* locked operation in order to force CPU ordering */ -#endif -} - -/*+F************************************************************************* - * Function: - * aic7xxx_setup - * - * Description: - * Handle Linux boot parameters. This routine allows for assigning a value - * to a parameter with a ':' between the parameter and the value. - * ie. aic7xxx=unpause:0x0A,extended - *-F*************************************************************************/ -static int -aic7xxx_setup(char *s) -{ - int i, n; - char *p; - char *end; - - static struct { - const char *name; - unsigned int *flag; - } options[] = { - { "extended", &aic7xxx_extended }, - { "no_reset", &aic7xxx_no_reset }, - { "irq_trigger", &aic7xxx_irq_trigger }, - { "verbose", &aic7xxx_verbose }, - { "reverse_scan",&aic7xxx_reverse_scan }, - { "override_term", &aic7xxx_override_term }, - { "stpwlev", &aic7xxx_stpwlev }, - { "no_probe", &aic7xxx_no_probe }, - { "panic_on_abort", &aic7xxx_panic_on_abort }, - { "pci_parity", &aic7xxx_pci_parity }, - { "dump_card", &aic7xxx_dump_card }, - { "dump_sequencer", &aic7xxx_dump_sequencer }, - { "scbram", &aic7xxx_scbram }, - { "seltime", &aic7xxx_seltime }, - { "tag_info", NULL } - }; - - end = strchr(s, '\0'); - - for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) - { - for (i = 0; i < NUMBER(options); i++) - { - n = strlen(options[i].name); - if (!strncmp(options[i].name, p, n)) - { - if (!strncmp(p, "tag_info", n)) - { - if (p[n] == ':') - { - char *base; - char *tok, *tok_end, *tok_end2; - char tok_list[] = { '.', ',', '{', '}', '\0' }; - int i, instance = -1, device = -1; - unsigned char done = FALSE; - - base = p; - tok = base + n + 1; /* Forward us just past the ':' */ - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while(!done) - { - switch(*tok) - { - case '{': - if (instance == -1) - instance = 0; - else if (device == -1) - device = 0; - tok++; - break; - case '}': - if (device != -1) - device = -1; - else if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (device >= 0) - device++; - else if (instance >= 0) - instance++; - if ( (device >= MAX_TARGETS) || - (instance >= NUMBER(aic7xxx_tag_info)) ) - done = TRUE; - tok++; - if (!done) - { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for(i=0; tok_list[i]; i++) - { - tok_end2 = strchr(tok, tok_list[i]); - if ( (tok_end2) && (tok_end2 < tok_end) ) - { - tok_end = tok_end2; - done = FALSE; - } - } - if ( (instance >= 0) && (device >= 0) && - (instance < NUMBER(aic7xxx_tag_info)) && - (device < MAX_TARGETS) ) - aic7xxx_tag_info[instance].tag_commands[device] = - simple_strtoul(tok, NULL, 0) & 0xff; - tok = tok_end; - break; - } - } - while((p != base) && (p != NULL)) - p = strtok(NULL, ",."); - } - } - else if (p[n] == ':') - { - *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); - if(!strncmp(p, "seltime", n)) - { - *(options[i].flag) = (*(options[i].flag) % 4) << 3; - } - } - else if (!strncmp(p, "verbose", n)) - { - *(options[i].flag) = 0xff29; - } - else - { - *(options[i].flag) = ~(*(options[i].flag)); - if(!strncmp(p, "seltime", n)) - { - *(options[i].flag) = (*(options[i].flag) % 4) << 3; - } - } - } - } - } - return 1; -} - -__setup("aic7xxx=", aic7xxx_setup); - -/*+F************************************************************************* - * Function: - * pause_sequencer - * - * Description: - * Pause the sequencer and wait for it to actually stop - this - * is important since the sequencer can disable pausing for critical - * sections. - *-F*************************************************************************/ -static void -pause_sequencer(struct aic7xxx_host *p) -{ - aic_outb(p, p->pause, HCNTRL); - while ((aic_inb(p, HCNTRL) & PAUSE) == 0) - { - ; - } - if(p->features & AHC_ULTRA2) - { - aic_inb(p, CCSCBCTL); - } -} - -/*+F************************************************************************* - * Function: - * unpause_sequencer - * - * Description: - * Unpause the sequencer. Unremarkable, yet done often enough to - * warrant an easy way to do it. - *-F*************************************************************************/ -static void -unpause_sequencer(struct aic7xxx_host *p, int unpause_always) -{ - if (unpause_always || - ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) && - !(p->flags & AHC_HANDLING_REQINITS) ) ) - { - aic_outb(p, p->unpause, HCNTRL); - } -} - -/*+F************************************************************************* - * Function: - * restart_sequencer - * - * Description: - * Restart the sequencer program from address zero. This assumes - * that the sequencer is already paused. - *-F*************************************************************************/ -static void -restart_sequencer(struct aic7xxx_host *p) -{ - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE, SEQCTL); -} - -/* - * We include the aic7xxx_seq.c file here so that the other defines have - * already been made, and so that it comes before the code that actually - * downloads the instructions (since we don't typically use function - * prototype, our code has to be ordered that way, it's a left-over from - * the original driver days.....I should fix it some time DL). - */ -#include "aic7xxx_seq.c" - -/*+F************************************************************************* - * Function: - * aic7xxx_check_patch - * - * Description: - * See if the next patch to download should be downloaded. - *-F*************************************************************************/ -static int -aic7xxx_check_patch(struct aic7xxx_host *p, - struct sequencer_patch **start_patch, int start_instr, int *skip_addr) -{ - struct sequencer_patch *cur_patch; - struct sequencer_patch *last_patch; - int num_patches; - - num_patches = sizeof(sequencer_patches)/sizeof(struct sequencer_patch); - last_patch = &sequencer_patches[num_patches]; - cur_patch = *start_patch; - - while ((cur_patch < last_patch) && (start_instr == cur_patch->begin)) - { - if (cur_patch->patch_func(p) == 0) - { - /* - * Start rejecting code. - */ - *skip_addr = start_instr + cur_patch->skip_instr; - cur_patch += cur_patch->skip_patch; - } - else - { - /* - * Found an OK patch. Advance the patch pointer to the next patch - * and wait for our instruction pointer to get here. - */ - cur_patch++; - } - } - - *start_patch = cur_patch; - if (start_instr < *skip_addr) - /* - * Still skipping - */ - return (0); - return(1); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_download_instr - * - * Description: - * Find the next patch to download. - *-F*************************************************************************/ -static void -aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr, - unsigned char *dconsts) -{ - union ins_formats instr; - struct ins_format1 *fmt1_ins; - struct ins_format3 *fmt3_ins; - unsigned char opcode; - - instr = *(union ins_formats*) &seqprog[instrptr * 4]; - - instr.integer = le32_to_cpu(instr.integer); - - fmt1_ins = &instr.format1; - fmt3_ins = NULL; - - /* Pull the opcode */ - opcode = instr.format1.opcode; - switch (opcode) - { - case AIC_OP_JMP: - case AIC_OP_JC: - case AIC_OP_JNC: - case AIC_OP_CALL: - case AIC_OP_JNE: - case AIC_OP_JNZ: - case AIC_OP_JE: - case AIC_OP_JZ: - { - struct sequencer_patch *cur_patch; - int address_offset; - unsigned int address; - int skip_addr; - int i; - - fmt3_ins = &instr.format3; - address_offset = 0; - address = fmt3_ins->address; - cur_patch = sequencer_patches; - skip_addr = 0; - - for (i = 0; i < address;) - { - aic7xxx_check_patch(p, &cur_patch, i, &skip_addr); - if (skip_addr > i) - { - int end_addr; - - end_addr = MIN(address, skip_addr); - address_offset += end_addr - i; - i = skip_addr; - } - else - { - i++; - } - } - address -= address_offset; - fmt3_ins->address = address; - /* Fall Through to the next code section */ - } - case AIC_OP_OR: - case AIC_OP_AND: - case AIC_OP_XOR: - case AIC_OP_ADD: - case AIC_OP_ADC: - case AIC_OP_BMOV: - if (fmt1_ins->parity != 0) - { - fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; - } - fmt1_ins->parity = 0; - /* Fall Through to the next code section */ - case AIC_OP_ROL: - if ((p->features & AHC_ULTRA2) != 0) - { - int i, count; - - /* Calculate odd parity for the instruction */ - for ( i=0, count=0; i < 31; i++) - { - unsigned int mask; - - mask = 0x01 << i; - if ((instr.integer & mask) != 0) - count++; - } - if (!(count & 0x01)) - instr.format1.parity = 1; - } - else - { - if (fmt3_ins != NULL) - { - instr.integer = fmt3_ins->immediate | - (fmt3_ins->source << 8) | - (fmt3_ins->address << 16) | - (fmt3_ins->opcode << 25); - } - else - { - instr.integer = fmt1_ins->immediate | - (fmt1_ins->source << 8) | - (fmt1_ins->destination << 16) | - (fmt1_ins->ret << 24) | - (fmt1_ins->opcode << 25); - } - } - aic_outb(p, (instr.integer & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM); - udelay(10); - break; - - default: - panic("aic7xxx: Unknown opcode encountered in sequencer program."); - break; - } -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_loadseq - * - * Description: - * Load the sequencer code into the controller memory. - *-F*************************************************************************/ -static void -aic7xxx_loadseq(struct aic7xxx_host *p) -{ - struct sequencer_patch *cur_patch; - int i; - int downloaded; - int skip_addr; - unsigned char download_consts[4] = {0, 0, 0, 0}; - - if (aic7xxx_verbose & VERBOSE_PROBE) - { - printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no); - } -#if 0 - download_consts[TMODE_NUMCMDS] = p->num_targetcmds; -#endif - download_consts[TMODE_NUMCMDS] = 0; - cur_patch = &sequencer_patches[0]; - downloaded = 0; - skip_addr = 0; - - aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL); - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - - for (i = 0; i < sizeof(seqprog) / 4; i++) - { - if (aic7xxx_check_patch(p, &cur_patch, i, &skip_addr) == 0) - { - /* Skip this instruction for this configuration. */ - continue; - } - aic7xxx_download_instr(p, i, &download_consts[0]); - downloaded++; - } - - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE | FAILDIS, SEQCTL); - unpause_sequencer(p, TRUE); - mdelay(1); - pause_sequencer(p); - aic_outb(p, FASTMODE, SEQCTL); - if (aic7xxx_verbose & VERBOSE_PROBE) - { - printk(" %d instructions downloaded\n", downloaded); - } - if (aic7xxx_dump_sequencer) - aic7xxx_print_sequencer(p, downloaded); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_sequencer - * - * Description: - * Print the contents of the sequencer memory to the screen. - *-F*************************************************************************/ -static void -aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded) -{ - int i, k, temp; - - aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL); - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - - k = 0; - for (i=0; i < downloaded; i++) - { - if ( k == 0 ) - printk("%03x: ", i); - temp = aic_inb(p, SEQRAM); - temp |= (aic_inb(p, SEQRAM) << 8); - temp |= (aic_inb(p, SEQRAM) << 16); - temp |= (aic_inb(p, SEQRAM) << 24); - printk("%08x", temp); - if ( ++k == 8 ) - { - printk("\n"); - k = 0; - } - else - printk(" "); - } - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE | FAILDIS, SEQCTL); - unpause_sequencer(p, TRUE); - mdelay(1); - pause_sequencer(p); - aic_outb(p, FASTMODE, SEQCTL); - printk("\n"); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_info - * - * Description: - * Return a string describing the driver. - *-F*************************************************************************/ -const char * -aic7xxx_info(struct Scsi_Host *dooh) -{ - static char buffer[256]; - char *bp; - struct aic7xxx_host *p; - - bp = &buffer[0]; - p = (struct aic7xxx_host *)dooh->hostdata; - memset(bp, 0, sizeof(buffer)); - strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) "); - strcat(bp, AIC7XXX_C_VERSION); - strcat(bp, "/"); - strcat(bp, AIC7XXX_H_VERSION); - strcat(bp, "\n"); - strcat(bp, " <"); - strcat(bp, board_names[p->board_name_index]); - strcat(bp, ">"); - - return(bp); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_find_syncrate - * - * Description: - * Look up the valid period to SCSIRATE conversion in our table - *-F*************************************************************************/ -static struct aic7xxx_syncrate * -aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period, - unsigned int maxsync, unsigned char *options) -{ - struct aic7xxx_syncrate *syncrate; - int done = FALSE; - - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC: - case MSG_EXT_PPR_OPTION_DT_UNITS: - if(!(p->features & AHC_ULTRA3)) - { - *options = 0; - maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); - } - break; - case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: - case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK: - if(!(p->features & AHC_ULTRA3)) - { - *options = 0; - maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); - } - else - { - /* - * we don't support the Quick Arbitration variants of dual edge - * clocking. As it turns out, we want to send back the - * same basic option, but without the QA attribute. - * We know that we are responding because we would never set - * these options ourself, we would only respond to them. - */ - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: - *options = MSG_EXT_PPR_OPTION_DT_CRC; - break; - case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK: - *options = MSG_EXT_PPR_OPTION_DT_UNITS; - break; - } - } - break; - default: - *options = 0; - maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); - break; - } - syncrate = &aic7xxx_syncrates[maxsync]; - while ( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) ) - { - if (*period <= syncrate->period) - { - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC: - case MSG_EXT_PPR_OPTION_DT_UNITS: - if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC)) - { - done = TRUE; - /* - * oops, we went too low for the CRC/DualEdge signalling, so - * clear the options byte - */ - *options = 0; - /* - * We'll be sending a reply to this packet to set the options - * properly, so unilaterally set the period as well. - */ - *period = syncrate->period; - } - else - { - done = TRUE; - if(syncrate == &aic7xxx_syncrates[maxsync]) - { - *period = syncrate->period; - } - } - break; - default: - if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC)) - { - done = TRUE; - if(syncrate == &aic7xxx_syncrates[maxsync]) - { - *period = syncrate->period; - } - } - break; - } - if(done) - { - break; - } - } - syncrate++; - } - if ( (*period == 0) || (syncrate->rate[0] == NULL) || - ((p->features & AHC_ULTRA2) && (syncrate->sxfr_ultra2 == 0)) ) - { - /* - * Use async transfers for this target - */ - *options = 0; - *period = 255; - syncrate = NULL; - } - return (syncrate); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_find_period - * - * Description: - * Look up the valid SCSIRATE to period conversion in our table - *-F*************************************************************************/ -static unsigned int -aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate, - unsigned int maxsync) -{ - struct aic7xxx_syncrate *syncrate; - - if (p->features & AHC_ULTRA2) - { - scsirate &= SXFR_ULTRA2; - } - else - { - scsirate &= SXFR; - } - - syncrate = &aic7xxx_syncrates[maxsync]; - while (syncrate->rate[0] != NULL) - { - if (p->features & AHC_ULTRA2) - { - if (syncrate->sxfr_ultra2 == 0) - break; - else if (scsirate == syncrate->sxfr_ultra2) - return (syncrate->period); - else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC)) - return (syncrate->period); - } - else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR)) - { - return (syncrate->period); - } - syncrate++; - } - return (0); /* async */ -} - -/*+F************************************************************************* - * Function: - * aic7xxx_validate_offset - * - * Description: - * Set a valid offset value for a particular card in use and transfer - * settings in use. - *-F*************************************************************************/ -static void -aic7xxx_validate_offset(struct aic7xxx_host *p, - struct aic7xxx_syncrate *syncrate, unsigned int *offset, int wide) -{ - unsigned int maxoffset; - - /* Limit offset to what the card (and device) can do */ - if (syncrate == NULL) - { - maxoffset = 0; - } - else if (p->features & AHC_ULTRA2) - { - maxoffset = MAX_OFFSET_ULTRA2; - } - else - { - if (wide) - maxoffset = MAX_OFFSET_16BIT; - else - maxoffset = MAX_OFFSET_8BIT; - } - *offset = MIN(*offset, maxoffset); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_set_syncrate - * - * Description: - * Set the actual syncrate down in the card and in our host structs - *-F*************************************************************************/ -static void -aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate, - int target, int channel, unsigned int period, unsigned int offset, - unsigned char options, unsigned int type) -{ - unsigned char tindex; - unsigned short target_mask; - unsigned char lun, old_options; - unsigned int old_period, old_offset; - - tindex = target | (channel << 3); - target_mask = 0x01 << tindex; - lun = aic_inb(p, SCB_TCL) & 0x07; - - if (syncrate == NULL) - { - period = 0; - offset = 0; - } - - old_period = p->transinfo[tindex].cur_period; - old_offset = p->transinfo[tindex].cur_offset; - old_options = p->transinfo[tindex].cur_options; - - - if (type & AHC_TRANS_CUR) - { - unsigned int scsirate; - - scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - if (p->features & AHC_ULTRA2) - { - scsirate &= ~SXFR_ULTRA2; - if (syncrate != NULL) - { - switch(options) - { - case MSG_EXT_PPR_OPTION_DT_UNITS: - /* - * mask off the CRC bit in the xfer settings - */ - scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC); - break; - default: - scsirate |= syncrate->sxfr_ultra2; - break; - } - } - if (type & AHC_TRANS_ACTIVE) - { - aic_outb(p, offset, SCSIOFFSET); - } - aic_outb(p, offset, TARG_OFFSET + tindex); - } - else /* Not an Ultra2 controller */ - { - scsirate &= ~(SXFR|SOFS); - p->ultraenb &= ~target_mask; - if (syncrate != NULL) - { - if (syncrate->sxfr & ULTRA_SXFR) - { - p->ultraenb |= target_mask; - } - scsirate |= (syncrate->sxfr & SXFR); - scsirate |= (offset & SOFS); - } - if (type & AHC_TRANS_ACTIVE) - { - unsigned char sxfrctl0; - - sxfrctl0 = aic_inb(p, SXFRCTL0); - sxfrctl0 &= ~FAST20; - if (p->ultraenb & target_mask) - sxfrctl0 |= FAST20; - aic_outb(p, sxfrctl0, SXFRCTL0); - } - aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB); - aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1 ); - } - if (type & AHC_TRANS_ACTIVE) - { - aic_outb(p, scsirate, SCSIRATE); - } - aic_outb(p, scsirate, TARG_SCSIRATE + tindex); - p->transinfo[tindex].cur_period = period; - p->transinfo[tindex].cur_offset = offset; - p->transinfo[tindex].cur_options = options; - if ( !(type & AHC_TRANS_QUITE) && - (aic7xxx_verbose & VERBOSE_NEGOTIATION) && - (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) - { - if (offset) - { - int rate_mod = (scsirate & WIDEXFER) ? 1 : 0; - - printk(INFO_LEAD "Synchronous at %s Mbyte/sec, " - "offset %d.\n", p->host_no, channel, target, lun, - syncrate->rate[rate_mod], offset); - } - else - { - printk(INFO_LEAD "Using asynchronous transfers.\n", - p->host_no, channel, target, lun); - } - p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR; - } - } - - if (type & AHC_TRANS_GOAL) - { - p->transinfo[tindex].goal_period = period; - p->transinfo[tindex].goal_offset = offset; - p->transinfo[tindex].goal_options = options; - } - - if (type & AHC_TRANS_USER) - { - p->transinfo[tindex].user_period = period; - p->transinfo[tindex].user_offset = offset; - p->transinfo[tindex].user_options = options; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_set_width - * - * Description: - * Set the actual width down in the card and in our host structs - *-F*************************************************************************/ -static void -aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun, - unsigned int width, unsigned int type) -{ - unsigned char tindex; - unsigned short target_mask; - unsigned int old_width; - - tindex = target | (channel << 3); - target_mask = 1 << tindex; - - old_width = p->transinfo[tindex].cur_width; - - if (type & AHC_TRANS_CUR) - { - unsigned char scsirate; - - scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - - scsirate &= ~WIDEXFER; - if (width == MSG_EXT_WDTR_BUS_16_BIT) - scsirate |= WIDEXFER; - - aic_outb(p, scsirate, TARG_SCSIRATE + tindex); - - if (type & AHC_TRANS_ACTIVE) - aic_outb(p, scsirate, SCSIRATE); - - p->transinfo[tindex].cur_width = width; - - if ( !(type & AHC_TRANS_QUITE) && - (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target, - lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" ); - } - } - - if (type & AHC_TRANS_GOAL) - p->transinfo[tindex].goal_width = width; - if (type & AHC_TRANS_USER) - p->transinfo[tindex].user_width = width; - - if (p->transinfo[tindex].goal_offset) - { - if (p->features & AHC_ULTRA2) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - } - else if (width == MSG_EXT_WDTR_BUS_16_BIT) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; - } - else - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; - } - } -} - -/*+F************************************************************************* - * Function: - * scbq_init - * - * Description: - * SCB queue initialization. - * - *-F*************************************************************************/ -static void -scbq_init(volatile scb_queue_type *queue) -{ - queue->head = NULL; - queue->tail = NULL; -} - -/*+F************************************************************************* - * Function: - * scbq_insert_head - * - * Description: - * Add an SCB to the head of the list. - * - *-F*************************************************************************/ -static inline void -scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned long cpu_flags; -#endif - - DRIVER_LOCK - scb->q_next = queue->head; - queue->head = scb; - if (queue->tail == NULL) /* If list was empty, update tail. */ - queue->tail = queue->head; - DRIVER_UNLOCK -} - -/*+F************************************************************************* - * Function: - * scbq_remove_head - * - * Description: - * Remove an SCB from the head of the list. - * - *-F*************************************************************************/ -static inline struct aic7xxx_scb * -scbq_remove_head(volatile scb_queue_type *queue) -{ - struct aic7xxx_scb * scbp; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned long cpu_flags; -#endif - - DRIVER_LOCK - scbp = queue->head; - if (queue->head != NULL) - queue->head = queue->head->q_next; - if (queue->head == NULL) /* If list is now empty, update tail. */ - queue->tail = NULL; - DRIVER_UNLOCK - return(scbp); -} - -/*+F************************************************************************* - * Function: - * scbq_remove - * - * Description: - * Removes an SCB from the list. - * - *-F*************************************************************************/ -static inline void -scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned long cpu_flags; -#endif - - DRIVER_LOCK - if (queue->head == scb) - { - /* At beginning of queue, remove from head. */ - scbq_remove_head(queue); - } - else - { - struct aic7xxx_scb *curscb = queue->head; - - /* - * Search until the next scb is the one we're looking for, or - * we run out of queue. - */ - while ((curscb != NULL) && (curscb->q_next != scb)) - { - curscb = curscb->q_next; - } - if (curscb != NULL) - { - /* Found it. */ - curscb->q_next = scb->q_next; - if (scb->q_next == NULL) - { - /* Update the tail when removing the tail. */ - queue->tail = curscb; - } - } - } - DRIVER_UNLOCK -} - -/*+F************************************************************************* - * Function: - * scbq_insert_tail - * - * Description: - * Add an SCB at the tail of the list. - * - *-F*************************************************************************/ -static inline void -scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned long cpu_flags; -#endif - - DRIVER_LOCK - scb->q_next = NULL; - if (queue->tail != NULL) /* Add the scb at the end of the list. */ - queue->tail->q_next = scb; - queue->tail = scb; /* Update the tail. */ - if (queue->head == NULL) /* If list was empty, update head. */ - queue->head = queue->tail; - DRIVER_UNLOCK -} - -/*+F************************************************************************* - * Function: - * aic7xxx_match_scb - * - * Description: - * Checks to see if an scb matches the target/channel as specified. - * If target is ALL_TARGETS (-1), then we're looking for any device - * on the specified channel; this happens when a channel is going - * to be reset and all devices on that channel must be aborted. - *-F*************************************************************************/ -static int -aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, - int target, int channel, int lun, unsigned char tag) -{ - int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F; - int chan = (scb->hscb->target_channel_lun >> 3) & 0x01; - int slun = scb->hscb->target_channel_lun & 0x07; - int match; - - match = ((chan == channel) || (channel == ALL_CHANNELS)); - if (match != 0) - match = ((targ == target) || (target == ALL_TARGETS)); - if (match != 0) - match = ((lun == slun) || (lun == ALL_LUNS)); - if (match != 0) - match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); - - return (match); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_add_curscb_to_free_list - * - * Description: - * Adds the current scb (in SCBPTR) to the list of free SCBs. - *-F*************************************************************************/ -static void -aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p) -{ - /* - * Invalidate the tag so that aic7xxx_find_scb doesn't think - * it's active - */ - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - - aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT); - aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_rem_scb_from_disc_list - * - * Description: - * Removes the current SCB from the disconnected list and adds it - * to the free list. - *-F*************************************************************************/ -static unsigned char -aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr, - unsigned char prev) -{ - unsigned char next; - - aic_outb(p, scbptr, SCBPTR); - next = aic_inb(p, SCB_NEXT); - aic7xxx_add_curscb_to_free_list(p); - - if (prev != SCB_LIST_NULL) - { - aic_outb(p, prev, SCBPTR); - aic_outb(p, next, SCB_NEXT); - } - else - { - aic_outb(p, next, DISCONNECTED_SCBH); - } - - return next; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_busy_target - * - * Description: - * Set the specified target busy. - *-F*************************************************************************/ -static inline void -aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_index_busy_target - * - * Description: - * Returns the index of the busy target, and optionally sets the - * target inactive. - *-F*************************************************************************/ -static inline unsigned char -aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl, - int unbusy) -{ - unsigned char busy_scbid; - - busy_scbid = p->untagged_scbs[tcl]; - if (unbusy) - { - p->untagged_scbs[tcl] = SCB_LIST_NULL; - } - return (busy_scbid); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_find_scb - * - * Description: - * Look through the SCB array of the card and attempt to find the - * hardware SCB that corresponds to the passed in SCB. Return - * SCB_LIST_NULL if unsuccessful. This routine assumes that the - * card is already paused. - *-F*************************************************************************/ -static unsigned char -aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - unsigned char saved_scbptr; - unsigned char curindex; - - saved_scbptr = aic_inb(p, SCBPTR); - curindex = 0; - for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++) - { - aic_outb(p, curindex, SCBPTR); - if (aic_inb(p, SCB_TAG) == scb->hscb->tag) - { - break; - } - } - aic_outb(p, saved_scbptr, SCBPTR); - if (curindex >= p->scb_data->maxhscbs) - { - curindex = SCB_LIST_NULL; - } - - return (curindex); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_allocate_scb - * - * Description: - * Get an SCB from the free list or by allocating a new one. - *-F*************************************************************************/ -static int -aic7xxx_allocate_scb(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scbp = NULL; - int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6; - int i; - int step = PAGE_SIZE / 1024; - unsigned long scb_count = 0; - struct hw_scatterlist *hsgp; - struct aic7xxx_scb *scb_ap; - struct aic7xxx_scb_dma *scb_dma; - unsigned char *bufs; - - if (p->scb_data->numscbs < p->scb_data->maxscbs) - { - /* - * Calculate the optimal number of SCBs to allocate. - * - * NOTE: This formula works because the sizeof(sg_array) is always - * 1024. Therefore, scb_size * i would always be > PAGE_SIZE * - * (i/step). The (i-1) allows the left hand side of the equation - * to grow into the right hand side to a point of near perfect - * efficiency since scb_size * (i -1) is growing slightly faster - * than the right hand side. If the number of SG array elements - * is changed, this function may not be near so efficient any more. - * - * Since the DMA'able buffers are now allocated in a seperate - * chunk this algorithm has been modified to match. The '12' - * and '6' factors in scb_size are for the DMA'able command byte - * and sensebuffers respectively. -DaveM - */ - for ( i=step;; i *= 2 ) - { - if ( (scb_size * (i-1)) >= ( (PAGE_SIZE * (i/step)) - 64 ) ) - { - i /= 2; - break; - } - } - scb_count = MIN( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs); - scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count - + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC); - if (scb_ap == NULL) - return(0); - scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count]; - hsgp = (struct hw_scatterlist *) - pci_alloc_consistent(p->pdev, scb_size * scb_count, - &scb_dma->dma_address); - if (hsgp == NULL) - { - kfree(scb_ap); - return(0); - } - bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG]; -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - { - if (p->scb_data->numscbs == 0) - printk(INFO_LEAD "Allocating initial %ld SCB structures.\n", - p->host_no, -1, -1, -1, scb_count); - else - printk(INFO_LEAD "Allocating %ld additional SCB structures.\n", - p->host_no, -1, -1, -1, scb_count); - } -#endif - memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count); - scb_dma->dma_offset = (unsigned long)scb_dma->dma_address - - (unsigned long)hsgp; - scb_dma->dma_len = scb_size * scb_count; - for (i=0; i < scb_count; i++) - { - scbp = &scb_ap[i]; - scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs]; - scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG]; - scbp->sense_cmd = bufs; - scbp->cmnd = bufs + 6; - bufs += 12 + 6; - scbp->scb_dma = scb_dma; - memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb)); - scbp->hscb->tag = p->scb_data->numscbs; - /* - * Place in the scb array; never is removed - */ - p->scb_data->scb_array[p->scb_data->numscbs++] = scbp; - scbq_insert_tail(&p->scb_data->free_scbs, scbp); - } - scbp->kmalloc_ptr = scb_ap; - } - return(scb_count); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_queue_cmd_complete - * - * Description: - * Due to race conditions present in the SCSI subsystem, it is easier - * to queue completed commands, then call scsi_done() on them when - * we're finished. This function queues the completed commands. - *-F*************************************************************************/ -static void -aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd) -{ - cmd->host_scribble = (char *)p->completeq.head; - p->completeq.head = cmd; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_done_cmds_complete - * - * Description: - * Process the completed command queue. - *-F*************************************************************************/ -static void -aic7xxx_done_cmds_complete(struct aic7xxx_host *p) -{ - Scsi_Cmnd *cmd; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned int cpu_flags = 0; -#endif - - DRIVER_LOCK - while (p->completeq.head != NULL) - { - cmd = p->completeq.head; - p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->scsi_done(cmd); - } - DRIVER_UNLOCK -} - -/*+F************************************************************************* - * Function: - * aic7xxx_free_scb - * - * Description: - * Free the scb and insert into the free scb list. - *-F*************************************************************************/ -static void -aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - - scb->flags = SCB_FREE; - scb->cmd = NULL; - scb->sg_count = 0; - scb->sg_length = 0; - scb->tag_action = 0; - scb->hscb->control = 0; - scb->hscb->target_status = 0; - scb->hscb->target_channel_lun = SCB_LIST_NULL; - - scbq_insert_head(&p->scb_data->free_scbs, scb); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_done - * - * Description: - * Calls the higher level scsi done function and frees the scb. - *-F*************************************************************************/ -static void -aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - Scsi_Cmnd *cmd = scb->cmd; - int tindex = TARGET_INDEX(cmd); - struct aic7xxx_scb *scbp; - unsigned char queue_depth; - - if (cmd->use_sg > 1) - { - struct scatterlist *sg; - - sg = (struct scatterlist *)cmd->request_buffer; - pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction)); - } - else if (cmd->request_bufflen) - pci_unmap_single(p->pdev, aic7xxx_mapping(cmd), - cmd->request_bufflen, - scsi_to_pci_dma_dir(cmd->sc_data_direction)); - if (scb->flags & SCB_SENSE) - { - pci_unmap_single(p->pdev, - le32_to_cpu(scb->sg_list[0].address), - sizeof(cmd->sense_buffer), - PCI_DMA_FROMDEVICE); - } - if (scb->flags & SCB_RECOVERY_SCB) - { - p->flags &= ~AHC_ABORT_PENDING; - } - if (scb->flags & SCB_RESET) - { - cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); - } - else if (scb->flags & SCB_ABORT) - { - cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); - } - else if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) - { - if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) ) - { - char *buffer; - - p->dev_flags[tindex] |= DEVICE_PRESENT; - if(cmd->use_sg) - { - struct scatterlist *sg; - - sg = (struct scatterlist *)cmd->request_buffer; - buffer = (char *)sg[0].address; - } - else - { - buffer = (char *)cmd->request_buffer; - } -#define WIDE_INQUIRY_BITS 0x60 -#define SYNC_INQUIRY_BITS 0x10 -#define SCSI_VERSION_BITS 0x07 -#define SCSI_DT_BIT 0x04 - if ( (buffer[7] & WIDE_INQUIRY_BITS) && - (p->features & AHC_WIDE) ) - { - p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width = p->transinfo[tindex].user_width; - } - else - { - p->needwdtr &= ~(1<needwdtr_copy &= ~(1<target, cmd->channel, cmd->lun, - MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | - AHC_TRANS_GOAL | - AHC_TRANS_CUR) ); - unpause_sequencer(p, FALSE); - } - if ( (buffer[7] & SYNC_INQUIRY_BITS) && - p->transinfo[tindex].user_offset ) - { - p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; - if (p->features & AHC_ULTRA2) - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; - else - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; - if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) || - (buffer[56] & SCSI_DT_BIT) || - (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && - (p->transinfo[tindex].user_period <= 9) && - (p->transinfo[tindex].user_options) ) - { - p->needppr |= (1<needppr_copy |= (1<needsdtr &= ~(1<needsdtr_copy &= ~(1<needwdtr &= ~(1<needwdtr_copy &= ~(1<dev_flags[tindex] |= DEVICE_SCSI_3; - } - else - { - p->needsdtr |= (1<needsdtr_copy |= (1<transinfo[tindex].goal_period = - MAX(10, p->transinfo[tindex].goal_period); - p->transinfo[tindex].goal_options = 0; - } - } - else - { - p->needsdtr &= ~(1<needsdtr_copy &= ~(1<transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_options = 0; - } - /* - * This is needed to work around a sequencer bug for now. Regardless - * of the controller in use, if we have a Quantum drive, we need to - * limit the speed to 80MByte/sec. As soon as I get a fixed version - * of the sequencer, this code will get yanked. - */ - if(!strncmp(buffer + 8, "QUANTUM", 7) && - p->transinfo[tindex].goal_options ) - { - p->transinfo[tindex].goal_period = - MAX(p->transinfo[tindex].goal_period, 10); - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<needppr_copy &= ~(1<needsdtr |= (1<needsdtr_copy |= (1<needwdtr |= (1<needwdtr_copy |= (1<dev_dtr_cmnd[tindex] == cmd) { - unsigned int checksum = 0; - int *ibuffer; - int i=0; - - ibuffer = (int *)buffer; - for( i = 0; i < (cmd->request_bufflen >> 2); i++) - { - checksum += ibuffer[i]; - } - p->dev_checksum[tindex] = checksum; - p->dev_flags[tindex] |= DEVICE_SCANNED; - p->dev_flags[tindex] |= DEVICE_PRINT_DTR; - } -#undef WIDE_INQUIRY_BITS -#undef SYNC_INQUIRY_BITS -#undef SCSI_VERSION_BITS -#undef SCSI_DT_BIT - } - } - else if ((scb->flags & SCB_MSGOUT_BITS) != 0) - { - unsigned short mask; - int message_error = FALSE; - - mask = 0x01 << tindex; - - /* - * Check to see if we get an invalid message or a message error - * after failing to negotiate a wide or sync transfer message. - */ - if ((scb->flags & SCB_SENSE) && - ((scb->cmd->sense_buffer[12] == 0x43) || /* INVALID_MESSAGE */ - (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR */ - { - message_error = TRUE; - } - - if (scb->flags & SCB_MSGOUT_WDTR) - { - p->dtr_pending &= ~mask; - if (message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Wide Negotiation " - "processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no, - CTL_OF_SCB(scb)); - } - p->needwdtr &= ~mask; - p->needwdtr_copy &= ~mask; - } - } - if (scb->flags & SCB_MSGOUT_SDTR) - { - p->dtr_pending &= ~mask; - if (message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Sync Negotiation " - "processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no, - CTL_OF_SCB(scb)); - p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR; - } - p->needsdtr &= ~mask; - p->needsdtr_copy &= ~mask; - } - } - if (scb->flags & SCB_MSGOUT_PPR) - { - p->dtr_pending &= ~mask; - if(message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Parallel Protocol " - "Request processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Parallel Protocol Request negotiation to this " - "device.\n", p->host_no, CTL_OF_SCB(scb)); - } - /* - * Disable PPR negotiation and revert back to WDTR and SDTR setup - */ - p->needppr &= ~mask; - p->needppr_copy &= ~mask; - p->needsdtr |= mask; - p->needsdtr_copy |= mask; - p->needwdtr |= mask; - p->needwdtr_copy |= mask; - } - } - } - queue_depth = p->dev_temp_queue_depth[tindex]; - if (queue_depth >= p->dev_active_cmds[tindex]) - { - scbp = scbq_remove_head(&p->delayed_scbs[tindex]); - if (scbp) - { - if (queue_depth == 1) - { - /* - * Give extra preference to untagged devices, such as CD-R devices - * This makes it more likely that a drive *won't* stuff up while - * waiting on data at a critical time, such as CD-R writing and - * audio CD ripping operations. Should also benefit tape drives. - */ - scbq_insert_head(&p->waiting_scbs, scbp); - } - else - { - scbq_insert_tail(&p->waiting_scbs, scbp); - } -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n", - p->host_no, CTL_OF_SCB(scbp)); -#endif - if (queue_depth > p->dev_active_cmds[tindex]) - { - scbp = scbq_remove_head(&p->delayed_scbs[tindex]); - if (scbp) - scbq_insert_tail(&p->waiting_scbs, scbp); - } - } - } - if ( !(scb->tag_action) && (p->tagenable & (1<dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex]; - } - p->dev_active_cmds[tindex]--; - p->activescbs--; - - { - int actual; - - /* - * XXX: we should actually know how much actually transferred - * XXX: for each command, but apparently that's too difficult. - * - * We set a lower limit of 512 bytes on the transfer length. We - * ignore anything less than this because we don't have a real - * reason to count it. Read/Writes to tapes are usually about 20K - * and disks are a minimum of 512 bytes unless you want to count - * non-read/write commands (such as TEST_UNIT_READY) which we don't - */ - actual = scb->sg_length; - if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK)) - { - struct aic7xxx_xferstats *sp; -#ifdef AIC7XXX_PROC_STATS - long *ptr; - int x; -#endif /* AIC7XXX_PROC_STATS */ - - sp = &p->stats[TARGET_INDEX(cmd)]; - - /* - * For block devices, cmd->request.cmd is always == either READ or - * WRITE. For character devices, this isn't always set properly, so - * we check data_cmnd[0]. This catches the conditions for st.c, but - * I'm still not sure if request.cmd is valid for sg devices. - */ - if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) || - (cmd->data_cmnd[0] == WRITE_FILEMARKS) ) - { - sp->w_total++; -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if ( (sp->w_total > 16) && (aic7xxx_verbose > 0xffff) ) - aic7xxx_verbose &= 0xffff; -#endif -#ifdef AIC7XXX_PROC_STATS - ptr = sp->w_bins; -#endif /* AIC7XXX_PROC_STATS */ - } - else - { - sp->r_total++; -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if ( (sp->r_total > 16) && (aic7xxx_verbose > 0xffff) ) - aic7xxx_verbose &= 0xffff; -#endif -#ifdef AIC7XXX_PROC_STATS - ptr = sp->r_bins; -#endif /* AIC7XXX_PROC_STATS */ - } -#ifdef AIC7XXX_PROC_STATS - x = -11; - while(actual) - { - actual >>= 1; - x++; - } - if (x < 0) - { - ptr[0]++; - } - else if (x > 7) - { - ptr[7]++; - } - else - { - ptr[x]++; - } -#endif /* AIC7XXX_PROC_STATS */ - } - } - aic7xxx_free_scb(p, scb); - aic7xxx_queue_cmd_complete(p, cmd); - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_run_done_queue - * - * Description: - * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the - * aborted list, and adds each scb to the free list. If complete - * is TRUE, we also process the commands complete list. - *-F*************************************************************************/ -static void -aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete) -{ - struct aic7xxx_scb *scb; - int i, found = 0; - - for (i = 0; i < p->scb_data->numscbs; i++) - { - scb = p->scb_data->scb_array[i]; - if (scb->flags & SCB_QUEUED_FOR_DONE) - { - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Aborting scb %d\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag); - found++; - aic7xxx_done(p, scb); - } - } - if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN)) - { - printk(INFO_LEAD "%d commands found and queued for " - "completion.\n", p->host_no, -1, -1, -1, found); - } - if (complete) - { - aic7xxx_done_cmds_complete(p); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_abort_waiting_scb - * - * Description: - * Manipulate the waiting for selection list and return the - * scb that follows the one that we remove. - *-F*************************************************************************/ -static unsigned char -aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, - unsigned char scbpos, unsigned char prev) -{ - unsigned char curscb, next; - - /* - * Select the SCB we want to abort and pull the next pointer out of it. - */ - curscb = aic_inb(p, SCBPTR); - aic_outb(p, scbpos, SCBPTR); - next = aic_inb(p, SCB_NEXT); - - aic7xxx_add_curscb_to_free_list(p); - - /* - * Update the waiting list - */ - if (prev == SCB_LIST_NULL) - { - /* - * First in the list - */ - aic_outb(p, next, WAITING_SCBH); - } - else - { - /* - * Select the scb that pointed to us and update its next pointer. - */ - aic_outb(p, prev, SCBPTR); - aic_outb(p, next, SCB_NEXT); - } - /* - * Point us back at the original scb position and inform the SCSI - * system that the command has been aborted. - */ - aic_outb(p, curscb, SCBPTR); - return (next); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_search_qinfifo - * - * Description: - * Search the queue-in FIFO for matching SCBs and conditionally - * requeue. Returns the number of matching SCBs. - *-F*************************************************************************/ -static int -aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel, - int lun, unsigned char tag, int flags, int requeue, - volatile scb_queue_type *queue) -{ - int found; - unsigned char qinpos, qintail; - struct aic7xxx_scb *scbp; - - found = 0; - qinpos = aic_inb(p, QINPOS); - qintail = p->qinfifonext; - - p->qinfifonext = qinpos; - - while (qinpos != qintail) - { - scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - /* - * We found an scb that needs to be removed. - */ - if (requeue && (queue != NULL)) - { - if (scbp->flags & SCB_WAITINGQ) - { - scbq_remove(queue, scbp); - scbq_remove(&p->waiting_scbs, scbp); - scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp); - p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; - p->activescbs++; - } - scbq_insert_tail(queue, scbp); - p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--; - p->activescbs--; - scbp->flags |= SCB_WAITINGQ; - if ( !(scbp->tag_action & TAG_ENB) ) - { - aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - TRUE); - } - } - else if (requeue) - { - p->qinfifo[p->qinfifonext++] = scbp->hscb->tag; - } - else - { - /* - * Preserve any SCB_RECOVERY_SCB flags on this scb then set the - * flags we were called with, presumeably so aic7xxx_run_done_queue - * can find this scb - */ - scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB); - if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - FALSE) == scbp->hscb->tag) - { - aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - TRUE); - } - } - found++; - } - else - { - p->qinfifo[p->qinfifonext++] = scbp->hscb->tag; - } - } - /* - * Now that we've done the work, clear out any left over commands in the - * qinfifo and update the KERNEL_QINPOS down on the card. - * - * NOTE: This routine expect the sequencer to already be paused when - * it is run....make sure it's that way! - */ - qinpos = p->qinfifonext; - while(qinpos != qintail) - { - p->qinfifo[qinpos++] = SCB_LIST_NULL; - } - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - - return (found); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_scb_on_qoutfifo - * - * Description: - * Is the scb that was passed to us currently on the qoutfifo? - *-F*************************************************************************/ -static int -aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - int i=0; - - while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL) - { - if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag) - return TRUE; - else - i++; - } - return FALSE; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_device - * - * Description: - * The device at the given target/channel has been reset. Abort - * all active and queued scbs for that target/channel. This function - * need not worry about linked next pointers because if was a MSG_ABORT_TAG - * then we had a tagged command (no linked next), if it was MSG_ABORT or - * MSG_BUS_DEV_RESET then the device won't know about any commands any more - * and no busy commands will exist, and if it was a bus reset, then nothing - * knows about any linked next commands any more. In all cases, we don't - * need to worry about the linked next or busy scb, we just need to clear - * them. - *-F*************************************************************************/ -static void -aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, - int lun, unsigned char tag) -{ - struct aic7xxx_scb *scbp; - unsigned char active_scb, tcl; - int i = 0, j, init_lists = FALSE; - - /* - * Restore this when we're done - */ - active_scb = aic_inb(p, SCBPTR); - - if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) - printk(INFO_LEAD "Reset device, active_scb %d\n", - p->host_no, channel, target, lun, active_scb); - /* - * Deal with the busy target and linked next issues. - */ - { - int min_target, max_target; - struct aic7xxx_scb *scbp, *prev_scbp; - - /* Make all targets 'relative' to bus A. */ - if (target == ALL_TARGETS) - { - switch (channel) - { - case 0: - min_target = 0; - max_target = (p->features & AHC_WIDE) ? 15 : 7; - break; - case 1: - min_target = 8; - max_target = 15; - break; - case ALL_CHANNELS: - default: - min_target = 0; - max_target = (p->features & (AHC_TWIN|AHC_WIDE)) ? 15 : 7; - break; - } - } - else - { - min_target = target | (channel << 3); - max_target = min_target; - } - - - for (i = min_target; i <= max_target; i++) - { - if ( i == p->scsi_id ) - { - continue; - } - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning up status information " - "and delayed_scbs.\n", p->host_no, channel, i, lun); - p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR); - if ( tag == SCB_LIST_NULL ) - { - p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY; - p->dev_expires[i] = jiffies + (4 * HZ); - p->dev_timer_active |= (0x01 << i); - p->dev_last_queue_full_count[i] = 0; - p->dev_last_queue_full[i] = 0; - p->dev_temp_queue_depth[i] = - p->dev_max_queue_depth[i]; - } - for(j=0; jdelayed_scbs[i].head; - while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) ) - { - prev_scbp = scbp; - scbp = scbp->q_next; - if ( prev_scbp == scbp ) - { - if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) - printk(WARN_LEAD "Yikes!! scb->q_next == scb " - "in the delayed_scbs queue!\n", p->host_no, channel, i, lun); - scbp = NULL; - prev_scbp->q_next = NULL; - p->delayed_scbs[i].tail = prev_scbp; - } - if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) - { - scbq_remove(&p->delayed_scbs[i], prev_scbp); - if (prev_scbp->flags & SCB_WAITINGQ) - { - p->dev_active_cmds[i]++; - p->activescbs++; - } - prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - } - } - if ( j > (p->scb_data->maxscbs + 1) ) - { - if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) - printk(WARN_LEAD "Yikes!! There's a loop in the " - "delayed_scbs queue!\n", p->host_no, channel, i, lun); - scbq_init(&p->delayed_scbs[i]); - } - if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) || - time_after_eq(p->dev_timer.expires, p->dev_expires[i]) ) - { - mod_timer(&p->dev_timer, p->dev_expires[i]); - p->dev_timer_active |= (0x01 << MAX_TARGETS); - } - } - } - - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun ); - aic7xxx_search_qinfifo(p, target, channel, lun, tag, - SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL); - -/* - * Search the waiting_scbs queue for matches, this catches any SCB_QUEUED - * ABORT/RESET commands. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel, - target, lun ); - { - struct aic7xxx_scb *scbp, *prev_scbp; - - j = 0; - prev_scbp = NULL; - scbp = p->waiting_scbs.head; - while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) ) - { - prev_scbp = scbp; - scbp = scbp->q_next; - if ( prev_scbp == scbp ) - { - if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) - printk(WARN_LEAD "Yikes!! scb->q_next == scb " - "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp)); - scbp = NULL; - prev_scbp->q_next = NULL; - p->waiting_scbs.tail = prev_scbp; - } - if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) - { - scbq_remove(&p->waiting_scbs, prev_scbp); - if (prev_scbp->flags & SCB_WAITINGQ) - { - p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++; - p->activescbs++; - } - prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - } - } - if ( j > (p->scb_data->maxscbs + 1) ) - { - if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) - printk(WARN_LEAD "Yikes!! There's a loop in the " - "waiting_scbs queue!\n", p->host_no, channel, target, lun); - scbq_init(&p->waiting_scbs); - } - } - - - /* - * Search waiting for selection list. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning waiting for selection " - "list.\n", p->host_no, channel, target, lun); - { - unsigned char next, prev, scb_index; - - next = aic_inb(p, WAITING_SCBH); /* Start at head of list. */ - prev = SCB_LIST_NULL; - j = 0; - while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) ) - { - aic_outb(p, next, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index >= p->scb_data->numscbs) - { - /* - * No aic7xxx_verbose check here.....we want to see this since it - * means either the kernel driver or the sequencer screwed things up - */ - printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, " - "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, - p->scb_data->numscbs); - next = aic_inb(p, SCB_NEXT); - aic7xxx_add_curscb_to_free_list(p); - } - else - { - scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - next = aic7xxx_abort_waiting_scb(p, scbp, next, prev); - if (scbp->flags & SCB_WAITINGQ) - { - p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; - p->activescbs++; - } - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - if (prev == SCB_LIST_NULL) - { - /* - * This is either the first scb on the waiting list, or we - * have already yanked the first and haven't left any behind. - * Either way, we need to turn off the selection hardware if - * it isn't already off. - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - } - } - else - { - prev = next; - next = aic_inb(p, SCB_NEXT); - } - } - } - if ( j > (p->scb_data->maxscbs + 1) ) - { - printk(WARN_LEAD "Yikes!! There is a loop in the waiting for " - "selection list!\n", p->host_no, channel, target, lun); - init_lists = TRUE; - } - } - - /* - * Go through disconnected list and remove any entries we have queued - * for completion, zeroing their control byte too. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning disconnected scbs " - "list.\n", p->host_no, channel, target, lun); - if (p->flags & AHC_PAGESCBS) - { - unsigned char next, prev, scb_index; - - next = aic_inb(p, DISCONNECTED_SCBH); - prev = SCB_LIST_NULL; - j = 0; - while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) ) - { - aic_outb(p, next, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, " - "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, - p->scb_data->numscbs); - next = aic7xxx_rem_scb_from_disc_list(p, next, prev); - } - else - { - scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - next = aic7xxx_rem_scb_from_disc_list(p, next, prev); - if (scbp->flags & SCB_WAITINGQ) - { - p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; - p->activescbs++; - } - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - scbp->hscb->control = 0; - } - else - { - prev = next; - next = aic_inb(p, SCB_NEXT); - } - } - } - if ( j > (p->scb_data->maxscbs + 1) ) - { - printk(WARN_LEAD "Yikes!! There is a loop in the disconnected list!\n", - p->host_no, channel, target, lun); - init_lists = TRUE; - } - } - - /* - * Walk the free list making sure no entries on the free list have - * a valid SCB_TAG value or SCB_CONTROL byte. - */ - if (p->flags & AHC_PAGESCBS) - { - unsigned char next; - - j = 0; - next = aic_inb(p, FREE_SCBH); - if ( (next >= p->scb_data->maxhscbs) && (next != SCB_LIST_NULL) ) - { - printk(WARN_LEAD "Bogus FREE_SCBH!.\n", p->host_no, channel, - target, lun); - init_lists = TRUE; - next = SCB_LIST_NULL; - } - while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) ) - { - aic_outb(p, next, SCBPTR); - if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs) - { - printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel, - target, lun); - init_lists = TRUE; - next = SCB_LIST_NULL; - } - else - { - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - next = aic_inb(p, SCB_NEXT); - } - } - if ( j > (p->scb_data->maxscbs + 1) ) - { - printk(WARN_LEAD "Yikes!! There is a loop in the free list!\n", - p->host_no, channel, target, lun); - init_lists = TRUE; - } - } - - /* - * Go through the hardware SCB array looking for commands that - * were active but not on any list. - */ - if (init_lists) - { - aic_outb(p, SCB_LIST_NULL, FREE_SCBH); - aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); - aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH); - } - for (i = p->scb_data->maxhscbs - 1; i >= 0; i--) - { - unsigned char scbid; - - aic_outb(p, i, SCBPTR); - if (init_lists) - { - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, SCB_LIST_NULL, SCB_NEXT); - aic_outb(p, 0, SCB_CONTROL); - aic7xxx_add_curscb_to_free_list(p); - } - else - { - scbid = aic_inb(p, SCB_TAG); - if (scbid < p->scb_data->numscbs) - { - scbp = p->scb_data->scb_array[scbid]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - aic_outb(p, 0, SCB_CONTROL); - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic7xxx_add_curscb_to_free_list(p); - } - } - } - } - - /* - * Go through the entire SCB array now and look for commands for - * for this target that are stillactive. These are other (most likely - * tagged) commands that were disconnected when the reset occurred. - * Any commands we find here we know this about, it wasn't on any queue, - * it wasn't in the qinfifo, it wasn't in the disconnected or waiting - * lists, so it really must have been a paged out SCB. In that case, - * we shouldn't need to bother with updating any counters, just mark - * the correct flags and go on. - */ - for (i = 0; i < p->scb_data->numscbs; i++) - { - scbp = p->scb_data->scb_array[i]; - if ((scbp->flags & SCB_ACTIVE) && - aic7xxx_match_scb(p, scbp, target, channel, lun, tag) && - !aic7xxx_scb_on_qoutfifo(p, scbp)) - { - if (scbp->flags & SCB_WAITINGQ) - { - scbq_remove(&p->waiting_scbs, scbp); - scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp); - p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; - p->activescbs++; - } - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - } - } - - aic_outb(p, active_scb, SCBPTR); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_clear_intstat - * - * Description: - * Clears the interrupt status. - *-F*************************************************************************/ -static void -aic7xxx_clear_intstat(struct aic7xxx_host *p) -{ - /* Clear any interrupt conditions this may have caused. */ - aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0); - aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR | - CLRPHASECHG | CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT | CLRPARERR, CLRINT); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_current_bus - * - * Description: - * Reset the current SCSI bus. - *-F*************************************************************************/ -static void -aic7xxx_reset_current_bus(struct aic7xxx_host *p) -{ - - /* Disable reset interrupts. */ - aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1); - - /* Turn off the bus' current operations, after all, we shouldn't have any - * valid commands left to cause a RSELI and SELO once we've tossed the - * bus away with this reset, so we might as well shut down the sequencer - * until the bus is restarted as oppossed to saving the current settings - * and restoring them (which makes no sense to me). */ - - /* Turn on the bus reset. */ - aic_outb(p, aic_inb(p, SCSISEQ) | SCSIRSTO, SCSISEQ); - while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0) - mdelay(5); - - /* - * Some of the new Ultra2 chipsets need a longer delay after a chip - * reset than just the init setup creates, so we have to delay here - * before we go into a reset in order to make the chips happy. - */ - if (p->features & AHC_ULTRA2) - mdelay(250); - else - mdelay(50); - - /* Turn off the bus reset. */ - aic_outb(p, 0, SCSISEQ); - mdelay(10); - - aic7xxx_clear_intstat(p); - /* Re-enable reset interrupts. */ - aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1); - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_channel - * - * Description: - * Reset the channel. - *-F*************************************************************************/ -static void -aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset) -{ - unsigned long offset_min, offset_max; - unsigned char sblkctl; - int cur_channel; - - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Reset channel called, %s initiate reset.\n", - p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" ); - - - if (channel == 1) - { - p->needsdtr |= (p->needsdtr_copy & 0xFF00); - p->dtr_pending &= 0x00FF; - offset_min = 8; - offset_max = 16; - } - else - { - if (p->features & AHC_TWIN) - { - /* Channel A */ - p->needsdtr |= (p->needsdtr_copy & 0x00FF); - p->dtr_pending &= 0xFF00; - offset_min = 0; - offset_max = 8; - } - else - { - p->needppr = p->needppr_copy; - p->needsdtr = p->needsdtr_copy; - p->needwdtr = p->needwdtr_copy; - p->dtr_pending = 0x0; - offset_min = 0; - if (p->features & AHC_WIDE) - { - offset_max = 16; - } - else - { - offset_max = 8; - } - } - } - - while (offset_min < offset_max) - { - /* - * Revert to async/narrow transfers until we renegotiate. - */ - aic_outb(p, 0, TARG_SCSIRATE + offset_min); - if (p->features & AHC_ULTRA2) - { - aic_outb(p, 0, TARG_OFFSET + offset_min); - } - offset_min++; - } - - /* - * Reset the bus and unpause/restart the controller - */ - sblkctl = aic_inb(p, SBLKCTL); - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - cur_channel = (sblkctl & SELBUSB) >> 3; - else - cur_channel = 0; - if ( (cur_channel != channel) && (p->features & AHC_TWIN) ) - { - /* - * Case 1: Command for another bus is active - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no, - channel, -1, -1); - /* - * Stealthily reset the other bus without upsetting the current bus. - */ - aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL); - aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1); - if (initiate_reset) - { - aic7xxx_reset_current_bus(p); - } - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ); - aic7xxx_clear_intstat(p); - aic_outb(p, sblkctl, SBLKCTL); - } - else - { - /* - * Case 2: A command from this bus is active or we're idle. - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no, - channel, -1, -1); - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), - SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - p->msg_type = MSG_TYPE_NONE; - p->msg_len = 0; - if (initiate_reset) - { - aic7xxx_reset_current_bus(p); - } - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ); - aic7xxx_clear_intstat(p); - } - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1); - /* - * Clean up all the state information for the pending transactions - * on this bus. - */ - aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL); - - if ( !(p->features & AHC_TWIN) ) - { - restart_sequencer(p); - } - - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_run_waiting_queues - * - * Description: - * Scan the awaiting_scbs queue downloading and starting as many - * scbs as we can. - *-F*************************************************************************/ -static void -aic7xxx_run_waiting_queues(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scb; - int tindex; - int sent; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned long cpu_flags = 0; -#endif - - - if (p->waiting_scbs.head == NULL) - return; - - sent = 0; - - /* - * First handle SCBs that are waiting but have been assigned a slot. - */ - DRIVER_LOCK - while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL) - { - tindex = TARGET_INDEX(scb->cmd); - if ( !scb->tag_action && (p->tagenable & (1<dev_temp_queue_depth[tindex] = 1; - } - if ( (p->dev_active_cmds[tindex] >= - p->dev_temp_queue_depth[tindex]) || - (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) || - (p->flags & AHC_RESET_DELAY) ) - { - scbq_insert_tail(&p->delayed_scbs[tindex], scb); - } - else - { - scb->flags &= ~SCB_WAITINGQ; - p->dev_active_cmds[tindex]++; - p->activescbs++; - if ( !(scb->tag_action) ) - { - aic7xxx_busy_target(p, scb); - } - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - sent++; - } - } - if (sent) - { - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - { - pause_sequencer(p); - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - unpause_sequencer(p, FALSE); - } - if (p->activescbs > p->max_activescbs) - p->max_activescbs = p->activescbs; - } - DRIVER_UNLOCK -} - -#ifdef CONFIG_PCI - -#define DPE 0x80 -#define SSE 0x40 -#define RMA 0x20 -#define RTA 0x10 -#define STA 0x08 -#define DPR 0x01 - -/*+F************************************************************************* - * Function: - * aic7xxx_pci_intr - * - * Description: - * Check the scsi card for PCI errors and clear the interrupt - * - * NOTE: If you don't have this function and a 2940 card encounters - * a PCI error condition, the machine will end up locked as the - * interrupt handler gets slammed with non-stop PCI error interrupts - *-F*************************************************************************/ -static void -aic7xxx_pci_intr(struct aic7xxx_host *p) -{ - unsigned char status1; - - pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1); - - if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Data Parity Error during PCI address or PCI write" - "phase.\n", p->host_no, -1, -1, -1); - if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Signal System Error Detected\n", p->host_no, - -1, -1, -1); - if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Data Parity Error has been reported via PCI pin " - "PERR#\n", p->host_no, -1, -1, -1); - - pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1); - if (status1 & (DPR|RMA|RTA)) - aic_outb(p, CLRPARERR, CLRINT); - - if ( (aic7xxx_panic_on_abort) && (p->spurious_int > 500) ) - aic7xxx_panic_abort(p, NULL); - -} -#endif /* CONFIG_PCI */ - -/*+F************************************************************************* - * Function: - * aic7xxx_timer - * - * Description: - * Take expired extries off of delayed queues and place on waiting queue - * then run waiting queue to start commands. - ***************************************************************************/ -static void -aic7xxx_timer(struct aic7xxx_host *p) -{ - int i, j; - unsigned long cpu_flags = 0; - struct aic7xxx_scb *scb; - - spin_lock_irqsave(&io_request_lock, cpu_flags); - p->dev_timer_active &= ~(0x01 << MAX_TARGETS); - if ( (p->dev_timer_active & (0x01 << p->scsi_id)) && - time_after_eq(jiffies, p->dev_expires[p->scsi_id]) ) - { - p->flags &= ~AHC_RESET_DELAY; - p->dev_timer_active &= ~(0x01 << p->scsi_id); - } - for(i=0; iscsi_id) && - (p->dev_timer_active & (0x01 << i)) && - time_after_eq(jiffies, p->dev_expires[i]) ) - { - p->dev_timer_active &= ~(0x01 << i); - p->dev_flags[i] &= ~(DEVICE_RESET_DELAY|DEVICE_WAS_BUSY); - p->dev_temp_queue_depth[i] = p->dev_max_queue_depth[i]; - j = 0; - while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) && - (j++ < p->scb_data->numscbs) ) - { - scbq_insert_tail(&p->waiting_scbs, scb); - } - if (j == p->scb_data->numscbs) - { - printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n", - p->host_no, 0, i, -1); - scbq_init(&p->delayed_scbs[i]); - scbq_init(&p->waiting_scbs); - /* - * Well, things are screwed now, wait for a reset to clean the junk - * out. - */ - } - } - else if ( p->dev_timer_active & (0x01 << i) ) - { - if ( p->dev_timer_active & (0x01 << MAX_TARGETS) ) - { - if ( time_after_eq(p->dev_timer.expires, p->dev_expires[i]) ) - { - p->dev_timer.expires = p->dev_expires[i]; - } - } - else - { - p->dev_timer.expires = p->dev_expires[i]; - p->dev_timer_active |= (0x01 << MAX_TARGETS); - } - } - } - if ( p->dev_timer_active & (0x01 << MAX_TARGETS) ) - { - add_timer(&p->dev_timer); - } - - aic7xxx_run_waiting_queues(p); - spin_unlock_irqrestore(&io_request_lock, cpu_flags); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_ppr - * - * Description: - * Build up a Parallel Protocol Request message for use with SCSI-3 - * devices. - *-F*************************************************************************/ -static void -aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - int tindex = TARGET_INDEX(scb->cmd); - - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_PPR; - p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period; - p->msg_buf[p->msg_index++] = 0; - p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset; - p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width; - p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options; - p->msg_len += 8; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_sdtr - * - * Description: - * Constucts a synchronous data transfer message in the message - * buffer on the sequencer. - *-F*************************************************************************/ -static void -aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period, - unsigned char offset) -{ - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_SDTR; - p->msg_buf[p->msg_index++] = period; - p->msg_buf[p->msg_index++] = offset; - p->msg_len += 5; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_wdtr - * - * Description: - * Constucts a wide data transfer message in the message buffer - * on the sequencer. - *-F*************************************************************************/ -static void -aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width) -{ - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_WDTR; - p->msg_buf[p->msg_index++] = bus_width; - p->msg_len += 4; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_calc_residual - * - * Description: - * Calculate the residual data not yet transferred. - *-F*************************************************************************/ -static void -aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - struct aic7xxx_hwscb *hscb; - Scsi_Cmnd *cmd; - int actual, i; - - cmd = scb->cmd; - hscb = scb->hscb; - - /* - * Don't destroy valid residual information with - * residual coming from a check sense operation. - */ - if (((scb->hscb->control & DISCONNECTED) == 0) && - (scb->flags & SCB_SENSE) == 0) - { - /* - * We had an underflow. At this time, there's only - * one other driver that bothers to check for this, - * and cmd->underflow seems to be set rather half- - * heartedly in the higher-level SCSI code. - */ - actual = scb->sg_length; - for (i=1; i < hscb->residual_SG_segment_count; i++) - { - actual -= scb->sg_list[scb->sg_count - i].length; - } - actual -= (hscb->residual_data_count[2] << 16) | - (hscb->residual_data_count[1] << 8) | - hscb->residual_data_count[0]; - - if (actual < cmd->underflow) - { - if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) - printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG " - "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow, - (cmd->request.cmd == WRITE) ? "wrote" : "read", actual, - hscb->residual_SG_segment_count); - aic7xxx_error(cmd) = DID_RETRY_COMMAND; - aic7xxx_status(cmd) = hscb->target_status; - } - } - - /* - * Clean out the residual information in the SCB for the - * next consumer. - */ - hscb->residual_data_count[2] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_SG_segment_count = 0; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_device_reset - * - * Description: - * Interrupt handler for sequencer interrupts (SEQINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel) -{ - unsigned short targ_mask; - unsigned char tindex = target; - - tindex |= ((channel & 0x01) << 3); - - targ_mask = (0x01 << tindex); - /* - * Go back to async/narrow transfers and renegotiate. - */ - p->needppr |= (p->needppr_copy & targ_mask); - p->needsdtr |= (p->needsdtr_copy & targ_mask); - p->needwdtr |= (p->needwdtr_copy & targ_mask); - p->dtr_pending &= ~targ_mask; - aic_outb(p, 0, TARG_SCSIRATE + tindex); - if (p->features & AHC_ULTRA2) - aic_outb(p, 0, TARG_OFFSET + tindex); - aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL); - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel, - target, -1); - aic7xxx_run_done_queue(p, /*complete*/ TRUE); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_seqint - * - * Description: - * Interrupt handler for sequencer interrupts (SEQINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) -{ - struct aic7xxx_scb *scb; - unsigned short target_mask; - unsigned char target, lun, tindex; - unsigned char queue_flag = FALSE; - char channel; - - target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f); - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - tindex = target + (channel << 3); - lun = aic_inb(p, SAVED_TCL) & 0x07; - target_mask = (0x01 << tindex); - - /* - * Go ahead and clear the SEQINT now, that avoids any interrupt race - * conditions later on in case we enable some other interrupt. - */ - aic_outb(p, CLRSEQINT, CLRINT); - switch (intstat & SEQINT_MASK) - { - case NO_MATCH: - { - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), - SCSISEQ); - printk(WARN_LEAD "No active SCB for reconnecting target - Issuing " - "BUS DEVICE RESET.\n", p->host_no, channel, target, lun); - printk(WARN_LEAD " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n", - p->host_no, channel, target, lun, - aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1), - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - } - break; - - case SEND_REJECT: - { - if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) - printk(INFO_LEAD "Rejecting unknown message (0x%x) received from " - "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun, - aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS)); - } - break; - - case NO_IDENT: - { - /* - * The reconnecting target either did not send an identify - * message, or did, but we didn't find an SCB to match and - * before it could respond to our ATN/abort, it hit a dataphase. - * The only safe thing to do is to blow it away with a bus - * reset. - */ - if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID)) - printk(INFO_LEAD "Target did not send an IDENTIFY message; " - "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target, - lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL)); - - aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE); - aic7xxx_run_done_queue(p, TRUE); - - } - break; - - case BAD_PHASE: - if (aic_inb(p, LASTPHASE) == P_BUSFREE) - { - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel, - target, lun); - restart_sequencer(p); - } - else - { - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no, - channel, target, lun); - } - break; - - case EXTENDED_MSG: - { - p->msg_type = MSG_TYPE_INITIATOR_MSGIN; - p->msg_len = 0; - p->msg_index = 0; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Enabling REQINITs for MSG_IN\n", p->host_no, - channel, target, lun); -#endif - - /* - * To actually receive the message, simply turn on - * REQINIT interrupts and let our interrupt handler - * do the rest (REQINIT should already be true). - */ - p->flags |= AHC_HANDLING_REQINITS; - aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1); - - /* - * We don't want the sequencer unpaused yet so we return early - */ - return; - } - - case REJECT_MSG: - { - /* - * What we care about here is if we had an outstanding SDTR - * or WDTR message for this target. If we did, this is a - * signal that the target is refusing negotiation. - */ - unsigned char scb_index; - unsigned char last_msg; - - scb_index = aic_inb(p, SCB_TAG); - scb = p->scb_data->scb_array[scb_index]; - last_msg = aic_inb(p, LAST_MSG); - - if ( (last_msg == MSG_IDENTIFYFLAG) && - (scb->tag_action) && - !(scb->flags & SCB_MSGOUT_BITS) ) - { - if (scb->tag_action == MSG_ORDERED_Q_TAG) - { - /* - * OK...the device seems able to accept tagged commands, but - * not ordered tag commands, only simple tag commands. So, we - * disable ordered tag commands and go on with life just like - * normal. - */ - p->orderedtag &= ~target_mask; - scb->tag_action = MSG_SIMPLE_Q_TAG; - scb->hscb->control &= ~SCB_TAG_TYPE; - scb->hscb->control |= MSG_SIMPLE_Q_TAG; - aic_outb(p, scb->hscb->control, SCB_CONTROL); - /* - * OK..we set the tag type to simple tag command, now we re-assert - * ATNO and hope this will take us into the identify phase again - * so we can resend the tag type and info to the device. - */ - aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - else if (scb->tag_action == MSG_SIMPLE_Q_TAG) - { - unsigned char i, reset = 0; - struct aic7xxx_scb *scbp; - int old_verbose; - /* - * Hmmmm....the device is flaking out on tagged commands. The - * bad thing is that we already have tagged commands enabled in - * the device struct in the mid level code. We also have a queue - * set according to the tagged queue depth. Gonna have to live - * with it by controlling our queue depth internally and making - * sure we don't set the tagged command flag any more. - */ - p->tagenable &= ~target_mask; - p->orderedtag &= ~target_mask; - p->dev_max_queue_depth[tindex] = - p->dev_temp_queue_depth[tindex] = 1; - /* - * We set this command up as a bus device reset. However, we have - * to clear the tag type as it's causing us problems. We shouldnt - * have to worry about any other commands being active, since if - * the device is refusing tagged commands, this should be the - * first tagged command sent to the device, however, we do have - * to worry about any other tagged commands that may already be - * in the qinfifo. The easiest way to do this, is to issue a BDR, - * send all the commands back to the mid level code, then let them - * come back and get rebuilt as untagged commands. - */ - scb->tag_action = 0; - scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE); - aic_outb(p, scb->hscb->control, SCB_CONTROL); - - old_verbose = aic7xxx_verbose; - aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT); - for (i=0; i!=p->scb_data->numscbs; i++) - { - scbp = p->scb_data->scb_array[i]; - if ((scbp->flags & SCB_ACTIVE) && (scbp != scb)) - { - if (aic7xxx_match_scb(p, scbp, target, channel, lun, i)) - { - aic7xxx_reset_device(p, target, channel, lun, i); - reset++; - } - aic7xxx_run_done_queue(p, TRUE); - } - } - aic7xxx_verbose = old_verbose; - /* - * Wait until after the for loop to set the busy index since - * aic7xxx_reset_device will clear the busy index during its - * operation. - */ - aic7xxx_busy_target(p, scb); - printk(INFO_LEAD "Device is refusing tagged commands, using " - "untagged I/O.\n", p->host_no, channel, target, lun); - aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - } - else if (scb->flags & SCB_MSGOUT_PPR) - { - /* - * As per the draft specs, any device capable of supporting any of - * the option values other than 0 are not allowed to reject the - * PPR message. Instead, they must negotiate out what they do - * support instead of rejecting our offering or else they cause - * a parity error during msg_out phase to signal that they don't - * like our settings. - */ - p->needppr &= ~target_mask; - p->needppr_copy &= ~target_mask; - aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE)); - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); - p->transinfo[tindex].goal_options = 0; - p->dtr_pending &= ~target_mask; - scb->flags &= ~SCB_MSGOUT_BITS; - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting PPR messages, falling " - "back.\n", p->host_no, channel, target, lun); - } - if ( p->transinfo[tindex].goal_width ) - { - p->needwdtr |= target_mask; - p->needwdtr_copy |= target_mask; - p->dtr_pending |= target_mask; - scb->flags |= SCB_MSGOUT_WDTR; - } - if ( p->transinfo[tindex].goal_offset ) - { - p->needsdtr |= target_mask; - p->needsdtr_copy |= target_mask; - if( !(p->dtr_pending & target_mask) ) - { - p->dtr_pending |= target_mask; - scb->flags |= SCB_MSGOUT_SDTR; - } - } - if ( p->dtr_pending & target_mask ) - { - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - } - else if (scb->flags & SCB_MSGOUT_WDTR) - { - /* - * note 8bit xfers and clear flag - */ - p->needwdtr &= ~target_mask; - p->needwdtr_copy &= ~target_mask; - p->dtr_pending &= ~target_mask; - scb->flags &= ~SCB_MSGOUT_BITS; - aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR)); - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting WDTR messages, using " - "narrow transfers.\n", p->host_no, channel, target, lun); - } - p->needsdtr |= (p->needsdtr_copy & target_mask); - } - else if (scb->flags & SCB_MSGOUT_SDTR) - { - /* - * note asynch xfers and clear flag - */ - p->needsdtr &= ~target_mask; - p->needsdtr_copy &= ~target_mask; - p->dtr_pending &= ~target_mask; - scb->flags &= ~SCB_MSGOUT_SDTR; - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL)); - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting SDTR messages, using " - "async transfers.\n", p->host_no, channel, target, lun); - } - } - else if (aic7xxx_verbose & VERBOSE_SEQINT) - { - /* - * Otherwise, we ignore it. - */ - printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause. " - "Ignoring.\n", p->host_no, channel, target, lun); - } - } - break; - - case BAD_STATUS: - { - unsigned char scb_index; - struct aic7xxx_hwscb *hscb; - Scsi_Cmnd *cmd; - - /* The sequencer will notify us when a command has an error that - * would be of interest to the kernel. This allows us to leave - * the sequencer running in the common case of command completes - * without error. The sequencer will have DMA'd the SCB back - * up to us, so we can reference the drivers SCB array. - * - * Set the default return value to 0 indicating not to send - * sense. The sense code will change this if needed and this - * reduces code duplication. - */ - aic_outb(p, 0, RETURN_1); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n", - p->host_no, channel, target, lun, intstat, scb_index); - break; - } - scb = p->scb_data->scb_array[scb_index]; - hscb = scb->hscb; - - if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x," - " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat, - scb_index, scb->flags, (unsigned long) scb->cmd); - } - else - { - cmd = scb->cmd; - hscb->target_status = aic_inb(p, SCB_TARGET_STATUS); - aic7xxx_status(cmd) = hscb->target_status; - - cmd->result = hscb->target_status; - - switch (status_byte(hscb->target_status)) - { - case GOOD: - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Interrupted for status of GOOD???\n", - p->host_no, CTL_OF_SCB(scb)); - break; - - case COMMAND_TERMINATED: - case CHECK_CONDITION: - if ( !(scb->flags & SCB_SENSE) ) - { - /* - * Send a sense command to the requesting target. - * XXX - revisit this and get rid of the memcopys. - */ - memcpy(scb->sense_cmd, &generic_sense[0], - sizeof(generic_sense)); - - scb->sense_cmd[1] = (cmd->lun << 5); - scb->sense_cmd[4] = sizeof(cmd->sense_buffer); - - scb->sg_list[0].length = - cpu_to_le32(sizeof(cmd->sense_buffer)); - scb->sg_list[0].address = - cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer, - sizeof(cmd->sense_buffer), - PCI_DMA_FROMDEVICE)); - - /* - * XXX - We should allow disconnection, but can't as it - * might allow overlapped tagged commands. - */ - /* hscb->control &= DISCENB; */ - hscb->control = 0; - hscb->target_status = 0; - hscb->SG_list_pointer = - cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list)); - hscb->SCSI_cmd_pointer = - cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd)); - hscb->data_count = scb->sg_list[0].length; - hscb->data_pointer = scb->sg_list[0].address; - hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]); - hscb->residual_SG_segment_count = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[2] = 0; - - scb->sg_count = hscb->SG_segment_count = 1; - scb->sg_length = sizeof(cmd->sense_buffer); - scb->tag_action = 0; - scb->flags |= SCB_SENSE; - /* - * Ensure the target is busy since this will be an - * an untagged request. - */ -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - if (scb->flags & SCB_MSGOUT_BITS) - printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no, - CTL_OF_SCB(scb), (scb->flags & SCB_MSGOUT_SDTR) ? - "SDTR" : "WDTR"); - else - printk(INFO_LEAD "Requesting SENSE, no MSG\n", p->host_no, - CTL_OF_SCB(scb)); - } -#endif - aic7xxx_busy_target(p, scb); - aic_outb(p, SEND_SENSE, RETURN_1); - aic7xxx_error(cmd) = DID_OK; - break; - } /* first time sense, no errors */ - aic7xxx_error(cmd) = DID_ERROR; - scb->flags &= ~SCB_SENSE; - break; - - case QUEUE_FULL: - queue_flag = TRUE; /* Mark that this is a QUEUE_FULL and */ - case BUSY: /* drop through to here */ - { - struct aic7xxx_scb *next_scbp, *prev_scbp; - unsigned char active_hscb, next_hscb, prev_hscb, scb_index; - /* - * We have to look three places for queued commands: - * 1: QINFIFO - * 2: p->waiting_scbs queue - * 3: WAITING_SCBS list on card (for commands that are started - * but haven't yet made it to the device) - */ - aic7xxx_search_qinfifo(p, target, channel, lun, - SCB_LIST_NULL, 0, TRUE, - &p->delayed_scbs[tindex]); - next_scbp = p->waiting_scbs.head; - while ( next_scbp != NULL ) - { - prev_scbp = next_scbp; - next_scbp = next_scbp->q_next; - if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun, - SCB_LIST_NULL) ) - { - scbq_remove(&p->waiting_scbs, prev_scbp); - scbq_insert_tail(&p->delayed_scbs[tindex], - prev_scbp); - } - } - next_scbp = NULL; - active_hscb = aic_inb(p, SCBPTR); - prev_hscb = next_hscb = scb_index = SCB_LIST_NULL; - next_hscb = aic_inb(p, WAITING_SCBH); - while (next_hscb != SCB_LIST_NULL) - { - aic_outb(p, next_hscb, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index < p->scb_data->numscbs) - { - next_scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, next_scbp, target, channel, lun, - SCB_LIST_NULL) ) - { - if (next_scbp->flags & SCB_WAITINGQ) - { - p->dev_active_cmds[tindex]++; - p->activescbs--; - scbq_remove(&p->delayed_scbs[tindex], next_scbp); - scbq_remove(&p->waiting_scbs, next_scbp); - } - scbq_insert_head(&p->delayed_scbs[tindex], - next_scbp); - next_scbp->flags |= SCB_WAITINGQ; - p->dev_active_cmds[tindex]--; - p->activescbs--; - next_hscb = aic_inb(p, SCB_NEXT); - aic_outb(p, 0, SCB_CONTROL); - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic7xxx_add_curscb_to_free_list(p); - if (prev_hscb == SCB_LIST_NULL) - { - /* We were first on the list, - * so we kill the selection - * hardware. Let the sequencer - * re-init the hardware itself - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - aic_outb(p, next_hscb, WAITING_SCBH); - } - else - { - aic_outb(p, prev_hscb, SCBPTR); - aic_outb(p, next_hscb, SCB_NEXT); - } - } - else - { - prev_hscb = next_hscb; - next_hscb = aic_inb(p, SCB_NEXT); - } - } /* scb_index >= p->scb_data->numscbs */ - } - aic_outb(p, active_hscb, SCBPTR); - if (scb->flags & SCB_WAITINGQ) - { - scbq_remove(&p->delayed_scbs[tindex], scb); - scbq_remove(&p->waiting_scbs, scb); - p->dev_active_cmds[tindex]++; - p->activescbs++; - } - scbq_insert_head(&p->delayed_scbs[tindex], scb); - p->dev_active_cmds[tindex]--; - p->activescbs--; - scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY; - - if ( !(p->dev_timer_active & (0x01 << tindex)) ) - { - p->dev_timer_active |= (0x01 << tindex); - if ( p->dev_active_cmds[tindex] ) - { - p->dev_expires[tindex] = jiffies + HZ; - } - else - { - p->dev_expires[tindex] = jiffies + (HZ / 10); - } - if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ) - { - p->dev_timer.expires = p->dev_expires[tindex]; - p->dev_timer_active |= (0x01 << MAX_TARGETS); - add_timer(&p->dev_timer); - } - else if ( time_after_eq(p->dev_timer.expires, - p->dev_expires[tindex]) ) - mod_timer(&p->dev_timer, p->dev_expires[tindex]); - } -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) || - (aic7xxx_verbose > 0xffff) ) - { - if (queue_flag) - printk(INFO_LEAD "Queue full received; queue depth %d, " - "active %d\n", p->host_no, CTL_OF_SCB(scb), - p->dev_max_queue_depth[tindex], - p->dev_active_cmds[tindex]); - else - printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb)); - - } -#endif - if (queue_flag) - { - if ( p->dev_last_queue_full[tindex] != - p->dev_active_cmds[tindex] ) - { - p->dev_last_queue_full[tindex] = - p->dev_active_cmds[tindex]; - p->dev_last_queue_full_count[tindex] = 0; - } - else - { - p->dev_last_queue_full_count[tindex]++; - } - if ( (p->dev_last_queue_full_count[tindex] > 14) && - (p->dev_active_cmds[tindex] > 4) ) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no, - CTL_OF_SCB(scb), p->dev_active_cmds[tindex]); - p->dev_max_queue_depth[tindex] = - p->dev_active_cmds[tindex]; - p->dev_last_queue_full[tindex] = 0; - p->dev_last_queue_full_count[tindex] = 0; - p->dev_temp_queue_depth[tindex] = - p->dev_active_cmds[tindex]; - } - else if (p->dev_active_cmds[tindex] == 0) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION) - { - printk(INFO_LEAD "QUEUE_FULL status received with 0 " - "commands active.\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Tagged Command Queueing disabled\n", - p->host_no, CTL_OF_SCB(scb)); - } - p->dev_max_queue_depth[tindex] = 1; - p->dev_temp_queue_depth[tindex] = 1; - scb->tag_action = 0; - scb->hscb->control &= ~(MSG_ORDERED_Q_TAG|MSG_SIMPLE_Q_TAG); - } - else - { - p->dev_flags[tindex] |= DEVICE_WAS_BUSY; - p->dev_temp_queue_depth[tindex] = - p->dev_active_cmds[tindex]; - } - } - break; - } - - default: - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no, - CTL_OF_SCB(scb), scb->hscb->target_status); - if (!aic7xxx_error(cmd)) - { - aic7xxx_error(cmd) = DID_RETRY_COMMAND; - } - break; - } /* end switch */ - } /* end else of */ - } - break; - - case AWAITING_MSG: - { - unsigned char scb_index, msg_out; - - scb_index = aic_inb(p, SCB_TAG); - msg_out = aic_inb(p, MSG_OUT); - scb = p->scb_data->scb_array[scb_index]; - p->msg_index = p->msg_len = 0; - /* - * This SCB had a MK_MESSAGE set in its control byte informing - * the sequencer that we wanted to send a special message to - * this target. - */ - - if ( !(scb->flags & SCB_DEVICE_RESET) && - (msg_out == MSG_IDENTIFYFLAG) && - (scb->hscb->control & TAG_ENB) ) - { - p->msg_buf[p->msg_index++] = scb->tag_action; - p->msg_buf[p->msg_index++] = scb->hscb->tag; - p->msg_len += 2; - } - - if (scb->flags & SCB_DEVICE_RESET) - { - p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET; - p->msg_len++; - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Bus device reset mailed.\n", - p->host_no, CTL_OF_SCB(scb)); - } - else if (scb->flags & SCB_ABORT) - { - if (scb->tag_action) - { - p->msg_buf[p->msg_index++] = MSG_ABORT_TAG; - } - else - { - p->msg_buf[p->msg_index++] = MSG_ABORT; - } - p->msg_len++; - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "Abort message mailed.\n", p->host_no, - CTL_OF_SCB(scb)); - } - else if (scb->flags & SCB_MSGOUT_PPR) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n", - p->host_no, CTL_OF_SCB(scb), - p->transinfo[tindex].goal_period, - p->transinfo[tindex].goal_offset, - p->transinfo[tindex].goal_width, - p->transinfo[tindex].goal_options); - } - aic7xxx_construct_ppr(p, scb); - } - else if (scb->flags & SCB_MSGOUT_WDTR) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending WDTR message.\n", p->host_no, - CTL_OF_SCB(scb)); - } - aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width); - } - else if (scb->flags & SCB_MSGOUT_SDTR) - { - unsigned int max_sync, period; - unsigned char options = 0; - /* - * Now that the device is selected, use the bits in SBLKCTL and - * SSTAT2 to determine the max sync rate for this device. - */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - max_sync = AHC_SYNCRATE_ULTRA2; - } - else - { - max_sync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - max_sync = AHC_SYNCRATE_ULTRA; - } - else - { - max_sync = AHC_SYNCRATE_FAST; - } - period = p->transinfo[tindex].goal_period; - aic7xxx_find_syncrate(p, &period, max_sync, &options); - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no, - CTL_OF_SCB(scb), period, - p->transinfo[tindex].goal_offset); - } - aic7xxx_construct_sdtr(p, period, - p->transinfo[tindex].goal_offset); - } - else - { - sti(); - panic("aic7xxx: AWAITING_MSG for an SCB that does " - "not have a waiting message.\n"); - } - /* - * We've set everything up to send our message, now to actually do - * so we need to enable reqinit interrupts and let the interrupt - * handler do the rest. We don't want to unpause the sequencer yet - * though so we'll return early. We also have to make sure that - * we clear the SEQINT *BEFORE* we set the REQINIT handler active - * or else it's possible on VLB cards to loose the first REQINIT - * interrupt. Edge triggered EISA cards could also loose this - * interrupt, although PCI and level triggered cards should not - * have this problem since they continually interrupt the kernel - * until we take care of the situation. - */ - scb->flags |= SCB_MSGOUT_SENT; - p->msg_index = 0; - p->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - p->flags |= AHC_HANDLING_REQINITS; - aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1); - return; - } - break; - - case DATA_OVERRUN: - { - unsigned char scb_index = aic_inb(p, SCB_TAG); - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned int i; - - scb = (p->scb_data->scb_array[scb_index]); - /* - * XXX - What do we really want to do on an overrun? The - * mid-level SCSI code should handle this, but for now, - * we'll just indicate that the command should retried. - * If we retrieved sense info on this target, then the - * base SENSE info should have been saved prior to the - * overrun error. In that case, we return DID_OK and let - * the mid level code pick up on the sense info. Otherwise - * we return DID_ERROR so the command will get retried. - */ - if ( !(scb->flags & SCB_SENSE) ) - { - printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n", - p->host_no, CTL_OF_SCB(scb), - (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag); - printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n", - (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't", - scb->sg_length, scb->sg_count); - for (i = 0; i < scb->sg_count; i++) - { - printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", - i, - le32_to_cpu(scb->sg_list[i].address), - le32_to_cpu(scb->sg_list[i].length) ); - } - aic7xxx_error(scb->cmd) = DID_ERROR; - } - else - printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n", - p->host_no, CTL_OF_SCB(scb)); - } - break; - - case WIDE_RESIDUE: - { - unsigned char resid_sgcnt, index; - unsigned char scb_index = aic_inb(p, SCB_TAG); - unsigned int cur_addr, resid_dcnt; - unsigned int native_addr, native_length; - int i; - - if(scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n", - p->host_no, -1, -1, -1); - /* - * XXX: Add error handling here - */ - break; - } - scb = p->scb_data->scb_array[scb_index]; - if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x " - "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb), - scb->flags, (unsigned long)scb->cmd); - break; - } - - /* - * We have a valid scb to use on this WIDE_RESIDUE message, so - * we need to walk the sg list looking for this particular sg - * segment, then see if we happen to be at the very beginning of - * the segment. If we are, then we have to back things up to - * the previous segment. If not, then we simply need to remove - * one byte from this segments address and add one to the byte - * count. - */ - cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) | - (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24); - resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT); - resid_dcnt = aic_inb(p, SCB_RESID_DCNT) | - (aic_inb(p, SCB_RESID_DCNT + 1) << 8) | - (aic_inb(p, SCB_RESID_DCNT + 2) << 16); - index = scb->sg_count - (resid_sgcnt + 1); - native_addr = le32_to_cpu(scb->sg_list[index].address); - native_length = le32_to_cpu(scb->sg_list[index].length); - /* - * Make sure this is a valid sg_seg for the given pointer - */ - if(cur_addr < native_addr || - cur_addr > (native_addr + native_length + 1)) - { - printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n", - p->host_no, CTL_OF_SCB(scb), cur_addr); - if(index > 0) - printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n", - p->host_no, CTL_OF_SCB(scb), - le32_to_cpu(scb->sg_list[index - 1].address), - le32_to_cpu(scb->sg_list[index - 1].length)); - printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n", - p->host_no, CTL_OF_SCB(scb), - native_addr, native_length); - if(resid_sgcnt > 1) - printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n", - p->host_no, CTL_OF_SCB(scb), - le32_to_cpu(scb->sg_list[index + 1].address), - le32_to_cpu(scb->sg_list[index + 1].length)); - printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n", - p->host_no, CTL_OF_SCB(scb), - cur_addr, resid_dcnt); - break; - } - - if( (resid_sgcnt == 0) && - ((resid_dcnt == 0) || (resid_dcnt == 0xffffff))) - { - /* - * We are at the end of the transfer and this is about a byte - * we ignored already (because the sequencer knew this was - * the last segment and set the adapter to ignore any wide - * residue bytes that might come through, which is only done - * on the last scatter gather segment of transfers). - */ - break; - } - else if(cur_addr == native_addr) - { - /* - * If our current address matches the sg_seg->address then we - * have to back up the sg array to the previous segment and set - * it up to have only one byte of transfer left to go. - */ - if(index == 0) - { - printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been " - "transferred.\n", p->host_no, CTL_OF_SCB(scb)); - break; - } - resid_sgcnt++; - index--; - cur_addr = le32_to_cpu(scb->sg_list[index].address) + - le32_to_cpu(scb->sg_list[index].length) - 1; - native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8) - | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24); - native_addr -= SG_SIZEOF; - aic_outb(p, resid_sgcnt, SG_COUNT); - aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); - aic_outb(p, native_addr & 0xff, SG_NEXT); - aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1); - aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2); - aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3); - aic_outb(p, 1, SCB_RESID_DCNT); - aic_outb(p, 0, SCB_RESID_DCNT + 1); - aic_outb(p, 0, SCB_RESID_DCNT + 2); - aic_outb(p, 1, HCNT); - aic_outb(p, 0, HCNT + 1); - aic_outb(p, 0, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); - } - else - { - /* - * Back the data pointer up by one and add one to the remaining - * byte count. Then store that in the HCNT and HADDR registers. - */ - cur_addr--; - resid_dcnt++; - aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); - aic_outb(p, resid_dcnt & 0xff, HCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); - } - /* - * The sequencer actually wants to find the new address and byte - * count in the SHCNT and SHADDR register sets. These registers - * are a shadow of the regular HCNT and HADDR registers. On the - * Ultra2 controllers, these registers are read only and the way - * we have to set their values is to put the values we want into - * the HCNT and HADDR registers and then output PRELOADEN into - * the DFCNTRL register which causes the card to latch the current - * values in the HADDR and HCNT registers and drop it through to - * the shadow registers. On older cards we copy them directly - * across by hand. - */ - if(p->features & AHC_ULTRA2) - { - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - i=0; - udelay(1); - while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000)) - { - udelay(1); - } - aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL); - i=0; - udelay(1); - while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000)) - { - udelay(1); - } - } - else - { - aic_outb(p, resid_dcnt & 0xff, STCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); - aic_outb(p, cur_addr & 0xff, SHADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3); - } - } - break; - - -#if AIC7XXX_NOT_YET - case TRACEPOINT: - { - printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, - channel, target, lun); - } - break; - - case TRACEPOINT2: - { - printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, - channel, target, lun); - } - break; - - /* XXX Fill these in later */ - case MSG_BUFFER_BUSY: - printk("aic7xxx: Message buffer busy.\n"); - break; - case MSGIN_PHASEMIS: - printk("aic7xxx: Message-in phasemis.\n"); - break; -#endif - - default: /* unknown */ - printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n", - p->host_no, channel, target, lun, intstat, - aic_inb(p, SCSISIGI)); - break; - } - - /* - * Clear the sequencer interrupt and unpause the sequencer. - */ - unpause_sequencer(p, /* unpause always */ TRUE); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_parse_msg - * - * Description: - * Parses incoming messages into actions on behalf of - * aic7xxx_handle_reqinit - *_F*************************************************************************/ -static int -aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - int reject, reply, done; - unsigned char target_scsirate, tindex; - unsigned short target_mask; - unsigned char target, channel, lun; - - target = scb->cmd->target; - channel = scb->cmd->channel; - lun = scb->cmd->lun; - reply = reject = done = FALSE; - tindex = TARGET_INDEX(scb->cmd); - target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - target_mask = (0x01 << tindex); - - /* - * Parse as much of the message as is availible, - * rejecting it if we don't support it. When - * the entire message is availible and has been - * handled, return TRUE indicating that we have - * parsed an entire message. - */ - - if (p->msg_buf[0] != MSG_EXTENDED) - { - reject = TRUE; - } - - /* - * Just accept the length byte outright and perform - * more checking once we know the message type. - */ - - if ( !reject && (p->msg_len > 2) ) - { - switch(p->msg_buf[2]) - { - case MSG_EXT_SDTR: - { - unsigned int period, offset; - unsigned char maxsync, saved_offset, options; - struct aic7xxx_syncrate *syncrate; - - if (p->msg_buf[1] != MSG_EXT_SDTR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_SDTR_LEN + 2)) - { - break; - } - - period = p->msg_buf[3]; - saved_offset = offset = p->msg_buf[4]; - options = 0; - - /* - * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when - * using the SDTR messages. We need the PPR messages to enable the - * higher speeds that include things like Dual Edge clocking. - */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - maxsync = AHC_SYNCRATE_ULTRA2; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - maxsync = AHC_SYNCRATE_ULTRA; - } - else - { - maxsync = AHC_SYNCRATE_FAST; - } - /* - * We might have a device that is starting negotiation with us - * before we can start up negotiation with it....be prepared to - * have a device ask for a higher speed then we want to give it - * in that case - */ - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) - { - if (!(p->dev_flags[tindex] & DEVICE_SCANNED) && - !(p->needsdtr_copy & target_mask) && - (p->transinfo[tindex].user_offset) ) - { - /* - * Not only is the device starting this up, but it also hasn't - * been scanned yet, so this would likely be our TUR or our - * INQUIRY command at scan time, so we need to use the - * settings from the SEEPROM if they existed. Of course, even - * if we didn't find a SEEPROM, we stuffed default values into - * the user settings anyway, so use those in all cases. - */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - if(p->features & AHC_ULTRA2) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - } - else if (p->transinfo[tindex].cur_width) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; - } - else - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; - } - p->needsdtr_copy |= target_mask; - } - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive SDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - if ( !p->transinfo[tindex].goal_offset ) - period = 255; - if ( p->transinfo[tindex].goal_period > period ) - period = p->transinfo[tindex].goal_period; - } - - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options); - aic7xxx_validate_offset(p, syncrate, &offset, - target_scsirate & WIDEXFER); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - - /* - * Did we drop to async? Or are we sending a reply? If we are, - * then we have to make sure that the reply value reflects the proper - * settings so we need to set the goal values according to what - * we need to send. - */ - if ( (offset != saved_offset) || - ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) ) - { - aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset, - options, AHC_TRANS_GOAL|AHC_TRANS_QUITE); - } - - /* - * Did we start this, if not, or if we went to low and had to - * go async, then send an SDTR back to the target - */ - p->needsdtr &= ~target_mask; - p->dtr_pending &= ~target_mask; - if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) || - (offset != saved_offset) ) - { - reply = TRUE; - p->dtr_pending |= target_mask; - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_SDTR; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } - done = TRUE; - break; - } - case MSG_EXT_WDTR: - { - unsigned char bus_width; - - if (p->msg_buf[1] != MSG_EXT_WDTR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_WDTR_LEN + 2)) - { - break; - } - - bus_width = p->msg_buf[3]; - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) == - (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) ) - { - switch(bus_width) - { - default: - { - reject = TRUE; - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - p->needwdtr_copy &= ~target_mask; - break; - } - case MSG_EXT_WDTR_BUS_16_BIT: - { - break; - } - } - p->dtr_pending &= ~target_mask; - p->needwdtr &= ~target_mask; - } - else - { - if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) ) - { - /* - * Well, we now know the WDTR and SYNC caps of this device since - * it contacted us first, mark it as such and copy the user stuff - * over to the goal stuff. - */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - if(p->transinfo[tindex].user_offset) - { - if(p->features & AHC_ULTRA2) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - } - else if( p->transinfo[tindex].user_width && - (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE ) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; - } - else - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; - } - } - p->transinfo[tindex].goal_width = - p->transinfo[tindex].user_width; - p->needwdtr_copy |= target_mask; - p->needsdtr_copy |= target_mask; - } - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive WDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - switch(bus_width) - { - default: - { - if ( (p->features & AHC_WIDE) && - (p->transinfo[tindex].goal_width == - MSG_EXT_WDTR_BUS_16_BIT) ) - { - bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - } /* Fall through if we aren't a wide card */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - p->needwdtr_copy &= ~target_mask; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); - break; - } - } - reply = TRUE; - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_WDTR; - p->needwdtr &= ~target_mask; - p->dtr_pending |= target_mask; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - - /* - * By virtue of the SCSI spec, a WDTR message negates any existing - * SDTR negotiations. So, even if needsdtr isn't marked for this - * device, we still have to do a new SDTR message if the device - * supports SDTR at all. Therefore, we check needsdtr_copy instead - * of needstr. - */ - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); - p->needsdtr |= (p->needsdtr_copy & target_mask); - done = TRUE; - break; - } - case MSG_EXT_PPR: - { - unsigned char bus_width, trans_options, new_trans_options; - unsigned int period, offset; - unsigned char maxsync, saved_offset; - struct aic7xxx_syncrate *syncrate; - - if (p->msg_buf[1] != MSG_EXT_PPR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_PPR_LEN + 2)) - { - break; - } - - period = p->msg_buf[3]; - offset = saved_offset = p->msg_buf[5]; - bus_width = p->msg_buf[6]; - trans_options = new_trans_options = p->msg_buf[7] & 0xf; - - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n", - p->host_no, CTL_OF_SCB(scb), period, offset, bus_width, - trans_options); - } - - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - if(p->features & AHC_ULTRA3) - { - maxsync = AHC_SYNCRATE_ULTRA3; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA2; - } - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } - /* - * We might have a device that is starting negotiation with us - * before we can start up negotiation with it....be prepared to - * have a device ask for a higher speed then we want to give it - * in that case - */ - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) ) - { - reply = TRUE; - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_PPR; - p->dev_flags[tindex] |= DEVICE_SCSI_3; - if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) - { - /* - * Not only is the device starting this up, but it also hasn't - * been scanned yet, so this would likely be our TUR or our - * INQUIRY command at scan time, so we need to use the - * settings from the SEEPROM if they existed. Of course, even - * if we didn't find a SEEPROM, we stuffed default values into - * the user settings anyway, so use those in all cases. - */ - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - if(p->transinfo[tindex].user_offset) - { - if(p->features & AHC_ULTRA2) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; - } - else if( p->transinfo[tindex].user_width && - (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE ) - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; - } - else - { - p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; - } - } - p->transinfo[tindex].goal_width = - p->transinfo[tindex].user_width; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - } - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive PPR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - if ( !p->transinfo[tindex].goal_offset ) - period = 255; - if ( p->transinfo[tindex].goal_period > period ) - period = p->transinfo[tindex].goal_period; - if ( p->transinfo[tindex].goal_options == 0 ) - new_trans_options = 0; - switch(bus_width) - { - default: - { - if ( (p->features & AHC_WIDE) && - (p->transinfo[tindex].goal_width == - MSG_EXT_WDTR_BUS_16_BIT) ) - { - bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - } /* Fall through if we aren't a wide card */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - p->needwdtr_copy &= ~target_mask; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_GOAL|AHC_TRANS_QUITE); - break; - } - } - if ( (p->transinfo[tindex].goal_period > 9) || - (p->transinfo[tindex].goal_options == 0) ) - { - scb->flags &= ~SCB_MSGOUT_BITS; - reject = TRUE; - reply = FALSE; - p->needppr &= ~(1 << tindex); - p->needppr_copy &= ~(1 << tindex); - if ( p->transinfo[tindex].goal_offset ) - { - p->needsdtr |= (1 << tindex); - p->needsdtr_copy |= (1 << tindex); - } - if ( p->transinfo[tindex].goal_width ) - { - p->needwdtr |= (1 << tindex); - p->needwdtr_copy |= (1 << tindex); - } - } - } - else - { - switch(bus_width) - { - default: - { - reject = TRUE; - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - /* - * According to the spec, if we aren't wide, we also can't be - * Dual Edge so clear the options byte - */ - new_trans_options = 0; - bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - case MSG_EXT_WDTR_BUS_16_BIT: - { - break; - } - } - } - - if ( !reject ) - { - aic7xxx_set_width(p, target, channel, lun, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - syncrate = aic7xxx_find_syncrate(p, &period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &offset, bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, period, - offset, new_trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR); - } - - p->dtr_pending &= ~target_mask; - p->needppr &= ~target_mask; - if(reply) - { - p->dtr_pending |= target_mask; - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_PPR; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } - done = TRUE; - break; - } - default: - { - reject = TRUE; - break; - } - } /* end of switch(p->msg_type) */ - } /* end of if (!reject && (p->msg_len > 2)) */ - - if (!reply && reject) - { - aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - done = TRUE; - } - return(done); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_reqinit - * - * Description: - * Interrupt handler for REQINIT interrupts (used to transfer messages to - * and from devices). - *_F*************************************************************************/ -static void -aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - unsigned char lastbyte; - unsigned char phasemis; - int done = FALSE; - - switch(p->msg_type) - { - case MSG_TYPE_INITIATOR_MSGOUT: - { - if (p->msg_len == 0) - panic("aic7xxx: REQINIT with no active message!\n"); - - lastbyte = (p->msg_index == (p->msg_len - 1)); - phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT; - - if (lastbyte || phasemis) - { - /* Time to end the message */ - p->msg_len = 0; - p->msg_type = MSG_TYPE_NONE; - /* - * NOTE-TO-MYSELF: If you clear the REQINIT after you - * disable REQINITs, then cases of REJECT_MSG stop working - * and hang the bus - */ - aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); - aic_outb(p, CLRSCSIINT, CLRINT); - p->flags &= ~AHC_HANDLING_REQINITS; - - if (phasemis == 0) - { - aic_outb(p, p->msg_buf[p->msg_index], SINDEX); - aic_outb(p, 0, RETURN_1); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Completed sending of REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); -#endif - } - else - { - aic_outb(p, MSGOUT_PHASEMIS, RETURN_1); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "PHASEMIS while sending REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); -#endif - } - unpause_sequencer(p, TRUE); - } - else - { - /* - * Present the byte on the bus (clearing REQINIT) but don't - * unpause the sequencer. - */ - aic_outb(p, CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - aic_outb(p, p->msg_buf[p->msg_index++], SCSIDATL); - } - break; - } - case MSG_TYPE_INITIATOR_MSGIN: - { - phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN; - - if (phasemis == 0) - { - p->msg_len++; - /* Pull the byte in without acking it */ - p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL); - done = aic7xxx_parse_msg(p, scb); - /* Ack the byte */ - aic_outb(p, CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - aic_inb(p, SCSIDATL); - p->msg_index++; - } - if (phasemis || done) - { -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - { - if (phasemis) - printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); - else - printk(INFO_LEAD "Completed receipt of REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); - } -#endif - /* Time to end our message session */ - p->msg_len = 0; - p->msg_type = MSG_TYPE_NONE; - aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); - aic_outb(p, CLRSCSIINT, CLRINT); - p->flags &= ~AHC_HANDLING_REQINITS; - unpause_sequencer(p, TRUE); - } - break; - } - default: - { - panic("aic7xxx: Unknown REQINIT message type.\n"); - break; - } - } /* End of switch(p->msg_type) */ -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_scsiint - * - * Description: - * Interrupt handler for SCSI interrupts (SCSIINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat) -{ - unsigned char scb_index; - unsigned char status; - struct aic7xxx_scb *scb; - - scb_index = aic_inb(p, SCB_TAG); - status = aic_inb(p, SSTAT1); - - if (scb_index < p->scb_data->numscbs) - { - scb = p->scb_data->scb_array[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - { - scb = NULL; - } - } - else - { - scb = NULL; - } - - - if ((status & SCSIRSTI) != 0) - { - int channel; - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - - if (aic7xxx_verbose & VERBOSE_RESET) - printk(WARN_LEAD "Someone else reset the channel!!\n", - p->host_no, channel, -1, -1); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - /* - * Go through and abort all commands for the channel, but do not - * reset the channel again. - */ - aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - } - else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) ) - { - /* - * First look at what phase we were last in. If it's message-out, - * chances are pretty good that the bus free was in response to - * one of our abort requests. - */ - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned char saved_tcl = aic_inb(p, SAVED_TCL); - unsigned char target = (saved_tcl >> 4) & 0x0F; - int channel; - int printerror = TRUE; - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), - SCSISEQ); - if (lastphase == P_MESGOUT) - { - unsigned char message; - - message = aic_inb(p, SINDEX); - - if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG)) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no, - CTL_OF_SCB(scb), scb->hscb->tag); - aic7xxx_reset_device(p, target, channel, ALL_LUNS, - (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag ); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - printerror = 0; - } - else if (message == MSG_BUS_DEV_RESET) - { - aic7xxx_handle_device_reset(p, target, channel); - scb = NULL; - printerror = 0; - } - } - if ( (scb != NULL) && - (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) ) - { - /* - * This might be a SCSI-3 device that is dropping the bus due to - * errors and signalling that we should reduce the transfer speed. - * All we have to do is complete this command (since it's a negotiation - * command already) and the checksum routine should flag an error and - * reduce the speed setting and renegotiate. We call the reset routing - * just to clean out the hardware from this scb. - */ - printerror = 0; - aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - } - if (printerror != 0) - { - if (scb != NULL) - { - unsigned char tag; - - if ((scb->hscb->control & TAG_ENB) != 0) - { - tag = scb->hscb->tag; - } - else - { - tag = SCB_LIST_NULL; - } - aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag); - aic7xxx_run_done_queue(p, TRUE); - } - else - { - aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL); - aic7xxx_run_done_queue(p, TRUE); - } - printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, " - "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase, - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - scb = NULL; - } - aic_outb(p, MSG_NOOP, MSG_OUT); - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), - SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - aic_outb(p, CLRBUSFREE, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - restart_sequencer(p); - unpause_sequencer(p, TRUE); - } - else if ((status & SELTO) != 0) - { - unsigned char scbptr; - unsigned char nextscb; - Scsi_Cmnd *cmd; - - scbptr = aic_inb(p, WAITING_SCBH); - if (scbptr > p->scb_data->maxhscbs) - { - /* - * I'm still trying to track down exactly how this happens, but until - * I find it, this code will make sure we aren't passing bogus values - * into the SCBPTR register, even if that register will just wrap - * things around, we still don't like having out of range variables. - * - * NOTE: Don't check the aic7xxx_verbose variable, I want this message - * to always be displayed. - */ - printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.\n", - p->host_no, -1, -1, -1, scbptr); - if (p->scb_data->maxhscbs > 4) - scbptr &= (p->scb_data->maxhscbs - 1); - else - scbptr &= 0x03; - } - aic_outb(p, scbptr, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - - scb = NULL; - if (scb_index < p->scb_data->numscbs) - { - scb = p->scb_data->scb_array[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - { - scb = NULL; - } - } - if (scb == NULL) - { - printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n", - p->host_no, -1, -1, -1, scb_index); - printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x " - "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - } - else - { - cmd = scb->cmd; - cmd->result = (DID_TIME_OUT << 16); - - /* - * Clear out this hardware SCB - */ - aic_outb(p, 0, SCB_CONTROL); - - /* - * Clear out a few values in the card that are in an undetermined - * state. - */ - aic_outb(p, MSG_NOOP, MSG_OUT); - - /* - * Shift the waiting for selection queue forward - */ - nextscb = aic_inb(p, SCB_NEXT); - aic_outb(p, nextscb, WAITING_SCBH); - - /* - * Put this SCB back on the free list. - */ - aic7xxx_add_curscb_to_free_list(p); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb)); -#endif - if (scb->flags & SCB_QUEUED_ABORT) - { - /* - * We know that this particular SCB had to be the queued abort since - * the disconnected SCB would have gotten a reconnect instead. - * What we need to do then is to let the command timeout again so - * we get a reset since this abort just failed. - */ - cmd->result = 0; - scb = NULL; - } - else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) - { - /* - * Turn off the needsdtr, needwdtr, and needppr bits since this device - * doesn't seem to exist. - */ - p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); - p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); - } - } - /* - * Keep the sequencer from trying to restart any selections - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - /* - * Make sure the data bits on the bus are released - * Don't do this on 7770 chipsets, it makes them give us - * a BRKADDRINT and kills the card. - */ - if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) - aic_outb(p, 0, SCSIBUSL); - - /* - * Delay for the selection timeout delay period then stop the selection - */ - udelay(301); - aic_outb(p, CLRSELINGO, CLRSINT0); - /* - * Clear out all the interrupt status bits - */ - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - /* - * Restarting the sequencer will stop the selection and make sure devices - * are allowed to reselect in. - */ - restart_sequencer(p); - unpause_sequencer(p, TRUE); - } - else if (scb == NULL) - { - printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid " - "during scsiint 0x%x scb(%d)\n" - " SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n", - p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0), - aic_inb(p, SIMODE1), aic_inb(p, SSTAT0), - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - /* - * Turn off the interrupt and set status to zero, so that it - * falls through the rest of the SCSIINT code. - */ - aic_outb(p, status, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause always */ TRUE); - scb = NULL; - } - else if (status & SCSIPERR) - { - /* - * Determine the bus phase and queue an appropriate message. - */ - char *phase; - Scsi_Cmnd *cmd; - unsigned char mesg_out = MSG_NOOP; - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned char sstat2 = aic_inb(p, SSTAT2); - unsigned char tindex = TARGET_INDEX(scb->cmd); - - cmd = scb->cmd; - switch (lastphase) - { - case P_DATAOUT: - phase = "Data-Out"; - break; - case P_DATAIN: - phase = "Data-In"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_COMMAND: - phase = "Command"; - break; - case P_MESGOUT: - phase = "Message-Out"; - break; - case P_STATUS: - phase = "Status"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_MESGIN: - phase = "Message-In"; - mesg_out = MSG_PARITY_ERROR; - break; - default: - phase = "unknown"; - break; - } - - /* - * A parity error has occurred during a data - * transfer phase. Flag it and continue. - */ - if( (p->features & AHC_ULTRA3) && - (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && - (lastphase == P_DATAIN) ) - { - printk(WARN_LEAD "CRC error during %s phase.\n", - p->host_no, CTL_OF_SCB(scb), phase); - if(sstat2 & CRCVALERR) - { - printk(WARN_LEAD " CRC error in intermediate CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & CRCENDERR) - { - printk(WARN_LEAD " CRC error in ending CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & CRCREQERR) - { - printk(WARN_LEAD " Target incorrectly requested a CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & DUAL_EDGE_ERROR) - { - printk(WARN_LEAD " Dual Edge transmission error.\n", - p->host_no, CTL_OF_SCB(scb)); - } - } - else if( (lastphase == P_MESGOUT) && - (cmd == p->dev_dtr_cmnd[tindex]) && - (scb->flags & SCB_MSGOUT_PPR) ) - { - /* - * As per the draft specs, any device capable of supporting any of - * the option values other than 0 are not allowed to reject the - * PPR message. Instead, they must negotiate out what they do - * support instead of rejecting our offering or else they cause - * a parity error during msg_out phase to signal that they don't - * like our settings. - */ - p->needppr &= ~(1 << tindex); - p->needppr_copy &= ~(1 << tindex); - aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun, - MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE)); - aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0, - 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); - p->transinfo[tindex].goal_options = 0; - p->dtr_pending &= ~(1 << tindex); - scb->flags &= ~SCB_MSGOUT_BITS; - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "parity error during PPR message, reverting " - "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb)); - } - if ( p->transinfo[tindex].goal_width ) - { - p->needwdtr |= (1 << tindex); - p->needwdtr_copy |= (1 << tindex); - } - if ( p->transinfo[tindex].goal_offset ) - { - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->transinfo[tindex].goal_period = 10; - } - p->needsdtr |= (1 << tindex); - p->needsdtr_copy |= (1 << tindex); - } - scb = NULL; - } - else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR) - { - struct aic7xxx_syncrate *syncrate; - unsigned int period = p->transinfo[tindex].cur_period; - unsigned char options = p->transinfo[tindex].cur_options; - /* - * oops, we had a failure, lower the transfer rate and try again. It's - * worth noting here that it might be wise to also check for typical - * wide setting on narrow cable type problems and try disabling wide - * instead of slowing down if those exist. That's hard to do with simple - * checksums though. - */ - printk(WARN_LEAD "Parity error during %s phase.\n", - p->host_no, CTL_OF_SCB(scb), phase); - if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) - { - syncrate++; - if( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) - { - p->transinfo[tindex].goal_period = syncrate->period; - if( p->transinfo[tindex].goal_period > 9 ) - { - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_width) - { - p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width) - { - p->transinfo[tindex].goal_width = 0; - p->needwdtr &= ~(1<needwdtr_copy &= ~(1<transinfo[tindex].goal_offset = - p->transinfo[tindex].user_offset; - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->needppr |= (1<needsdtr &= ~(1<needppr_copy |= (1<needsdtr_copy &= ~(1<needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_options = 0; - p->transinfo[tindex].goal_width = 0; - p->needppr &= ~(1<needsdtr &= ~(1<needwdtr &= ~(1<needppr_copy &= ~(1<needsdtr_copy &= ~(1<needwdtr_copy &= ~(1<dev_flags[tindex] &= ~DEVICE_PARITY_ERROR; - } - else - { - p->dev_flags[tindex] |= DEVICE_PARITY_ERROR; - } - - /* - * We've set the hardware to assert ATN if we get a parity - * error on "in" phases, so all we need to do is stuff the - * message buffer with the appropriate message. "In" phases - * have set mesg_out to something other than MSG_NOP. - */ - if (mesg_out != MSG_NOOP) - { - aic_outb(p, mesg_out, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - scb = NULL; - } - aic_outb(p, CLRSCSIPERR, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause_always */ TRUE); - } - else if ( (status & REQINIT) && - (p->flags & AHC_HANDLING_REQINITS) ) - { -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.\n", p->host_no, - CTL_OF_SCB(scb), aic_inb(p, SSTAT1)); -#endif - aic7xxx_handle_reqinit(p, scb); - return; - } - else - { - /* - * We don't know what's going on. Turn off the - * interrupt source and try to continue. - */ - if (aic7xxx_verbose & VERBOSE_SCSIINT) - printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n", - p->host_no, -1, -1, -1, status); - aic_outb(p, status, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause always */ TRUE); - scb = NULL; - } - if (scb != NULL) - { - aic7xxx_done(p, scb); - } -} - -#ifdef AIC7XXX_VERBOSE_DEBUGGING -static void -aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer) -{ - unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp; - int i, bogus, lost; - static unsigned char scb_status[AIC7XXX_MAXSCB]; - -#define SCB_NO_LIST 0 -#define SCB_FREE_LIST 1 -#define SCB_WAITING_LIST 2 -#define SCB_DISCONNECTED_LIST 4 -#define SCB_CURRENTLY_ACTIVE 8 - - /* - * Note, these checks will fail on a regular basis once the machine moves - * beyond the bus scan phase. The problem is race conditions concerning - * the scbs and where they are linked in. When you have 30 or so commands - * outstanding on the bus, and run this twice with every interrupt, the - * chances get pretty good that you'll catch the sequencer with an SCB - * only partially linked in. Therefore, once we pass the scan phase - * of the bus, we really should disable this function. - */ - bogus = FALSE; - memset(&scb_status[0], 0, sizeof(scb_status)); - pause_sequencer(p); - saved_scbptr = aic_inb(p, SCBPTR); - if (saved_scbptr >= p->scb_data->maxhscbs) - { - printk("Bogus SCBPTR %d\n", saved_scbptr); - bogus = TRUE; - } - scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE; - free_scbh = aic_inb(p, FREE_SCBH); - if ( (free_scbh != SCB_LIST_NULL) && - (free_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus FREE_SCBH %d\n", free_scbh); - bogus = TRUE; - } - else - { - temp = free_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_FREE_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_FREE_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - dis_scbh = aic_inb(p, DISCONNECTED_SCBH); - if ( (dis_scbh != SCB_LIST_NULL) && - (dis_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus DISCONNECTED_SCBH %d\n", dis_scbh); - bogus = TRUE; - } - else - { - temp = dis_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_DISCONNECTED_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_DISCONNECTED_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - wait_scbh = aic_inb(p, WAITING_SCBH); - if ( (wait_scbh != SCB_LIST_NULL) && - (wait_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus WAITING_SCBH %d\n", wait_scbh); - bogus = TRUE; - } - else - { - temp = wait_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_WAITING_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_WAITING_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - lost=0; - for(i=0; i < p->scb_data->maxhscbs; i++) - { - aic_outb(p, i, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - if ( ((temp != SCB_LIST_NULL) && - (temp >= p->scb_data->maxhscbs)) ) - { - printk("HSCB %d bad, SCB_NEXT invalid(%d).\n", i, temp); - bogus = TRUE; - } - if ( temp == i ) - { - printk("HSCB %d bad, SCB_NEXT points to self.\n", i); - bogus = TRUE; - } - if (scb_status[i] == 0) - lost++; - if (lost > 1) - { - printk("Too many lost scbs.\n"); - bogus=TRUE; - } - } - aic_outb(p, saved_scbptr, SCBPTR); - unpause_sequencer(p, FALSE); - if (bogus) - { - printk("Bogus parameters found in card SCB array structures.\n"); - printk("%s\n", buffer); - aic7xxx_panic_abort(p, NULL); - } - return; -} -#endif - - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_command_completion_intr - * - * Description: - * SCSI command completion interrupt handler. - *-F*************************************************************************/ -static void -aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scb = NULL; - Scsi_Cmnd *cmd; - unsigned char scb_index, tindex; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) ) - printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1); -#endif - - /* - * Read the INTSTAT location after clearing the CMDINT bit. This forces - * any posted PCI writes to flush to memory. Gerard Roudier suggested - * this fix to the possible race of clearing the CMDINT bit but not - * having all command bytes flushed onto the qoutfifo. - */ - aic_outb(p, CLRCMDINT, CLRINT); - aic_inb(p, INTSTAT); - /* - * The sequencer will continue running when it - * issues this interrupt. There may be >1 commands - * finished, so loop until we've processed them all. - */ - - while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL) - { - scb_index = p->qoutfifo[p->qoutfifonext]; - p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL; - if ( scb_index >= p->scb_data->numscbs ) - { - printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no, - -1, -1, -1, scb_index); - continue; - } - scb = p->scb_data->scb_array[scb_index]; - if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags " - "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags, - (unsigned long) scb->cmd); - continue; - } - tindex = TARGET_INDEX(scb->cmd); - if (scb->flags & SCB_QUEUED_ABORT) - { - pause_sequencer(p); - if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) && - (aic_inb(p, SCB_TAG) == scb->hscb->tag) ) - { - unpause_sequencer(p, FALSE); - continue; - } - aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel, - scb->cmd->lun, scb->hscb->tag); - scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT | - SCB_QUEUED_ABORT); - unpause_sequencer(p, FALSE); - } - else if (scb->flags & SCB_ABORT) - { - /* - * We started to abort this, but it completed on us, let it - * through as successful - */ - scb->flags &= ~(SCB_ABORT|SCB_RESET); - } - else if (scb->flags & SCB_SENSE) - { - char *buffer = &scb->cmd->sense_buffer[0]; - if (scb->cmd == p->dev_dtr_cmnd[tindex]) - { - struct aic7xxx_scb *old_scb; - /* - * We have valid sense data, send it back immediately. - */ - old_scb = p->scb_data->scb_array[scb->cmd->next->tag]; - *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer; - old_scb->hscb->target_status = scb->hscb->target_status; - old_scb->cmd->result = scb->hscb->target_status; - old_scb->cmd->result |= (DID_ERROR << 16); - aic7xxx_status(old_scb->cmd) = scb->hscb->target_status; - scbq_remove(&p->waiting_scbs, old_scb); - scbq_remove(&p->delayed_scbs[tindex], old_scb); - scb->cmd->next = NULL; - aic7xxx_done(p, scb); - aic7xxx_done(p, old_scb); - continue; - } - else if (buffer[12] == 0x47 || buffer[12] == 0x54) - { - /* - * SCSI errors, run domain validation and re-run negotiation - */ - p->needdv |= (1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<needwdtr |= (p->needwdtr_copy & (1<hscb->target_status)) - { - case QUEUE_FULL: - case BUSY: - scb->hscb->target_status = 0; - scb->cmd->result = 0; - aic7xxx_error(scb->cmd) = DID_OK; - break; - default: - cmd = scb->cmd; - if (scb->hscb->residual_SG_segment_count != 0) - { - aic7xxx_calculate_residual(p, scb); - } - cmd->result |= (aic7xxx_error(cmd) << 16); - aic7xxx_done(p, scb); - break; - } - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_isr - * - * Description: - * SCSI controller interrupt handler. - *-F*************************************************************************/ -static void -aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) -{ - struct aic7xxx_host *p; - unsigned char intstat; - - p = (struct aic7xxx_host *)dev_id; - - /* - * Just a few sanity checks. Make sure that we have an int pending. - * Also, if PCI, then we are going to check for a PCI bus error status - * should we get too many spurious interrupts. - */ - if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND)) - { -#ifdef CONFIG_PCI - if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) && - !(p->flags & AHC_HANDLING_REQINITS) ) - { - if ( aic_inb(p, ERROR) & PCIERRSTAT ) - { - aic7xxx_pci_intr(p); - } - p->spurious_int = 0; - } - else if ( !(p->flags & AHC_HANDLING_REQINITS) ) - { - p->spurious_int++; - } -#endif - return; - } - - p->spurious_int = 0; - - /* - * Keep track of interrupts for /proc/scsi - */ - p->isr_count++; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) && - (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) ) - aic7xxx_check_scbs(p, "Bogus settings at start of interrupt."); -#endif - - /* - * Handle all the interrupt sources - especially for SCSI - * interrupts, we won't get a second chance at them. - */ - if (intstat & CMDCMPLT) - { - aic7xxx_handle_command_completion_intr(p); - } - - if (intstat & BRKADRINT) - { - int i; - unsigned char errno = aic_inb(p, ERROR); - - printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno); - for (i = 0; i < NUMBER(hard_error); i++) - { - if (errno & hard_error[i].errno) - { - printk(KERN_ERR " %s\n", hard_error[i].errmesg); - } - } - printk(KERN_ERR "(scsi%d) SEQADDR=0x%x\n", p->host_no, - (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0))); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); -#ifdef CONFIG_PCI - if (errno & PCIERRSTAT) - aic7xxx_pci_intr(p); -#endif - if (errno & (SQPARERR | ILLOPCODE | ILLSADDR)) - { - sti(); - panic("aic7xxx: unrecoverable BRKADRINT.\n"); - } - if (errno & ILLHADDR) - { - printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first " - "pausing controller!\n", p->host_no); - } -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (errno & DPARERR) - { - if (aic_inb(p, DMAPARAMS) & DIRECTION) - printk("(scsi%d) while DMAing SCB from host to card.\n", p->host_no); - else - printk("(scsi%d) while DMAing SCB from card to host.\n", p->host_no); - } -#endif - aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT); - unpause_sequencer(p, FALSE); - } - - if (intstat & SEQINT) - { - /* - * Read the CCSCBCTL register to work around a bug in the Ultra2 cards - */ - if(p->features & AHC_ULTRA2) - { - aic_inb(p, CCSCBCTL); - } - aic7xxx_handle_seqint(p, intstat); - } - - if (intstat & SCSIINT) - { - aic7xxx_handle_scsiint(p, intstat); - } - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) && - (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) ) - aic7xxx_check_scbs(p, "Bogus settings at end of interrupt."); -#endif - -} - -/*+F************************************************************************* - * Function: - * do_aic7xxx_isr - * - * Description: - * This is a gross hack to solve a problem in linux kernels 2.1.85 and - * above. Please, children, do not try this at home, and if you ever see - * anything like it, please inform the Gross Hack Police immediately - *-F*************************************************************************/ -static void -do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long cpu_flags; - struct aic7xxx_host *p; - - p = (struct aic7xxx_host *)dev_id; - if(!p) - return; - spin_lock_irqsave(&io_request_lock, cpu_flags); - if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags)) - { - spin_unlock_irqrestore(&io_request_lock, cpu_flags); - return; - } - do - { - aic7xxx_isr(irq, dev_id, regs); - } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags); - spin_unlock_irqrestore(&io_request_lock, cpu_flags); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_device_queue_depth - * - * Description: - * Determines the queue depth for a given device. There are two ways - * a queue depth can be obtained for a tagged queueing device. One - * way is the default queue depth which is determined by whether - * AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used - * as the default queue depth. Otherwise, we use either 4 or 8 as the - * default queue depth (dependent on the number of hardware SCBs). - * The other way we determine queue depth is through the use of the - * aic7xxx_tag_info array which is enabled by defining - * AIC7XXX_TAGGED_QUEUEING_BY_DEVICE. This array can be initialized - * with queue depths for individual devices. It also allows tagged - * queueing to be [en|dis]abled for a specific adapter. - *-F*************************************************************************/ -static int -aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) -{ - int default_depth = 3; - unsigned char tindex; - unsigned short target_mask; - - tindex = device->id | (device->channel << 3); - target_mask = (1 << tindex); - - if (p->dev_max_queue_depth[tindex] > 1) - { - /* - * We've already scanned this device, leave it alone - */ - return(p->dev_max_queue_depth[tindex]); - } - - device->queue_depth = default_depth; - p->dev_temp_queue_depth[tindex] = 1; - p->dev_max_queue_depth[tindex] = 1; - p->tagenable &= ~target_mask; - - if (device->tagged_supported) - { - int tag_enabled = TRUE; - - default_depth = AIC7XXX_CMDS_PER_DEVICE; - - if (!(p->discenable & target_mask)) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - printk(INFO_LEAD "Disconnection disabled, unable to " - "enable tagged queueing.\n", - p->host_no, device->channel, device->id, device->lun); - } - else - { - if (p->instance >= NUMBER(aic7xxx_tag_info)) - { - static int print_warning = TRUE; - if(print_warning) - { - printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for" - " installed controllers.\n"); - printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in" - " the aic7xxx.c source file.\n"); - print_warning = FALSE; - } - device->queue_depth = default_depth; - } - else - { - - if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255) - { - tag_enabled = FALSE; - device->queue_depth = 3; /* Tagged queueing is disabled. */ - } - else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0) - { - device->queue_depth = default_depth; - } - else - { - device->queue_depth = - aic7xxx_tag_info[p->instance].tag_commands[tindex]; - } - } - if ((device->tagged_queue == 0) && tag_enabled) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n", - p->host_no, device->channel, device->id, - device->lun, device->queue_depth); - } - p->dev_max_queue_depth[tindex] = device->queue_depth; - p->dev_temp_queue_depth[tindex] = device->queue_depth; - p->tagenable |= target_mask; - p->orderedtag |= target_mask; - device->tagged_queue = 1; - device->current_tag = SCB_LIST_NULL; - } - } - } - return(p->dev_max_queue_depth[tindex]); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_select_queue_depth - * - * Description: - * Sets the queue depth for each SCSI device hanging off the input - * host adapter. We use a queue depth of 2 for devices that do not - * support tagged queueing. If AIC7XXX_CMDS_PER_LUN is defined, we - * use that for tagged queueing devices; otherwise we use our own - * algorithm for determining the queue depth based on the maximum - * SCBs for the controller. - *-F*************************************************************************/ -static void -aic7xxx_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs) -{ - Scsi_Device *device; - struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata; - int scbnum; - - scbnum = 0; - for (device = scsi_devs; device != NULL; device = device->next) - { - if (device->host == host) - { - scbnum += aic7xxx_device_queue_depth(p, device); - } - } - while (scbnum > p->scb_data->numscbs) - { - /* - * Pre-allocate the needed SCBs to get around the possibility of having - * to allocate some when memory is more or less exhausted and we need - * the SCB in order to perform a swap operation (possible deadlock) - */ - if ( aic7xxx_allocate_scb(p) == 0 ) - return; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_probe - * - * Description: - * Probing for EISA boards: it looks like the first two bytes - * are a manufacturer code - three characters, five bits each: - * - * BYTE 0 BYTE 1 BYTE 2 BYTE 3 - * ?1111122 22233333 PPPPPPPP RRRRRRRR - * - * The characters are baselined off ASCII '@', so add that value - * to each to get the real ASCII code for it. The next two bytes - * appear to be a product and revision number, probably vendor- - * specific. This is what is being searched for at each port, - * and what should probably correspond to the ID= field in the - * ECU's .cfg file for the card - if your card is not detected, - * make sure your signature is listed in the array. - * - * The fourth byte's lowest bit seems to be an enabled/disabled - * flag (rest of the bits are reserved?). - * - * NOTE: This function is only needed on Intel and Alpha platforms, - * the other platforms we support don't have EISA/VLB busses. So, - * we #ifdef this entire function to avoid compiler warnings about - * an unused function. - *-F*************************************************************************/ -#if defined(__i386__) || defined(__alpha__) -static int -aic7xxx_probe(int slot, int base, ahc_flag_type *flags) -{ - int i; - unsigned char buf[4]; - - static struct { - int n; - unsigned char signature[sizeof(buf)]; - ahc_chip type; - int bios_disabled; - } AIC7xxx[] = { - { 4, { 0x04, 0x90, 0x77, 0x70 }, - AHC_AIC7770|AHC_EISA, FALSE }, /* mb 7770 */ - { 4, { 0x04, 0x90, 0x77, 0x71 }, - AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */ - { 4, { 0x04, 0x90, 0x77, 0x56 }, - AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */ - { 4, { 0x04, 0x90, 0x77, 0x57 }, - AHC_AIC7770|AHC_VL, TRUE } /* 284x BIOS disabled */ - }; - - /* - * The VL-bus cards need to be primed by - * writing before a signature check. - */ - for (i = 0; i < sizeof(buf); i++) - { - outb(0x80 + i, base); - buf[i] = inb(base + i); - } - - for (i = 0; i < NUMBER(AIC7xxx); i++) - { - /* - * Signature match on enabled card? - */ - if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n)) - { - if (inb(base + 4) & 1) - { - if (AIC7xxx[i].bios_disabled) - { - *flags |= AHC_USEDEFAULTS; - } - else - { - *flags |= AHC_BIOS_ENABLED; - } - return (i); - } - - printk("aic7xxx: " - "disabled at slot %d, ignored.\n", slot); - } - } - - return (-1); -} -#endif /* (__i386__) || (__alpha__) */ - - -/*+F************************************************************************* - * Function: - * read_2840_seeprom - * - * Description: - * Reads the 2840 serial EEPROM and returns 1 if successful and 0 if - * not successful. - * - * See read_seeprom (for the 2940) for the instruction set of the 93C46 - * chip. - * - * The 2840 interface to the 93C46 serial EEPROM is through the - * STATUS_2840 and SEECTL_2840 registers. The CS_2840, CK_2840, and - * DO_2840 bits of the SEECTL_2840 register are connected to the chip - * select, clock, and data out lines respectively of the serial EEPROM. - * The DI_2840 bit of the STATUS_2840 is connected to the data in line - * of the serial EEPROM. The EEPROM_TF bit of STATUS_2840 register is - * useful in that it gives us an 800 nsec timer. After a read from the - * SEECTL_2840 register the timing flag is cleared and goes high 800 nsec - * later. - *-F*************************************************************************/ -static int -read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc) -{ - int i = 0, k = 0; - unsigned char temp; - unsigned short checksum = 0; - unsigned short *seeprom = (unsigned short *) sc; - struct seeprom_cmd { - unsigned char len; - unsigned char bits[3]; - }; - struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; - -#define CLOCK_PULSE(p) \ - while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0) \ - { \ - ; /* Do nothing */ \ - } \ - (void) aic_inb(p, SEECTL_2840); - - /* - * Read the first 32 registers of the seeprom. For the 2840, - * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers - * but only the first 32 are used by Adaptec BIOS. The loop - * will range from 0 to 31. - */ - for (k = 0; k < (sizeof(*sc) / 2); k++) - { - /* - * Send chip select for one clock cycle. - */ - aic_outb(p, CK_2840 | CS_2840, SEECTL_2840); - CLOCK_PULSE(p); - - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - for (i = 0; i < seeprom_read.len; i++) - { - temp = CS_2840 | seeprom_read.bits[i]; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - /* - * Send the 6 bit address (MSB first, LSB last). - */ - for (i = 5; i >= 0; i--) - { - temp = k; - temp = (temp >> i) & 1; /* Mask out all but lower bit. */ - temp = CS_2840 | temp; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - for (i = 0; i <= 16; i++) - { - temp = CS_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840); - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - /* - * The serial EEPROM has a checksum in the last word. Keep a - * running checksum for all words read except for the last - * word. We'll verify the checksum after all words have been - * read. - */ - if (k < (sizeof(*sc) / 2) - 1) - { - checksum = checksum + seeprom[k]; - } - - /* - * Reset the chip select for the next command cycle. - */ - aic_outb(p, 0, SEECTL_2840); - CLOCK_PULSE(p); - aic_outb(p, CK_2840, SEECTL_2840); - CLOCK_PULSE(p); - aic_outb(p, 0, SEECTL_2840); - CLOCK_PULSE(p); - } - -#if 0 - printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum); - printk("Serial EEPROM:"); - for (k = 0; k < (sizeof(*sc) / 2); k++) - { - if (((k % 8) == 0) && (k != 0)) - { - printk("\n "); - } - printk(" 0x%x", seeprom[k]); - } - printk("\n"); -#endif - - if (checksum != sc->checksum) - { - printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n"); - return (0); - } - - return (1); -#undef CLOCK_PULSE -} - -#define CLOCK_PULSE(p) \ - do { \ - int limit = 0; \ - do { \ - mb(); \ - pause_sequencer(p); /* This is just to generate some PCI */ \ - /* traffic so the PCI read is flushed */ \ - /* it shouldn't be needed, but some */ \ - /* chipsets do indeed appear to need */ \ - /* something to force PCI reads to get */ \ - /* flushed */ \ - udelay(1); /* Do nothing */ \ - } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \ - } while(0) - -/*+F************************************************************************* - * Function: - * acquire_seeprom - * - * Description: - * Acquires access to the memory port on PCI controllers. - *-F*************************************************************************/ -static int -acquire_seeprom(struct aic7xxx_host *p) -{ - - /* - * Request access of the memory port. When access is - * granted, SEERDY will go high. We use a 1 second - * timeout which should be near 1 second more than - * is needed. Reason: after the 7870 chip reset, there - * should be no contention. - */ - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - if ((aic_inb(p, SEECTL) & SEERDY) == 0) - { - aic_outb(p, 0, SEECTL); - return (0); - } - return (1); -} - -/*+F************************************************************************* - * Function: - * release_seeprom - * - * Description: - * Releases access to the memory port on PCI controllers. - *-F*************************************************************************/ -static void -release_seeprom(struct aic7xxx_host *p) -{ - /* - * Make sure the SEEPROM is ready before we release it. - */ - CLOCK_PULSE(p); - aic_outb(p, 0, SEECTL); -} - -/*+F************************************************************************* - * Function: - * read_seeprom - * - * Description: - * Reads the serial EEPROM and returns 1 if successful and 0 if - * not successful. - * - * The instruction set of the 93C46/56/66 chips is as follows: - * - * Start OP - * Function Bit Code Address Data Description - * ------------------------------------------------------------------- - * READ 1 10 A5 - A0 Reads data stored in memory, - * starting at specified address - * EWEN 1 00 11XXXX Write enable must precede - * all programming modes - * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 - * WRITE 1 01 A5 - A0 D15 - D0 Writes register - * ERAL 1 00 10XXXX Erase all registers - * WRAL 1 00 01XXXX D15 - D0 Writes to all registers - * EWDS 1 00 00XXXX Disables all programming - * instructions - * *Note: A value of X for address is a don't care condition. - * *Note: The 93C56 and 93C66 have 8 address bits. - * - * - * The 93C46 has a four wire interface: clock, chip select, data in, and - * data out. In order to perform one of the above functions, you need - * to enable the chip select for a clock period (typically a minimum of - * 1 usec, with the clock high and low a minimum of 750 and 250 nsec - * respectively. While the chip select remains high, you can clock in - * the instructions (above) starting with the start bit, followed by the - * OP code, Address, and Data (if needed). For the READ instruction, the - * requested 16-bit register contents is read from the data out line but - * is preceded by an initial zero (leading 0, followed by 16-bits, MSB - * first). The clock cycling from low to high initiates the next data - * bit to be sent from the chip. - * - * The 78xx interface to the 93C46 serial EEPROM is through the SEECTL - * register. After successful arbitration for the memory port, the - * SEECS bit of the SEECTL register is connected to the chip select. - * The SEECK, SEEDO, and SEEDI are connected to the clock, data out, - * and data in lines respectively. The SEERDY bit of SEECTL is useful - * in that it gives us an 800 nsec timer. After a write to the SEECTL - * register, the SEERDY goes high 800 nsec later. The one exception - * to this is when we first request access to the memory port. The - * SEERDY goes high to signify that access has been granted and, for - * this case, has no implied timing. - *-F*************************************************************************/ -static int -read_seeprom(struct aic7xxx_host *p, int offset, - unsigned short *scarray, unsigned int len, seeprom_chip_type chip) -{ - int i = 0, k; - unsigned char temp; - unsigned short checksum = 0; - struct seeprom_cmd { - unsigned char len; - unsigned char bits[3]; - }; - struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; - - /* - * Request access of the memory port. - */ - if (acquire_seeprom(p) == 0) - { - return (0); - } - - /* - * Read 'len' registers of the seeprom. For the 7870, the 93C46 - * SEEPROM is a 1024-bit device with 64 16-bit registers but only - * the first 32 are used by Adaptec BIOS. Some adapters use the - * 93C56 SEEPROM which is a 2048-bit device. The loop will range - * from 0 to 'len' - 1. - */ - for (k = 0; k < len; k++) - { - /* - * Send chip select for one clock cycle. - */ - aic_outb(p, SEEMS | SEECK | SEECS, SEECTL); - CLOCK_PULSE(p); - - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - for (i = 0; i < seeprom_read.len; i++) - { - temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - /* - * Send the 6 or 8 bit address (MSB first, LSB last). - */ - for (i = ((int) chip - 1); i >= 0; i--) - { - temp = k + offset; - temp = (temp >> i) & 1; /* Mask out all but lower bit. */ - temp = SEEMS | SEECS | (temp << 1); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - for (i = 0; i <= 16; i++) - { - temp = SEEMS | SEECS; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - - /* - * The serial EEPROM should have a checksum in the last word. - * Keep a running checksum for all words read except for the - * last word. We'll verify the checksum after all words have - * been read. - */ - if (k < (len - 1)) - { - checksum = checksum + scarray[k]; - } - - /* - * Reset the chip select for the next command cycle. - */ - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - aic_outb(p, SEEMS | SEECK, SEECTL); - CLOCK_PULSE(p); - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - } - - /* - * Release access to the memory port and the serial EEPROM. - */ - release_seeprom(p); - -#if 0 - printk("Computed checksum 0x%x, checksum read 0x%x\n", - checksum, scarray[len - 1]); - printk("Serial EEPROM:"); - for (k = 0; k < len; k++) - { - if (((k % 8) == 0) && (k != 0)) - { - printk("\n "); - } - printk(" 0x%x", scarray[k]); - } - printk("\n"); -#endif - if ( (checksum != scarray[len - 1]) || (checksum == 0) ) - { - return (0); - } - - return (1); -} - -/*+F************************************************************************* - * Function: - * read_brdctl - * - * Description: - * Reads the BRDCTL register. - *-F*************************************************************************/ -static unsigned char -read_brdctl(struct aic7xxx_host *p) -{ - unsigned char brdctl, value; - - /* - * Make sure the SEEPROM is ready before we access it - */ - CLOCK_PULSE(p); - if (p->features & AHC_ULTRA2) - { - brdctl = BRDRW_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - value = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - return(value); - } - brdctl = BRDRW; - if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || - (p->flags & AHC_CHNLB) ) - { - brdctl |= BRDCS; - } - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - value = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - aic_outb(p, 0, BRDCTL); - CLOCK_PULSE(p); - return (value); -} - -/*+F************************************************************************* - * Function: - * write_brdctl - * - * Description: - * Writes a value to the BRDCTL register. - *-F*************************************************************************/ -static void -write_brdctl(struct aic7xxx_host *p, unsigned char value) -{ - unsigned char brdctl; - - /* - * Make sure the SEEPROM is ready before we access it - */ - CLOCK_PULSE(p); - if (p->features & AHC_ULTRA2) - { - brdctl = value; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl |= BRDSTB_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDSTB_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - read_brdctl(p); - CLOCK_PULSE(p); - } - else - { - brdctl = BRDSTB; - if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || - (p->flags & AHC_CHNLB) ) - { - brdctl |= BRDCS; - } - brdctl = BRDSTB | BRDCS; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl |= value; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDSTB; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDCS; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - } -} - -/*+F************************************************************************* - * Function: - * aic785x_cable_detect - * - * Description: - * Detect the cables that are present on aic785x class controller chips - *-F*************************************************************************/ -static void -aic785x_cable_detect(struct aic7xxx_host *p, int *int_50, - int *ext_present, int *eeprom) -{ - unsigned char brdctl; - - aic_outb(p, BRDRW | BRDCS, BRDCTL); - CLOCK_PULSE(p); - aic_outb(p, 0, BRDCTL); - CLOCK_PULSE(p); - brdctl = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - *int_50 = !(brdctl & BRDDAT5); - *ext_present = !(brdctl & BRDDAT6); - *eeprom = (aic_inb(p, SPIOCAP) & EEPROM); -} - -#undef CLOCK_PULSE - -/*+F************************************************************************* - * Function: - * aic2940_uwpro_cable_detect - * - * Description: - * Detect the cables that are present on the 2940-UWPro cards - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68, - int *ext_68, int *eeprom) -{ - unsigned char brdctl; - - /* - * First read the status of our cables. Set the rom bank to - * 0 since the bank setting serves as a multiplexor for the - * cable detection logic. BRDDAT5 controls the bank switch. - */ - write_brdctl(p, 0); - - /* - * Now we read the state of the internal 68 connector. BRDDAT6 - * is don't care, BRDDAT7 is internal 68. The cable is - * present if the bit is 0 - */ - brdctl = read_brdctl(p); - *int_68 = !(brdctl & BRDDAT7); - - /* - * Set the bank bit in brdctl and then read the external cable state - * and the EEPROM status - */ - write_brdctl(p, BRDDAT5); - brdctl = read_brdctl(p); - - *ext_68 = !(brdctl & BRDDAT6); - *eeprom = !(brdctl & BRDDAT7); - - /* - * We're done, the calling function will release the SEEPROM for us - */ -} - -/*+F************************************************************************* - * Function: - * aic787x_cable_detect - * - * Description: - * Detect the cables that are present on aic787x class controller chips - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68, - int *ext_present, int *eeprom) -{ - unsigned char brdctl; - - /* - * First read the status of our cables. Set the rom bank to - * 0 since the bank setting serves as a multiplexor for the - * cable detection logic. BRDDAT5 controls the bank switch. - */ - write_brdctl(p, 0); - - /* - * Now we read the state of the two internal connectors. BRDDAT6 - * is internal 50, BRDDAT7 is internal 68. For each, the cable is - * present if the bit is 0 - */ - brdctl = read_brdctl(p); - *int_50 = !(brdctl & BRDDAT6); - *int_68 = !(brdctl & BRDDAT7); - - /* - * Set the bank bit in brdctl and then read the external cable state - * and the EEPROM status - */ - write_brdctl(p, BRDDAT5); - brdctl = read_brdctl(p); - - *ext_present = !(brdctl & BRDDAT6); - *eeprom = !(brdctl & BRDDAT7); - - /* - * We're done, the calling function will release the SEEPROM for us - */ -} - -/*+F************************************************************************* - * Function: - * aic787x_ultra2_term_detect - * - * Description: - * Detect the termination settings present on ultra2 class controllers - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low, - int *enableSE_high, int *enableLVD_low, - int *enableLVD_high, int *eprom_present) -{ - unsigned char brdctl; - - brdctl = read_brdctl(p); - - *eprom_present = (brdctl & BRDDAT7); - *enableSE_high = (brdctl & BRDDAT6); - *enableSE_low = (brdctl & BRDDAT5); - *enableLVD_high = (brdctl & BRDDAT4); - *enableLVD_low = (brdctl & BRDDAT3); -} - -/*+F************************************************************************* - * Function: - * configure_termination - * - * Description: - * Configures the termination settings on PCI adapters that have - * SEEPROMs available. - *-F*************************************************************************/ -static void -configure_termination(struct aic7xxx_host *p) -{ - int internal50_present = 0; - int internal68_present = 0; - int external_present = 0; - int eprom_present = 0; - int enableSE_low = 0; - int enableSE_high = 0; - int enableLVD_low = 0; - int enableLVD_high = 0; - unsigned char brddat = 0; - unsigned char max_target = 0; - unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1); - - if (acquire_seeprom(p)) - { - if (p->features & (AHC_WIDE|AHC_TWIN)) - max_target = 16; - else - max_target = 8; - aic_outb(p, SEEMS | SEECS, SEECTL); - sxfrctl1 &= ~STPWEN; - /* - * The termination/cable detection logic is split into three distinct - * groups. Ultra2 and later controllers, 2940UW-Pro controllers, and - * older 7850, 7860, 7870, 7880, and 7895 controllers. Each has its - * own unique way of detecting their cables and writing the results - * back to the card. - */ - if (p->features & AHC_ULTRA2) - { - /* - * As long as user hasn't overridden term settings, always check the - * cable detection logic - */ - if (aic7xxx_override_term == -1) - { - aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high, - &enableLVD_low, &enableLVD_high, - &eprom_present); - } - - /* - * If the user is overriding settings, then they have been preserved - * to here as fake adapter_control entries. Parse them and allow - * them to override the detected settings (if we even did detection). - */ - if (!(p->adapter_control & CFSEAUTOTERM)) - { - enableSE_low = (p->adapter_control & CFSTERM); - enableSE_high = (p->adapter_control & CFWSTERM); - } - if (!(p->adapter_control & CFAUTOTERM)) - { - enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM); - } - - /* - * Now take those settings that we have and translate them into the - * values that must be written into the registers. - * - * Flash Enable = BRDDAT7 - * Secondary High Term Enable = BRDDAT6 - * Secondary Low Term Enable = BRDDAT5 - * LVD/Primary High Term Enable = BRDDAT4 - * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1 - */ - if (enableLVD_low != 0) - { - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_LVD; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination " - "Enabled\n", p->host_no); - } - - if (enableLVD_high != 0) - { - brddat |= BRDDAT4; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination " - "Enabled\n", p->host_no); - } - - if (enableSE_low != 0) - { - brddat |= BRDDAT5; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Secondary Low byte termination " - "Enabled\n", p->host_no); - } - - if (enableSE_high != 0) - { - brddat |= BRDDAT6; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Secondary High byte termination " - "Enabled\n", p->host_no); - } - } - else if (p->features & AHC_NEW_AUTOTERM) - { - /* - * The 50 pin connector termination is controlled by STPWEN in the - * SXFRCTL1 register. Since the Adaptec docs typically say the - * controller is not allowed to be in the middle of a cable and - * this is the only connection on that stub of the bus, there is - * no need to even check for narrow termination, it's simply - * always on. - */ - sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n", - p->host_no); - - if (p->adapter_control & CFAUTOTERM) - { - aic2940_uwpro_wide_cable_detect(p, &internal68_present, - &external_present, - &eprom_present); - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " - "Ext-68 %s)\n", p->host_no, - "Don't Care", - internal68_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, - eprom_present ? "is" : "is not"); - if (internal68_present && external_present) - { - brddat = 0; - p->flags &= ~AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n", - p->host_no); - } - else - { - brddat = BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", - p->host_no); - } - } - else - { - /* - * The termination of the Wide channel is done more like normal - * though, and the setting of this termination is done by writing - * either a 0 or 1 to BRDDAT6 of the BRDDAT register - */ - if (p->adapter_control & CFWSTERM) - { - brddat = BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", - p->host_no); - } - else - { - brddat = 0; - } - } - } - else - { - if (p->adapter_control & CFAUTOTERM) - { - if (p->flags & AHC_MOTHERBOARD) - { - printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n", - p->host_no); - printk(KERN_INFO "(scsi%d) Please verify driver detected settings " - "are correct.\n", p->host_no); - printk(KERN_INFO "(scsi%d) If not, then please properly set the " - "device termination\n", p->host_no); - printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting " - "CTRL-A when prompted\n", p->host_no); - printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no); - } - /* Configure auto termination. */ - - if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 ) - { - aic787x_cable_detect(p, &internal50_present, &internal68_present, - &external_present, &eprom_present); - } - else - { - aic785x_cable_detect(p, &internal50_present, &external_present, - &eprom_present); - } - - if (max_target <= 8) - internal68_present = 0; - - if (max_target > 8) - { - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " - "Ext-68 %s)\n", p->host_no, - internal50_present ? "YES" : "NO", - internal68_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - } - else - { - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)\n", - p->host_no, - internal50_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - } - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, - eprom_present ? "is" : "is not"); - - /* - * Now set the termination based on what we found. BRDDAT6 - * controls wide termination enable. - * Flash Enable = BRDDAT7 - * SE High Term Enable = BRDDAT6 - */ - if (internal50_present && internal68_present && external_present) - { - printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n", - p->host_no); - printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be " - "in use at a time!\n", p->host_no); - /* - * Force termination (low and high byte) on. This is safer than - * leaving it completely off, especially since this message comes - * most often from motherboard controllers that don't even have 3 - * connectors, but instead are failing the cable detection. - */ - internal50_present = external_present = 0; - enableSE_high = enableSE_low = 1; - } - - if ((max_target > 8) && - ((external_present == 0) || (internal68_present == 0)) ) - { - brddat |= BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", - p->host_no); - } - - if ( ((internal50_present ? 1 : 0) + - (internal68_present ? 1 : 0) + - (external_present ? 1 : 0)) <= 1 ) - { - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", - p->host_no); - } - } - else /* p->adapter_control & CFAUTOTERM */ - { - if (p->adapter_control & CFSTERM) - { - sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", - p->host_no); - } - - if (p->adapter_control & CFWSTERM) - { - brddat |= BRDDAT6; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", - p->host_no); - } - } - } - - aic_outb(p, sxfrctl1, SXFRCTL1); - write_brdctl(p, brddat); - release_seeprom(p); - } -} - -/*+F************************************************************************* - * Function: - * detect_maxscb - * - * Description: - * Detects the maximum number of SCBs for the controller and returns - * the count and a mask in p (p->maxscbs, p->qcntmask). - *-F*************************************************************************/ -static void -detect_maxscb(struct aic7xxx_host *p) -{ - int i; - - /* - * It's possible that we've already done this for multichannel - * adapters. - */ - if (p->scb_data->maxhscbs == 0) - { - /* - * We haven't initialized the SCB settings yet. Walk the SCBs to - * determince how many there are. - */ - aic_outb(p, 0, FREE_SCBH); - - for (i = 0; i < AIC7XXX_MAXSCB; i++) - { - aic_outb(p, i, SCBPTR); - aic_outb(p, i, SCB_CONTROL); - if (aic_inb(p, SCB_CONTROL) != i) - break; - aic_outb(p, 0, SCBPTR); - if (aic_inb(p, SCB_CONTROL) != 0) - break; - - aic_outb(p, i, SCBPTR); - aic_outb(p, 0, SCB_CONTROL); /* Clear the control byte. */ - aic_outb(p, i + 1, SCB_NEXT); /* Set the next pointer. */ - aic_outb(p, SCB_LIST_NULL, SCB_TAG); /* Make the tag invalid. */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS); /* no busy untagged */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2); - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3); - } - - /* Make sure the last SCB terminates the free list. */ - aic_outb(p, i - 1, SCBPTR); - aic_outb(p, SCB_LIST_NULL, SCB_NEXT); - - /* Ensure we clear the first (0) SCBs control byte. */ - aic_outb(p, 0, SCBPTR); - aic_outb(p, 0, SCB_CONTROL); - - p->scb_data->maxhscbs = i; - /* - * Use direct indexing instead for speed - */ - if ( i == AIC7XXX_MAXSCB ) - p->flags &= ~AHC_PAGESCBS; - } - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_register - * - * Description: - * Register a Adaptec aic7xxx chip SCSI controller with the kernel. - *-F*************************************************************************/ -static int -aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p, - int reset_delay) -{ - int i, result; - int max_targets; - int found = 1; - unsigned char term, scsi_conf; - struct Scsi_Host *host; - - host = p->host; - - p->scb_data->maxscbs = AIC7XXX_MAXSCB; - host->can_queue = AIC7XXX_MAXSCB; - host->cmd_per_lun = 3; - host->sg_tablesize = AIC7XXX_MAX_SG; - host->select_queue_depths = aic7xxx_select_queue_depth; - host->this_id = p->scsi_id; - host->io_port = p->base; - host->n_io_port = 0xFF; - host->base = p->mbase; - host->irq = p->irq; - if (p->features & AHC_WIDE) - { - host->max_id = 16; - } - if (p->features & AHC_TWIN) - { - host->max_channel = 1; - } - - p->host = host; - p->host_no = host->host_no; - host->unique_id = p->instance; - p->isr_count = 0; - p->next = NULL; - p->completeq.head = NULL; - p->completeq.tail = NULL; - scbq_init(&p->scb_data->free_scbs); - scbq_init(&p->waiting_scbs); - init_timer(&p->dev_timer); - p->dev_timer.data = (unsigned long)p; - p->dev_timer.function = (void *)aic7xxx_timer; - p->dev_timer_active = 0; - - /* - * We currently have no commands of any type - */ - p->qinfifonext = 0; - p->qoutfifonext = 0; - - for (i = 0; i < MAX_TARGETS; i++) - { - p->dev_commands_sent[i] = 0; - p->dev_flags[i] = 0; - p->dev_active_cmds[i] = 0; - p->dev_last_queue_full[i] = 0; - p->dev_last_queue_full_count[i] = 0; - p->dev_max_queue_depth[i] = 1; - p->dev_temp_queue_depth[i] = 1; - p->dev_expires[i] = 0; - scbq_init(&p->delayed_scbs[i]); - } - - printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no, - board_names[p->board_name_index]); - switch(p->chip) - { - case (AHC_AIC7770|AHC_EISA): - printk("EISA slot %d\n", p->pci_device_fn); - break; - case (AHC_AIC7770|AHC_VL): - printk("VLB slot %d\n", p->pci_device_fn); - break; - default: - printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn), - PCI_FUNC(p->pci_device_fn)); - break; - } - if (p->features & AHC_TWIN) - { - printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ", - p->host_no, p->scsi_id, p->scsi_id_b); - } - else - { - char *channel; - - channel = ""; - - if ((p->flags & AHC_MULTI_CHANNEL) != 0) - { - channel = " A"; - - if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 ) - { - channel = (p->flags & AHC_CHNLB) ? " B" : " C"; - } - } - if (p->features & AHC_WIDE) - { - printk(KERN_INFO "(scsi%d) Wide ", p->host_no); - } - else - { - printk(KERN_INFO "(scsi%d) Narrow ", p->host_no); - } - printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id); - } - aic_outb(p, 0, SEQ_FLAGS); - - detect_maxscb(p); - - printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n", - p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis", - p->base, p->irq); - printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n", - p->host_no, p->mbase, (unsigned long)p->maddr); - } - -#ifdef CONFIG_PCI - /* - * Now that we know our instance number, we can set the flags we need to - * force termination if need be. - */ - if (aic7xxx_stpwlev != -1) - { - /* - * This option only applies to PCI controllers. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) - { - unsigned char devconfig; - - pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig); - if ( (aic7xxx_stpwlev >> p->instance) & 0x01 ) - { - devconfig |= STPWLEVEL; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no); - } - else - { - devconfig &= ~STPWLEVEL; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no); - } - pci_write_config_byte(p->pdev, DEVCONFIG, devconfig); - } - } -#endif - - /* - * That took care of devconfig and stpwlev, now for the actual termination - * settings. - */ - if (aic7xxx_override_term != -1) - { - /* - * Again, this only applies to PCI controllers. We don't have problems - * with the termination on 274x controllers to the best of my knowledge. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) - { - unsigned char term_override; - - term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f); - p->adapter_control &= - ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM); - if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) ) - { - p->adapter_control |= CFLVDSTERM; - } - if (term_override & 0x02) - { - p->adapter_control |= CFWSTERM; - } - if (term_override & 0x01) - { - p->adapter_control |= CFSTERM; - } - } - } - - if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) ) - { - if (p->features & AHC_SPIOCAP) - { - if ( aic_inb(p, SPIOCAP) & SSPIOCPS ) - /* - * Update the settings in sxfrctl1 to match the termination - * settings. - */ - configure_termination(p); - } - else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870) - { - configure_termination(p); - } - } - - /* - * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels - */ - if (p->features & AHC_TWIN) - { - /* Select channel B */ - aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); - - if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) - term = (aic_inb(p, SXFRCTL1) & STPWEN); - else - term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0); - - aic_outb(p, p->scsi_id_b, SCSIID); - scsi_conf = aic_inb(p, SCSICONF + 1); - aic_outb(p, DFON | SPIOEN, SXFRCTL0); - aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | - ENSTIMER | ACTNEGEN, SXFRCTL1); - aic_outb(p, 0, SIMODE0); - aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); - aic_outb(p, 0, SCSIRATE); - - /* Select channel A */ - aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); - } - - if (p->features & AHC_ULTRA2) - { - aic_outb(p, p->scsi_id, SCSIID_ULTRA2); - } - else - { - aic_outb(p, p->scsi_id, SCSIID); - } - if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) - term = (aic_inb(p, SXFRCTL1) & STPWEN); - else - term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0); - scsi_conf = aic_inb(p, SCSICONF); - aic_outb(p, DFON | SPIOEN, SXFRCTL0); - aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | - ENSTIMER | ACTNEGEN, SXFRCTL1); - aic_outb(p, 0, SIMODE0); - /* - * If we are a cardbus adapter then don't enable SCSI reset detection. - * We shouldn't likely be sharing SCSI busses with someone else, and - * if we don't have a cable currently plugged into the controller then - * we won't have a power source for the SCSI termination, which means - * we'll see infinite incoming bus resets. - */ - if(p->flags & AHC_NO_STPWEN) - aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1); - else - aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); - aic_outb(p, 0, SCSIRATE); - if ( p->features & AHC_ULTRA2) - aic_outb(p, 0, SCSIOFFSET); - - /* - * Look at the information that board initialization or the board - * BIOS has left us. In the lower four bits of each target's - * scratch space any value other than 0 indicates that we should - * initiate synchronous transfers. If it's zero, the user or the - * BIOS has decided to disable synchronous negotiation to that - * target so we don't activate the needsdtr flag. - */ - if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0) - { - max_targets = 8; - } - else - { - max_targets = 16; - } - - if (!(aic7xxx_no_reset)) - { - /* - * If we reset the bus, then clear the transfer settings, else leave - * them be - */ - for (i = 0; i < max_targets; i++) - { - aic_outb(p, 0, TARG_SCSIRATE + i); - if (p->features & AHC_ULTRA2) - { - aic_outb(p, 0, TARG_OFFSET + i); - } - p->transinfo[i].cur_offset = 0; - p->transinfo[i].cur_period = 0; - p->transinfo[i].cur_width = MSG_EXT_WDTR_BUS_8_BIT; - } - - /* - * If we reset the bus, then clear the transfer settings, else leave - * them be. - */ - aic_outb(p, 0, ULTRA_ENB); - aic_outb(p, 0, ULTRA_ENB + 1); - p->ultraenb = 0; - } - - /* - * Allocate enough hardware scbs to handle the maximum number of - * concurrent transactions we can have. We have to make sure that - * the allocated memory is contiguous memory. The Linux kmalloc - * routine should only allocate contiguous memory, but note that - * this could be a problem if kmalloc() is changed. - */ - { - size_t array_size; - unsigned int hscb_physaddr; - - array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb); - if (p->scb_data->hscbs == NULL) - { - /* pci_alloc_consistent enforces the alignment already and - * clears the area as well. - */ - p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size, - &p->scb_data->hscbs_dma); - /* We have to use pci_free_consistent, not kfree */ - p->scb_data->hscb_kmalloc_ptr = NULL; - p->scb_data->hscbs_dma_len = array_size; - } - if (p->scb_data->hscbs == NULL) - { - printk("(scsi%d) Unable to allocate hardware SCB array; " - "failing detection.\n", p->host_no); - aic_outb(p, 0, SIMODE1); - p->irq = 0; - return(0); - } - - hscb_physaddr = p->scb_data->hscbs_dma; - aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR); - aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1); - aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2); - aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3); - - /* Set up the fifo areas at the same time */ - p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma); - if (p->untagged_scbs == NULL) - { - printk("(scsi%d) Unable to allocate hardware FIFO arrays; " - "failing detection.\n", p->host_no); - p->irq = 0; - return(0); - } - - p->qoutfifo = p->untagged_scbs + 256; - p->qinfifo = p->qoutfifo + 256; - for (i = 0; i < 256; i++) - { - p->untagged_scbs[i] = SCB_LIST_NULL; - p->qinfifo[i] = SCB_LIST_NULL; - p->qoutfifo[i] = SCB_LIST_NULL; - } - - hscb_physaddr = p->fifo_dma; - aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR); - aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1); - aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2); - aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3); - } - - /* The Q-FIFOs we just set up are all empty */ - aic_outb(p, 0, QINPOS); - aic_outb(p, 0, KERNEL_QINPOS); - aic_outb(p, 0, QOUTPOS); - - if(p->features & AHC_QUEUE_REGS) - { - aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA); - aic_outb(p, 0, SDSCB_QOFF); - aic_outb(p, 0, SNSCB_QOFF); - aic_outb(p, 0, HNSCB_QOFF); - } - - /* - * We don't have any waiting selections or disconnected SCBs. - */ - aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); - aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH); - - /* - * Message out buffer starts empty - */ - aic_outb(p, MSG_NOOP, MSG_OUT); - aic_outb(p, MSG_NOOP, LAST_MSG); - - /* - * Set all the other asundry items that haven't been set yet. - * This includes just dumping init values to a lot of registers simply - * to make sure they've been touched and are ready for use parity wise - * speaking. - */ - aic_outb(p, 0, TMODE_CMDADDR); - aic_outb(p, 0, TMODE_CMDADDR + 1); - aic_outb(p, 0, TMODE_CMDADDR + 2); - aic_outb(p, 0, TMODE_CMDADDR + 3); - aic_outb(p, 0, TMODE_CMDADDR_NEXT); - - /* - * Link us into the list of valid hosts - */ - p->next = first_aic7xxx; - first_aic7xxx = p; - - /* - * Allocate the first set of scbs for this controller. This is to stream- - * line code elsewhere in the driver. If we have to check for the existence - * of scbs in certain code sections, it slows things down. However, as - * soon as we register the IRQ for this card, we could get an interrupt that - * includes possibly the SCSI_RSTI interrupt. If we catch that interrupt - * then we are likely to segfault if we don't have at least one chunk of - * SCBs allocated or add checks all through the reset code to make sure - * that the SCBs have been allocated which is an invalid running condition - * and therefore I think it's preferable to simply pre-allocate the first - * chunk of SCBs. - */ - aic7xxx_allocate_scb(p); - - /* - * Load the sequencer program, then re-enable the board - - * resetting the AIC-7770 disables it, leaving the lights - * on with nobody home. - */ - aic7xxx_loadseq(p); - - /* - * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register - */ - aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL); - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - { - aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */ - } - - if ( !(aic7xxx_no_reset) ) - { - if (p->features & AHC_TWIN) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no); - aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); - aic7xxx_reset_current_bus(p); - aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); - } - /* Reset SCSI bus A. */ - if (aic7xxx_verbose & VERBOSE_PROBE2) - { /* In case we are a 3940, 3985, or 7895, print the right channel */ - char *channel = ""; - if (p->flags & AHC_MULTI_CHANNEL) - { - channel = " A"; - if (p->flags & (AHC_CHNLB|AHC_CHNLC)) - channel = (p->flags & AHC_CHNLB) ? " B" : " C"; - } - printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel); - } - - aic7xxx_reset_current_bus(p); - - /* - * Delay for the reset delay by setting the timer, this will delay - * future commands sent to any devices. - */ - p->flags |= AHC_RESET_DELAY; - for(i=0; idev_expires[i] = jiffies + (4 * HZ); - p->dev_timer_active |= (0x01 << i); - } - p->dev_timer.expires = p->dev_expires[p->scsi_id]; - add_timer(&p->dev_timer); - p->dev_timer_active |= (0x01 << MAX_TARGETS); - } - else - { - if (!reset_delay) - { - printk(KERN_INFO "(scsi%d) Not resetting SCSI bus. Note: Don't use " - "the no_reset\n", p->host_no); - printk(KERN_INFO "(scsi%d) option unless you have a verifiable need " - "for it.\n", p->host_no); - } - } - - /* - * Register IRQ with the kernel. Only allow sharing IRQs with - * PCI devices. - */ - if (!(p->chip & AHC_PCI)) - { - result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p)); - } - else - { - result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ, - "aic7xxx", p)); - if (result < 0) - { - result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ, - "aic7xxx", p)); - } - } - if (result < 0) - { - printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring " - "controller.\n", p->host_no, p->irq); - aic_outb(p, 0, SIMODE1); - p->irq = 0; - return (0); - } - - if(aic_inb(p, INTSTAT) & INT_PEND) - printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n", - p->host_no, -1, -1 , -1); - aic7xxx_clear_intstat(p); - - unpause_sequencer(p, /* unpause_always */ TRUE); - - return (found); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_chip_reset - * - * Description: - * Perform a chip reset on the aic7xxx SCSI controller. The controller - * is paused upon return. - *-F*************************************************************************/ -int -aic7xxx_chip_reset(struct aic7xxx_host *p) -{ - unsigned char sblkctl; - int wait; - - /* - * For some 274x boards, we must clear the CHIPRST bit and pause - * the sequencer. For some reason, this makes the driver work. - */ - aic_outb(p, PAUSE | CHIPRST, HCNTRL); - - /* - * In the future, we may call this function as a last resort for - * error handling. Let's be nice and not do any unecessary delays. - */ - wait = 1000; /* 1 msec (1000 * 1 msec) */ - while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK)) - { - udelay(1); /* 1 usec */ - } - - pause_sequencer(p); - - sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE); - if (p->chip & AHC_PCI) - sblkctl &= ~SELBUSB; - switch( sblkctl ) - { - case 0: /* normal narrow card */ - break; - case 2: /* Wide card */ - p->features |= AHC_WIDE; - break; - case 8: /* Twin card */ - p->features |= AHC_TWIN; - p->flags |= AHC_MULTI_CHANNEL; - break; - default: /* hmmm...we don't know what this is */ - printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n", - aic_inb(p, SBLKCTL) & 0x0a); - return(-1); - } - return(0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_alloc - * - * Description: - * Allocate and initialize a host structure. Returns NULL upon error - * and a pointer to a aic7xxx_host struct upon success. - *-F*************************************************************************/ -static struct aic7xxx_host * -aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp) -{ - struct aic7xxx_host *p = NULL; - struct Scsi_Host *host; - int i; - - /* - * Allocate a storage area by registering us with the mid-level - * SCSI layer. - */ - host = scsi_register(sht, sizeof(struct aic7xxx_host)); - - if (host != NULL) - { - p = (struct aic7xxx_host *) host->hostdata; - memset(p, 0, sizeof(struct aic7xxx_host)); - *p = *temp; - p->host = host; - - p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC); - if (p->scb_data != NULL) - { - memset(p->scb_data, 0, sizeof(scb_data_type)); - scbq_init (&p->scb_data->free_scbs); - } - else - { - /* - * For some reason we don't have enough memory. Free the - * allocated memory for the aic7xxx_host struct, and return NULL. - */ - release_region(p->base, MAXREG - MINREG); - scsi_unregister(host); - return(NULL); - } - p->host_no = host->host_no; - p->tagenable = 0; - p->orderedtag = 0; - for (i=0; itransinfo[i].goal_period = 255; - p->transinfo[i].goal_offset = 0; - p->transinfo[i].goal_options = 0; - p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT; - } - DRIVER_LOCK_INIT - } - return (p); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_free - * - * Description: - * Frees and releases all resources associated with an instance of - * the driver (struct aic7xxx_host *). - *-F*************************************************************************/ -static void -aic7xxx_free(struct aic7xxx_host *p) -{ - int i; - - /* - * Free the allocated hardware SCB space. - */ - if (p->scb_data != NULL) - { - struct aic7xxx_scb_dma *scb_dma = NULL; - if (p->scb_data->hscbs != NULL) - { - pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len, - p->scb_data->hscbs, p->scb_data->hscbs_dma); - p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL; - } - /* - * Free the driver SCBs. These were allocated on an as-need - * basis. We allocated these in groups depending on how many - * we could fit into a given amount of RAM. The tail SCB for - * these allocations has a pointer to the alloced area. - */ - for (i = 0; i < p->scb_data->numscbs; i++) - { - if (p->scb_data->scb_array[i]->scb_dma != scb_dma) - { - scb_dma = p->scb_data->scb_array[i]->scb_dma; - pci_free_consistent(p->pdev, scb_dma->dma_len, - (void *)((unsigned long)scb_dma->dma_address - - scb_dma->dma_offset), - scb_dma->dma_address); - } - if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL) - kfree(p->scb_data->scb_array[i]->kmalloc_ptr); - p->scb_data->scb_array[i] = NULL; - } - - /* - * Free the SCB data area. - */ - kfree(p->scb_data); - } - - /* - * Free any alloced Scsi_Cmnd structures that might be around for - * negotiation purposes.... - */ - for (i = 0; i < MAX_TARGETS; i++) - { - if(p->dev_dtr_cmnd[i]) - { - if(p->dev_dtr_cmnd[i]->request_buffer) - { - kfree(p->dev_dtr_cmnd[i]->request_buffer); - } - kfree(p->dev_dtr_cmnd[i]); - } - } - - pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_load_seeprom - * - * Description: - * Load the seeprom and configure adapter and target settings. - * Returns 1 if the load was successful and 0 otherwise. - *-F*************************************************************************/ -static void -aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1) -{ - int have_seeprom = 0; - int i, max_targets, mask; - unsigned char scsirate, scsi_conf; - unsigned short scarray[128]; - struct seeprom_config *sc = (struct seeprom_config *) scarray; - - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "aic7xxx: Loading serial EEPROM..."); - } - switch (p->chip) - { - case (AHC_AIC7770|AHC_EISA): /* None of these adapters have seeproms. */ - if (aic_inb(p, SCSICONF) & TERM_ENB) - p->flags |= AHC_TERM_ENB_A; - if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) ) - p->flags |= AHC_TERM_ENB_B; - break; - - case (AHC_AIC7770|AHC_VL): - have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray); - break; - - default: - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, p->sc_type); - if (!have_seeprom) - { - if(p->sc_type == C46) - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C56_66); - else - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C46); - } - if (!have_seeprom) - { - p->sc_size = 128; - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, p->sc_type); - if (!have_seeprom) - { - if(p->sc_type == C46) - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C56_66); - else - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C46); - } - } - break; - } - - if (!have_seeprom) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("\naic7xxx: No SEEPROM available.\n"); - } - p->flags |= AHC_NEWEEPROM_FMT; - if (aic_inb(p, SCSISEQ) == 0) - { - p->flags |= AHC_USEDEFAULTS; - p->flags &= ~AHC_BIOS_ENABLED; - p->scsi_id = p->scsi_id_b = 7; - *sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Using default values.\n"); - } - } - else if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Using leftover BIOS values.\n"); - } - if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) ) - { - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - sc->adapter_control &= ~CFAUTOTERM; - sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM; - } - if (aic7xxx_extended) - p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); - else - p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); - } - else - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("done\n"); - } - - /* - * Note things in our flags - */ - p->flags |= AHC_SEEPROM_FOUND; - - /* - * Update the settings in sxfrctl1 to match the termination settings. - */ - *sxfrctl1 = 0; - - /* - * Get our SCSI ID from the SEEPROM setting... - */ - p->scsi_id = (sc->brtime_id & CFSCSIID); - - /* - * First process the settings that are different between the VLB - * and PCI adapter seeproms. - */ - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770) - { - /* VLB adapter seeproms */ - if (sc->bios_control & CF284XEXTEND) - p->flags |= AHC_EXTEND_TRANS_A; - - if (sc->adapter_control & CF284XSTERM) - { - *sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - } - } - else - { - /* PCI adapter seeproms */ - if (sc->bios_control & CFEXTEND) - p->flags |= AHC_EXTEND_TRANS_A; - if (sc->bios_control & CFBIOSEN) - p->flags |= AHC_BIOS_ENABLED; - else - p->flags &= ~AHC_BIOS_ENABLED; - - if (sc->adapter_control & CFSTERM) - { - *sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - } - } - memcpy(&p->sc, sc, sizeof(struct seeprom_config)); - } - - p->discenable = 0; - - /* - * Limit to 16 targets just in case. The 2842 for one is known to - * blow the max_targets setting, future cards might also. - */ - max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8); - - if (have_seeprom) - { - for (i = 0; i < max_targets; i++) - { - if( ((p->features & AHC_ULTRA) && - !(sc->adapter_control & CFULTRAEN) && - (sc->device_flags[i] & CFSYNCHISULTRA)) || - (sc->device_flags[i] & CFNEWULTRAFORMAT) ) - { - p->flags |= AHC_NEWEEPROM_FMT; - break; - } - } - } - - for (i = 0; i < max_targets; i++) - { - mask = (0x01 << i); - if (!have_seeprom) - { - if (aic_inb(p, SCSISEQ) != 0) - { - /* - * OK...the BIOS set things up and left behind the settings we need. - * Just make our sc->device_flags[i] entry match what the card has - * set for this device. - */ - p->discenable = - ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) ); - p->ultraenb = - (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) ); - sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0; - if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) - sc->device_flags[i] |= CFWIDEB; - if (p->features & AHC_ULTRA2) - { - if (aic_inb(p, TARG_OFFSET + i)) - { - sc->device_flags[i] |= CFSYNCH; - sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07); - if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 ) - sc->device_flags[i] |= CFSYNCHISULTRA; - } - } - else - { - if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER) - { - sc->device_flags[i] |= CFSYNCH; - if (p->features & AHC_ULTRA) - sc->device_flags[i] |= ((p->ultraenb & mask) ? - CFSYNCHISULTRA : 0); - } - } - } - else - { - /* - * Assume the BIOS has NOT been run on this card and nothing between - * the card and the devices is configured yet. - */ - sc->device_flags[i] = CFDISC; - if (p->features & AHC_WIDE) - sc->device_flags[i] |= CFWIDEB; - if (p->features & AHC_ULTRA3) - sc->device_flags[i] |= 2; - else if (p->features & AHC_ULTRA2) - sc->device_flags[i] |= 3; - else if (p->features & AHC_ULTRA) - sc->device_flags[i] |= CFSYNCHISULTRA; - sc->device_flags[i] |= CFSYNCH; - aic_outb(p, 0, TARG_SCSIRATE + i); - if (p->features & AHC_ULTRA2) - aic_outb(p, 0, TARG_OFFSET + i); - } - } - if (sc->device_flags[i] & CFDISC) - { - p->discenable |= mask; - } - if (p->flags & AHC_NEWEEPROM_FMT) - { - if ( !(p->features & AHC_ULTRA2) ) - { - /* - * I know of two different Ultra BIOSes that do this differently. - * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to - * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s - * while on the IBM Netfinity 5000 they want the same thing - * to be something else, while flags[i] & CFXFER == 0x03 and - * SYNCHISULTRA false should be 40MByte/s. So, we set both to - * 40MByte/s and the lower speeds be damned. People will have - * to select around the conversely mapped lower speeds in order - * to select lower speeds on these boards. - */ - if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && - ((sc->device_flags[i] & CFXFER) == 0x03) ) - { - sc->device_flags[i] &= ~CFXFER; - sc->device_flags[i] |= CFSYNCHISULTRA; - } - if (sc->device_flags[i] & CFSYNCHISULTRA) - { - p->ultraenb |= mask; - } - } - else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) && - (p->features & AHC_ULTRA2) && - (sc->device_flags[i] & CFSYNCHISULTRA) ) - { - p->ultraenb |= mask; - } - } - else if (sc->adapter_control & CFULTRAEN) - { - p->ultraenb |= mask; - } - if ( (sc->device_flags[i] & CFSYNCH) == 0) - { - sc->device_flags[i] &= ~CFXFER; - p->ultraenb &= ~mask; - p->transinfo[i].user_offset = 0; - p->transinfo[i].user_period = 0; - p->transinfo[i].user_options = 0; - p->transinfo[i].cur_offset = 0; - p->transinfo[i].cur_period = 0; - p->transinfo[i].cur_options = 0; - p->needsdtr_copy &= ~mask; - } - else - { - if (p->features & AHC_ULTRA3) - { - p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2; - p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i); - if( (sc->device_flags[i] & CFXFER) < 0x03 ) - { - scsirate = (sc->device_flags[i] & CFXFER); - p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC; - if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 ) - { - p->transinfo[i].cur_options = - ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ? - MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS); - } - else - { - p->transinfo[i].cur_options = 0; - } - } - else - { - scsirate = (sc->device_flags[i] & CFXFER) | - ((p->ultraenb & mask) ? 0x18 : 0x10); - p->transinfo[i].user_options = 0; - p->transinfo[i].cur_options = 0; - } - p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate, - AHC_SYNCRATE_ULTRA3); - p->transinfo[i].cur_period = aic7xxx_find_period(p, - aic_inb(p, TARG_SCSIRATE + i), - AHC_SYNCRATE_ULTRA3); - } - else if (p->features & AHC_ULTRA2) - { - p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2; - p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i); - scsirate = (sc->device_flags[i] & CFXFER) | - ((p->ultraenb & mask) ? 0x18 : 0x10); - p->transinfo[i].user_options = 0; - p->transinfo[i].cur_options = 0; - p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate, - AHC_SYNCRATE_ULTRA2); - p->transinfo[i].cur_period = aic7xxx_find_period(p, - aic_inb(p, TARG_SCSIRATE + i), - AHC_SYNCRATE_ULTRA2); - } - else - { - scsirate = (sc->device_flags[i] & CFXFER) << 4; - p->transinfo[i].user_options = 0; - p->transinfo[i].cur_options = 0; - p->transinfo[i].user_offset = MAX_OFFSET_8BIT; - if (p->features & AHC_ULTRA) - { - short ultraenb; - ultraenb = aic_inb(p, ULTRA_ENB) | - (aic_inb(p, ULTRA_ENB + 1) << 8); - p->transinfo[i].user_period = aic7xxx_find_period(p, - scsirate, - (p->ultraenb & mask) ? - AHC_SYNCRATE_ULTRA : - AHC_SYNCRATE_FAST); - p->transinfo[i].cur_period = aic7xxx_find_period(p, - aic_inb(p, TARG_SCSIRATE + i), - (ultraenb & mask) ? - AHC_SYNCRATE_ULTRA : - AHC_SYNCRATE_FAST); - } - else - p->transinfo[i].user_period = aic7xxx_find_period(p, - scsirate, AHC_SYNCRATE_FAST); - } - p->needsdtr_copy |= mask; - } - if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) ) - { - p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_16_BIT; - p->needwdtr_copy |= mask; - } - else - { - p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_8_BIT; - p->needwdtr_copy &= ~mask; - } - p->transinfo[i].cur_width = - (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) ? - MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT; - } - aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB); - aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1); - p->needppr = p->needppr_copy = p->needdv = 0; - p->needwdtr = p->needwdtr_copy; - p->needsdtr = p->needsdtr_copy; - p->dtr_pending = 0; - - /* - * We set the p->ultraenb from the SEEPROM to begin with, but now we make - * it match what is already down in the card. If we are doing a reset - * on the card then this will get put back to a default state anyway. - * This allows us to not have to pre-emptively negotiate when using the - * no_reset option. - */ - if (p->features & AHC_ULTRA) - p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8); - - - scsi_conf = (p->scsi_id & HSCSIID); - - if(have_seeprom) - { - p->adapter_control = sc->adapter_control; - p->bios_control = sc->bios_control; - - switch (p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - if (p->adapter_control & CFBPRIMARY) - p->flags |= AHC_CHANNEL_B_PRIMARY; - default: - break; - } - - if (sc->adapter_control & CFSPARITY) - scsi_conf |= ENSPCHK; - } - else - { - scsi_conf |= ENSPCHK | RESET_SCSI; - } - - /* - * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card. - * The 2842 and 2742 cards already have these registers set and we don't - * want to muck with them since we don't set all the bits they do. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) - { - /* Set the host ID */ - aic_outb(p, scsi_conf, SCSICONF); - /* In case we are a wide card */ - aic_outb(p, p->scsi_id, SCSICONF + 1); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_detect - * - * Description: - * Try to detect and register an Adaptec 7770 or 7870 SCSI controller. - * - * XXX - This should really be called aic7xxx_probe(). A sequence of - * probe(), attach()/detach(), and init() makes more sense than - * one do-it-all function. This may be useful when (and if) the - * mid-level SCSI code is overhauled. - *-F*************************************************************************/ -int -aic7xxx_detect(Scsi_Host_Template *template) -{ - struct aic7xxx_host *temp_p = NULL; - struct aic7xxx_host *current_p = NULL; - struct aic7xxx_host *list_p = NULL; - int found = 0; -#if defined(__i386__) || defined(__alpha__) - ahc_flag_type flags = 0; - int type; -#endif - unsigned char sxfrctl1; -#if defined(__i386__) || defined(__alpha__) - unsigned char hcntrl, hostconf; - unsigned int slot, base; -#endif - -#ifdef MODULE - /* - * If we are called as a module, the aic7xxx pointer may not be null - * and it would point to our bootup string, just like on the lilo - * command line. IF not NULL, then process this config string with - * aic7xxx_setup - */ - if(aic7xxx) - aic7xxx_setup(aic7xxx); - if(dummy_buffer[0] != 'P') - printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers" - "/scsi/README.aic7xxx\n" - "aic7xxx: to see the proper way to specify options to the aic7xxx " - "module\n" - "aic7xxx: Specifically, don't use any commas when passing arguments to\n" - "aic7xxx: insmod or else it might trash certain memory areas.\n"); -#endif - - template->proc_name = "aic7xxx"; - template->sg_tablesize = AIC7XXX_MAX_SG; - - -#ifdef CONFIG_PCI - /* - * PCI-bus probe. - */ - if (pci_present()) - { - struct - { - unsigned short vendor_id; - unsigned short device_id; - ahc_chip chip; - ahc_flag_type flags; - ahc_feature features; - int board_name_index; - unsigned short seeprom_size; - unsigned short seeprom_type; - } const aic_pdevs[] = { - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE, - AHC_FNONE, AHC_FENONE, 1, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850, - AHC_PAGESCBS, AHC_AIC7850_FE, 5, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850, - AHC_PAGESCBS, AHC_AIC7850_FE, 6, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 8, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7870_FE, 9, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 10, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7870_FE, 11, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7870_FE, 12, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 13, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7880_FE, 14, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 15, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7880_FE, 16, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7880_FE, 17, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7895_FE, 20, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 21, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 21, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 22, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 23, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 24, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 25, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 26, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN, - AHC_AIC7860_FE, 27, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - }; - - unsigned short command; - unsigned int devconfig, i, oldverbose; - struct pci_dev *pdev = NULL; - - for (i = 0; i < NUMBER(aic_pdevs); i++) - { - pdev = NULL; - while ((pdev = pci_find_device(aic_pdevs[i].vendor_id, - aic_pdevs[i].device_id, - pdev))) { - if (pci_enable_device(pdev)) - continue; - if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */ - { - if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2)) - { - printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not " - "supported by\n"); - printk(KERN_INFO " this driver, we are ignoring it.\n"); - } - } - else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host), - GFP_ATOMIC)) != NULL ) - { - memset(temp_p, 0, sizeof(struct aic7xxx_host)); - temp_p->chip = aic_pdevs[i].chip | AHC_PCI; - temp_p->flags = aic_pdevs[i].flags; - temp_p->features = aic_pdevs[i].features; - temp_p->board_name_index = aic_pdevs[i].board_name_index; - temp_p->sc_size = aic_pdevs[i].seeprom_size; - temp_p->sc_type = aic_pdevs[i].seeprom_type; - - /* - * Read sundry information from PCI BIOS. - */ - temp_p->irq = pdev->irq; - temp_p->pdev = pdev; - temp_p->pci_bus = pdev->bus->number; - temp_p->pci_device_fn = pdev->devfn; - temp_p->base = pci_resource_start(pdev, 0); - temp_p->mbase = pci_resource_start(pdev, 1); - current_p = list_p; - while(current_p && temp_p) - { - if ( ((current_p->pci_bus == temp_p->pci_bus) && - (current_p->pci_device_fn == temp_p->pci_device_fn)) || - (temp_p->base && (current_p->base == temp_p->base)) || - (temp_p->mbase && (current_p->mbase == temp_p->mbase)) ) - { - /* duplicate PCI entry, skip it */ - kfree(temp_p); - temp_p = NULL; - } - current_p = current_p->next; - } - if ( temp_p == NULL ) - continue; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at PCI %d/%d\n", - board_names[aic_pdevs[i].board_name_index], - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); - pci_read_config_word(pdev, PCI_COMMAND, &command); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n", - (int)command); - } -#ifdef AIC7XXX_STRICT_PCI_SETUP - command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | - PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -#else - command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -#endif - command &= ~PCI_COMMAND_INVALIDATE; - if (aic7xxx_pci_parity == 0) - command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); - pci_write_config_word(pdev, PCI_COMMAND, command); -#ifdef AIC7XXX_STRICT_PCI_SETUP - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig); - } - devconfig |= 0x80000040; - pci_write_config_dword(pdev, DEVCONFIG, devconfig); -#endif /* AIC7XXX_STRICT_PCI_SETUP */ - - if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG)) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: I/O ports already in use, ignoring.\n"); - kfree(temp_p); - temp_p = NULL; - continue; - } - - temp_p->unpause = INTEN; - temp_p->pause = temp_p->unpause | PAUSE; - if ( ((temp_p->base == 0) && - (temp_p->mbase == 0)) || - (temp_p->irq == 0) ) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); - kfree(temp_p); - temp_p = NULL; - continue; - } - -#ifdef MMAPIO - if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) || - ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) && - (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) ) - { - unsigned long page_offset, base; - - base = temp_p->mbase & PAGE_MASK; - page_offset = temp_p->mbase - base; - temp_p->maddr = ioremap_nocache(base, page_offset + 256); - if(temp_p->maddr) - { - temp_p->maddr += page_offset; - /* - * We need to check the I/O with the MMAPed address. Some machines - * simply fail to work with MMAPed I/O and certain controllers. - */ - if(aic_inb(temp_p, HCNTRL) == 0xff) - { - /* - * OK.....we failed our test....go back to programmed I/O - */ - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to " - "Programmed I/O.\n"); - iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK)); - temp_p->maddr = 0; - if(temp_p->base == 0) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); - kfree(temp_p); - temp_p = NULL; - continue; - } - } - } - } -#endif - - /* - * Lock out other contenders for our i/o space. - */ - if(temp_p->base) - request_region(temp_p->base, MAXREG - MINREG, "aic7xxx"); - - /* - * We HAVE to make sure the first pause_sequencer() and all other - * subsequent I/O that isn't PCI config space I/O takes place - * after the MMAPed I/O region is configured and tested. The - * problem is the PowerPC architecture that doesn't support - * programmed I/O at all, so we have to have the MMAP I/O set up - * for this pause to even work on those machines. - */ - pause_sequencer(temp_p); - - /* - * Clear out any pending PCI error status messages. Also set - * verbose to 0 so that we don't emit strange PCI error messages - * while cleaning out the current status bits. - */ - oldverbose = aic7xxx_verbose; - aic7xxx_verbose = 0; - aic7xxx_pci_intr(temp_p); - aic7xxx_verbose = oldverbose; - - temp_p->bios_address = 0; - - /* - * Remember how the card was setup in case there is no seeprom. - */ - if (temp_p->features & AHC_ULTRA2) - temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID; - else - temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID; - /* - * Get current termination setting - */ - sxfrctl1 = aic_inb(temp_p, SXFRCTL1); - - if (aic7xxx_chip_reset(temp_p) == -1) - { - release_region(temp_p->base, MAXREG - MINREG); - kfree(temp_p); - temp_p = NULL; - continue; - } - /* - * Very quickly put the term setting back into the register since - * the chip reset may cause odd things to happen. This is to keep - * LVD busses with lots of drives from draining the power out of - * the diffsense line before we get around to running the - * configure_termination() function. Also restore the STPWLEVEL - * bit of DEVCONFIG - */ - aic_outb(temp_p, sxfrctl1, SXFRCTL1); - pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig); - sxfrctl1 &= STPWEN; - - /* - * We need to set the CHNL? assignments before loading the SEEPROM - * The 3940 and 3985 cards (original stuff, not any of the later - * stuff) are 7870 and 7880 class chips. The Ultra2 stuff falls - * under 7896 and 7897. The 7895 is in a class by itself :) - */ - switch (temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7870: /* 3840 / 3985 */ - case AHC_AIC7880: /* 3840 UW / 3985 UW */ - if(temp_p->flags & AHC_MULTI_CHANNEL) - { - switch(PCI_SLOT(temp_p->pci_device_fn)) - { - case 5: - temp_p->flags |= AHC_CHNLB; - break; - case 8: - temp_p->flags |= AHC_CHNLB; - break; - case 12: - temp_p->flags |= AHC_CHNLC; - break; - default: - break; - } - } - break; - - case AHC_AIC7895: /* 7895 */ - case AHC_AIC7896: /* 7896/7 */ - case AHC_AIC7899: /* 7899 */ - if (PCI_FUNC(pdev->devfn) != 0) - { - temp_p->flags |= AHC_CHNLB; - } - /* - * The 7895 is the only chipset that sets the SCBSIZE32 param - * in the DEVCONFIG register. The Ultra2 chipsets use - * the DSCOMMAND0 register instead. - */ - if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) - { - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - devconfig |= SCBSIZE32; - pci_write_config_dword(pdev, DEVCONFIG, devconfig); - } - break; - default: - break; - } - - /* - * Loading of the SEEPROM needs to come after we've set the flags - * to indicate possible CHNLB and CHNLC assigments. Otherwise, - * on 394x and 398x cards we'll end up reading the wrong settings - * for channels B and C - */ - switch (temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7892: - case AHC_AIC7899: - aic_outb(temp_p, 0, SCAMCTL); - /* - * Switch to the alt mode of the chip... - */ - aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT); - /* - * Set our options...the last two items set our CRC after x byte - * count in target mode... - */ - aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE); - aic_outb(temp_p, 0x00, 0x0b); - aic_outb(temp_p, 0x10, 0x0a); - /* - * switch back to normal mode... - */ - aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT); - aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN | - TARGCRCENDEN | TARGCRCCNTEN, - CRCCONTROL1); - aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 | - MPARCKEN | CIOPARCKEN | CACHETHEN) & - ~DPARCKEN), DSCOMMAND0); - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7890: - case AHC_AIC7896: - aic_outb(temp_p, 0, SCAMCTL); - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN | USCBSIZE32 | - CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0); - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7850: - case AHC_AIC7860: - /* - * Set the DSCOMMAND0 register on these cards different from - * on the 789x cards. Also, read the SEEPROM as well. - */ - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN) & ~DPARCKEN, - DSCOMMAND0); - /* FALLTHROUGH */ - default: - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7880: - /* - * Check the rev of the chipset before we change DSCOMMAND0 - */ - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if ((devconfig & 0xff) >= 1) - { - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN) & ~DPARCKEN, - DSCOMMAND0); - } - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - } - - - /* - * and then we need another switch based on the type in order to - * make sure the channel B primary flag is set properly on 7895 - * controllers....Arrrgggghhh!!! We also have to catch the fact - * that when you disable the BIOS on the 7895 on the Intel DK440LX - * motherboard, and possibly others, it only sets the BIOS disabled - * bit on the A channel...I think I'm starting to lean towards - * going postal.... - */ - switch(temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - current_p = list_p; - while(current_p != NULL) - { - if ( (current_p->pci_bus == temp_p->pci_bus) && - (PCI_SLOT(current_p->pci_device_fn) == - PCI_SLOT(temp_p->pci_device_fn)) ) - { - if ( PCI_FUNC(current_p->pci_device_fn) == 0 ) - { - temp_p->flags |= - (current_p->flags & AHC_CHANNEL_B_PRIMARY); - temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS); - temp_p->flags |= - (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS)); - } - else - { - current_p->flags |= - (temp_p->flags & AHC_CHANNEL_B_PRIMARY); - current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS); - current_p->flags |= - (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS)); - } - } - current_p = current_p->next; - } - break; - default: - break; - } - - /* - * We only support external SCB RAM on the 7895/6/7 chipsets. - * We could support it on the 7890/1 easy enough, but I don't - * know of any 7890/1 based cards that have it. I do know - * of 7895/6/7 cards that have it and they work properly. - */ - switch(temp_p->chip & AHC_CHIPID_MASK) - { - default: - break; - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if (temp_p->features & AHC_ULTRA2) - { - if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) && - (aic7xxx_scbram) ) - { - aic_outb(temp_p, - aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2, - DSCOMMAND0); - temp_p->flags |= AHC_EXTERNAL_SRAM; - devconfig |= EXTSCBPEN; - } - else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) - { - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: external SCB RAM detected, " - "but not enabled\n"); - } - } - else - { - if ((devconfig & RAMPSM) && (aic7xxx_scbram)) - { - devconfig &= ~SCBRAMSEL; - devconfig |= EXTSCBPEN; - temp_p->flags |= AHC_EXTERNAL_SRAM; - } - else if (devconfig & RAMPSM) - { - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: external SCB RAM detected, " - "but not enabled\n"); - } - } - pci_write_config_dword(pdev, DEVCONFIG, devconfig); - if ( (temp_p->flags & AHC_EXTERNAL_SRAM) && - (temp_p->flags & AHC_CHNLB) ) - aic_outb(temp_p, 1, CCSCBBADDR); - break; - } - - /* - * Take the LED out of diagnostic mode - */ - aic_outb(temp_p, - (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)), - SBLKCTL); - - /* - * We don't know where this is set in the SEEPROM or by the - * BIOS, so we default to 100%. On Ultra2 controllers, use 75% - * instead. - */ - if (temp_p->features & AHC_ULTRA2) - { - aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH); - } - else - { - aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS); - } - - if ( list_p == NULL ) - { - list_p = current_p = temp_p; - } - else - { - current_p = list_p; - while(current_p->next != NULL) - current_p = current_p->next; - current_p->next = temp_p; - } - temp_p->next = NULL; - found++; - } /* Found an Adaptec PCI device. */ - else /* Well, we found one, but we couldn't get any memory */ - { - printk("aic7xxx: Found <%s>\n", - board_names[aic_pdevs[i].board_name_index]); - printk(KERN_INFO "aic7xxx: Unable to allocate device memory, " - "skipping.\n"); - } - } /* while(pdev=....) */ - } /* for PCI_DEVICES */ - } /* PCI BIOS present */ -#endif CONFIG_PCI - -#if defined(__i386__) || defined(__alpha__) - /* - * EISA/VL-bus card signature probe. - */ - slot = MINSLOT; - while ( (slot <= MAXSLOT) && - !(aic7xxx_no_probe) ) - { - base = SLOTBASE(slot) + MINREG; - - if (check_region(base, MAXREG - MINREG)) - { - /* - * Some other driver has staked a - * claim to this i/o region already. - */ - slot++; - continue; /* back to the beginning of the for loop */ - } - flags = 0; - type = aic7xxx_probe(slot, base + AHC_HID0, &flags); - if (type == -1) - { - slot++; - continue; - } - temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC); - if (temp_p == NULL) - { - printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n"); - slot++; - continue; /* back to the beginning of the while loop */ - } - /* - * Lock out other contenders for our i/o space. - */ - request_region(base, MAXREG - MINREG, "aic7xxx"); - - /* - * Pause the card preserving the IRQ type. Allow the operator - * to override the IRQ trigger. - */ - if (aic7xxx_irq_trigger == 1) - hcntrl = IRQMS; /* Level */ - else if (aic7xxx_irq_trigger == 0) - hcntrl = 0; /* Edge */ - else - hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */ - memset(temp_p, 0, sizeof(struct aic7xxx_host)); - temp_p->unpause = hcntrl | INTEN; - temp_p->pause = hcntrl | PAUSE | INTEN; - temp_p->base = base; - temp_p->mbase = 0; - temp_p->maddr = 0; - temp_p->pci_bus = 0; - temp_p->pci_device_fn = slot; - aic_outb(temp_p, hcntrl | PAUSE, HCNTRL); - while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ; - if (aic7xxx_chip_reset(temp_p) == -1) - temp_p->irq = 0; - else - temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F; - temp_p->flags |= AHC_PAGESCBS; - - switch (temp_p->irq) - { - case 9: - case 10: - case 11: - case 12: - case 14: - case 15: - break; - - default: - printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ " - "level %d, ignoring.\n", temp_p->irq); - kfree(temp_p); - release_region(base, MAXREG - MINREG); - slot++; - continue; /* back to the beginning of the while loop */ - } - - /* - * We are commited now, everything has been checked and this card - * has been found, now we just set it up - */ - - /* - * Insert our new struct into the list at the end - */ - if (list_p == NULL) - { - list_p = current_p = temp_p; - } - else - { - current_p = list_p; - while (current_p->next != NULL) - current_p = current_p->next; - current_p->next = temp_p; - } - - switch (type) - { - case 0: - temp_p->board_name_index = 2; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at EISA %d\n", - board_names[2], slot); - /* FALLTHROUGH */ - case 1: - { - temp_p->chip = AHC_AIC7770 | AHC_EISA; - temp_p->features |= AHC_AIC7770_FE; - temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL); - - /* - * Get the primary channel information. Right now we don't - * do anything with this, but someday we will be able to inform - * the mid-level SCSI code which channel is primary. - */ - if (temp_p->board_name_index == 0) - { - temp_p->board_name_index = 3; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at EISA %d\n", - board_names[3], slot); - } - if (temp_p->bios_control & CHANNEL_B_PRIMARY) - { - temp_p->flags |= AHC_CHANNEL_B_PRIMARY; - } - - if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED) - { - temp_p->flags &= ~AHC_BIOS_ENABLED; - } - else - { - temp_p->flags &= ~AHC_USEDEFAULTS; - temp_p->flags |= AHC_BIOS_ENABLED; - if ( (temp_p->bios_control & 0x20) == 0 ) - { - temp_p->bios_address = 0xcc000; - temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07)); - } - else - { - temp_p->bios_address = 0xd0000; - temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06)); - } - } - temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8; - temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1); - if (temp_p->features & AHC_WIDE) - { - temp_p->scsi_id = temp_p->adapter_control & HWSCSIID; - temp_p->scsi_id_b = temp_p->scsi_id; - } - else - { - temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID; - temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID; - } - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - } - - case 2: - case 3: - temp_p->chip = AHC_AIC7770 | AHC_VL; - temp_p->features |= AHC_AIC7770_FE; - if (type == 2) - temp_p->flags |= AHC_BIOS_ENABLED; - else - temp_p->flags &= ~AHC_BIOS_ENABLED; - if (aic_inb(temp_p, SCSICONF) & TERM_ENB) - sxfrctl1 = STPWEN; - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - temp_p->board_name_index = 4; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at VLB %d\n", - board_names[2], slot); - switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL ) - { - case 0x00: - temp_p->bios_address = 0xe0000; - break; - case 0x20: - temp_p->bios_address = 0xc8000; - break; - case 0x40: - temp_p->bios_address = 0xd0000; - break; - case 0x60: - temp_p->bios_address = 0xd8000; - break; - default: - break; /* can't get here */ - } - break; - - default: /* Won't get here. */ - break; - } - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n", - (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base, - temp_p->irq, - (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered"); - printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n", - (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis"); - } - - /* - * Set the FIFO threshold and the bus off time. - */ - hostconf = aic_inb(temp_p, HOSTCONF); - aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD); - aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME); - slot++; - found++; - } - -#endif /* defined(__i386__) || defined(__alpha__) */ - - /* - * Now, we re-order the probed devices by BIOS address and BUS class. - * In general, we follow this algorithm to make the adapters show up - * in the same order under linux that the computer finds them. - * 1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS - * address, going from lowest to highest. - * 2: All PCI controllers with BIOS_ENABLED next, according to BIOS - * address, going from lowest to highest. - * 3: Remaining VLB/EISA controllers going in slot order. - * 4: Remaining PCI controllers, going in PCI device order (reversable) - */ - - { - struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL }; - struct aic7xxx_host *vlb, *pci; - struct aic7xxx_host *prev_p; - struct aic7xxx_host *p; - unsigned char left; - - prev_p = vlb = pci = NULL; - - temp_p = list_p; - while (temp_p != NULL) - { - switch(temp_p->chip & ~AHC_CHIPID_MASK) - { - case AHC_EISA: - case AHC_VL: - { - p = temp_p; - if (p->flags & AHC_BIOS_ENABLED) - vlb = sort_list[0]; - else - vlb = sort_list[2]; - - if (vlb == NULL) - { - vlb = temp_p; - temp_p = temp_p->next; - vlb->next = NULL; - } - else - { - current_p = vlb; - prev_p = NULL; - while ( (current_p != NULL) && - (current_p->bios_address < temp_p->bios_address)) - { - prev_p = current_p; - current_p = current_p->next; - } - if (prev_p != NULL) - { - prev_p->next = temp_p; - temp_p = temp_p->next; - prev_p->next->next = current_p; - } - else - { - vlb = temp_p; - temp_p = temp_p->next; - vlb->next = current_p; - } - } - - if (p->flags & AHC_BIOS_ENABLED) - sort_list[0] = vlb; - else - sort_list[2] = vlb; - - break; - } - default: /* All PCI controllers fall through to default */ - { - - p = temp_p; - if (p->flags & AHC_BIOS_ENABLED) - pci = sort_list[1]; - else - pci = sort_list[3]; - - if (pci == NULL) - { - pci = temp_p; - temp_p = temp_p->next; - pci->next = NULL; - } - else - { - current_p = pci; - prev_p = NULL; - if (!aic7xxx_reverse_scan) - { - while ( (current_p != NULL) && - ( (PCI_SLOT(current_p->pci_device_fn) | - (current_p->pci_bus << 8)) < - (PCI_SLOT(temp_p->pci_device_fn) | - (temp_p->pci_bus << 8)) ) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - else - { - while ( (current_p != NULL) && - ( (PCI_SLOT(current_p->pci_device_fn) | - (current_p->pci_bus << 8)) > - (PCI_SLOT(temp_p->pci_device_fn) | - (temp_p->pci_bus << 8)) ) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - /* - * Are we dealing with a 7895/6/7/9 where we need to sort the - * channels as well, if so, the bios_address values should - * be the same - */ - if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) && - (temp_p->pci_bus == current_p->pci_bus) && - (PCI_SLOT(temp_p->pci_device_fn) == - PCI_SLOT(current_p->pci_device_fn)) ) - { - if (temp_p->flags & AHC_CHNLB) - { - if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - else - { - if (temp_p->flags & AHC_CHANNEL_B_PRIMARY) - { - prev_p = current_p; - current_p = current_p->next; - } - } - } - if (prev_p != NULL) - { - prev_p->next = temp_p; - temp_p = temp_p->next; - prev_p->next->next = current_p; - } - else - { - pci = temp_p; - temp_p = temp_p->next; - pci->next = current_p; - } - } - - if (p->flags & AHC_BIOS_ENABLED) - sort_list[1] = pci; - else - sort_list[3] = pci; - - break; - } - } /* End of switch(temp_p->type) */ - } /* End of while (temp_p != NULL) */ - /* - * At this point, the cards have been broken into 4 sorted lists, now - * we run through the lists in order and register each controller - */ - { - int i; - - left = found; - for (i=0; iname = board_names[temp_p->board_name_index]; - p = aic7xxx_alloc(template, temp_p); - if (p != NULL) - { - p->instance = found - left; - if (aic7xxx_register(template, p, (--left)) == 0) - { - found--; - aic7xxx_release(p->host); - scsi_unregister(p->host); - } - else if (aic7xxx_dump_card) - { - pause_sequencer(p); - aic7xxx_print_card(p); - aic7xxx_print_scratch_ram(p); - unpause_sequencer(p, TRUE); - } - } - current_p = temp_p; - temp_p = (struct aic7xxx_host *)temp_p->next; - kfree(current_p); - } - } - } - } - return (found); -} - -static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, - Scsi_Cmnd *old_cmd, int tindex); - -/*+F************************************************************************* - * Function: - * aic7xxx_allocate_negotiation_command - * - * Description: - * allocate the actual command struct and fill in the gaps... - *-F*************************************************************************/ -static Scsi_Cmnd * -aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p, - Scsi_Cmnd *old_cmd, int tindex) -{ - Scsi_Cmnd *cmd; - char *buffer; - - if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) ) - { - return(NULL); - } - if (!(buffer = kmalloc(256, GFP_ATOMIC))) - { - kfree(p->dev_dtr_cmnd[tindex]); - p->dev_dtr_cmnd[tindex] = NULL; - return(NULL); - } - cmd = p->dev_dtr_cmnd[tindex]; - memset(cmd, 0, sizeof(Scsi_Cmnd)); - memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd)); - memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd)); - memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd)); - cmd->lun = 0; - cmd->request_bufflen = 255; - cmd->request_buffer = buffer; - cmd->sc_data_direction = SCSI_DATA_READ; - cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0; - cmd->bufflen = 0; - cmd->buffer = NULL; - cmd->underflow = 0; - cmd->cmd_len = 6; - cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY; - cmd->cmnd[1] = cmd->data_cmnd[1] = 0; - cmd->cmnd[2] = cmd->data_cmnd[2] = 0; - cmd->cmnd[3] = cmd->data_cmnd[3] = 0; - cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */ - cmd->cmnd[5] = cmd->data_cmnd[5] = 0; - return(cmd); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_negotiation_complete - * - * Description: - * Handle completion events for our Negotiation commands. Clear out the - * struct and get it ready for its next use. - *-F*************************************************************************/ -static void -aic7xxx_negotiation_complete(Scsi_Cmnd *cmd) -{ - unsigned int checksum; - int i; - int *ibuffer; - struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata; - int tindex = TARGET_INDEX(cmd); - struct aic7xxx_syncrate *syncrate; - - /* - * perform our minimalistic domain validation - */ - if(p->dev_flags[tindex] & DEVICE_SCANNED) - { - ibuffer = (int *)cmd->request_buffer; - checksum = 0; - for(i = 0; i < (cmd->request_bufflen >> 2); i++) - { - checksum += ibuffer[i]; - } - if( (checksum != p->dev_checksum[tindex]) && - (p->transinfo[tindex].cur_offset != 0) ) - { - unsigned int period = p->transinfo[tindex].cur_period; - unsigned char options = p->transinfo[tindex].cur_options; - - if (p->needdv & (1<host_no, CTL_OF_CMD(cmd)); - } - if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) - { - syncrate++; - if( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) - { - p->transinfo[tindex].goal_period = syncrate->period; - if( p->transinfo[tindex].goal_period > 9 ) - { - p->transinfo[tindex].goal_options = 0; - p->needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_width) - { - p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width) - { - p->transinfo[tindex].goal_width = 0; - p->needwdtr &= ~(1<needwdtr_copy &= ~(1<transinfo[tindex].goal_offset = - p->transinfo[tindex].user_offset; - p->transinfo[tindex].goal_period = - p->transinfo[tindex].user_period; - p->transinfo[tindex].goal_options = - p->transinfo[tindex].user_options; - if( p->transinfo[tindex].goal_period <= 9 ) - { - p->needppr |= (1<needsdtr &= ~(1<needppr_copy |= (1<needsdtr_copy &= ~(1<needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_offset = 0; - p->transinfo[tindex].goal_period = 255; - p->transinfo[tindex].goal_options = 0; - p->transinfo[tindex].goal_width = 0; - p->needppr &= ~(1<needsdtr &= ~(1<needwdtr &= ~(1<needppr_copy &= ~(1<needsdtr_copy &= ~(1<needwdtr_copy &= ~(1<needdv &= ~(1<host_no, CTL_OF_CMD(cmd)); - } - /* - * Update the checksum in case the INQUIRY data has changed, maybe - * in relation to a change in the mode pages, or whatever. - */ - p->dev_checksum[tindex] = checksum; - /* - * Signal that we are trying out the domain validation - */ - p->needdv |= (1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<needwdtr |= (p->needwdtr_copy & (1<needdv & (1<host_no, CTL_OF_CMD(cmd)); - } - /* - * We successfully did our checksum, so don't leave the needdv flag set - * in case we might have set it last time through. - */ - p->needdv &= ~(1<dtr_pending &= ~(0x01 << tindex); - /* - * This looks recursive in the extreme, but if this was a WDTR negotiation - * and we didn't follow up with SDTR yet, then this will get it started. - * For all other cases, this should work out to be a no-op, unless we are - * doing domain validation and happen to need a new negotiation command. - * - * In case we don't want this to go any further, the cmdcmplt interrupt - * handler will NULL out the cmd->next entry so that the real SCSI command - * can be sent back to the mid layer code with SENSE data intact. We'll - * finish things up when the cmd gets sent back down to us, so no worries. - */ - if(cmd->next) - { - aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex); - } - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_build_negotiation_command - * - * Description: - * Build a Scsi_Cmnd structure to perform negotiation with or else send - * a pre-built command specifically for this purpose. - *-F*************************************************************************/ -static void -aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd, - int tindex) -{ - - if ( !(p->dtr_pending & (1<needppr & (1<needwdtr & (1<needsdtr & (1<dev_dtr_cmnd[tindex] == NULL) && - (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) ) - { - return; - } - /* - * Before sending this thing out, we also make the cmd->next pointer - * point to the real command so we can stuff any possible SENSE data - * into the real command instead of this fake command. This has to be - * done each time the command is built, not just the first time, hence - * it's outside of the above if()... - */ - p->dev_dtr_cmnd[tindex]->next = old_cmd; - /* - * Clear the buffer so checksums come out right.... - */ - memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0, - p->dev_dtr_cmnd[tindex]->request_bufflen); - /* - * Remove any commands for this particular device that might be on the - * waiting_scbs queue or qinfifo so that this command goes out first. - * This is vital for our implementation of domain validation. - */ - pause_sequencer(p); - aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS, - SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]); - unpause_sequencer(p, FALSE); - { - struct aic7xxx_scb *scb, *next; - - scb = p->waiting_scbs.head; - while(scb != NULL) - { - if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel, - ALL_LUNS, SCB_LIST_NULL) ) - { - next = scb->q_next; - scbq_remove(&p->waiting_scbs, scb); - scbq_insert_tail(&p->delayed_scbs[tindex], scb); - scb = next; - } - else - { - scb = scb->q_next; - } - } - } - aic7xxx_queue(p->dev_dtr_cmnd[tindex], - aic7xxx_negotiation_complete); - } -} - -#ifdef AIC7XXX_VERBOSE_DEBUGGING -/*+F************************************************************************* - * Function: - * aic7xxx_print_scb - * - * Description: - * Dump the byte codes for an about to be sent SCB. - *-F*************************************************************************/ -static void -aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - int i; - unsigned char *x; - - x = (unsigned char *)&scb->hscb->control; - - for(i=0; i<32; i++) - { - printk("%02x ", x[i]); - } - printk("\n"); -} -#endif - -/*+F************************************************************************* - * Function: - * aic7xxx_buildscb - * - * Description: - * Build a SCB. - *-F*************************************************************************/ -static void -aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, - struct aic7xxx_scb *scb) -{ - unsigned short mask; - struct aic7xxx_hwscb *hscb; - unsigned char tindex = TARGET_INDEX(cmd); - - mask = (0x01 << tindex); - hscb = scb->hscb; - - /* - * Setup the control byte if we need negotiation and have not - * already requested it. - */ - hscb->control = 0; - scb->tag_action = 0; - cmd->tag = hscb->tag; - if (p->discenable & mask) - { - hscb->control |= DISCENB; - if ( (p->tagenable & mask) && - (cmd->cmnd[0] != TEST_UNIT_READY) ) - { - p->dev_commands_sent[tindex]++; - if (p->dev_commands_sent[tindex] < 200) - { - hscb->control |= MSG_SIMPLE_Q_TAG; - scb->tag_action = MSG_SIMPLE_Q_TAG; - } - else - { - if (p->orderedtag & mask) - { - hscb->control |= MSG_ORDERED_Q_TAG; - scb->tag_action = MSG_ORDERED_Q_TAG; - } - else - { - hscb->control |= MSG_SIMPLE_Q_TAG; - scb->tag_action = MSG_SIMPLE_Q_TAG; - } - p->dev_commands_sent[tindex] = 0; - } - } - } - if ( cmd == p->dev_dtr_cmnd[tindex] ) - { - p->dtr_pending |= mask; - scb->tag_action = 0; - if (p->dev_flags[tindex] & DEVICE_SCANNED) - { - hscb->control &= DISCENB; - hscb->control |= MK_MESSAGE; - if(p->needppr & mask) - { - scb->flags |= SCB_MSGOUT_PPR; - } - else if(p->needwdtr & mask) - { - scb->flags |= SCB_MSGOUT_WDTR; - } - else if(p->needsdtr & mask) - { - scb->flags |= SCB_MSGOUT_SDTR; - } - } - } - if ( !(p->dtr_pending & mask) && - ( (p->needppr & mask) || - (p->needwdtr & mask) || - (p->needsdtr & mask) ) ) - { - aic7xxx_build_negotiation_cmnd(p, cmd, tindex); - } - hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) | - ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07); - - /* - * The interpretation of request_buffer and request_bufflen - * changes depending on whether or not use_sg is zero; a - * non-zero use_sg indicates the number of elements in the - * scatter-gather array. - */ - - /* - * XXX - this relies on the host data being stored in a - * little-endian format. - */ - hscb->SCSI_cmd_length = cmd->cmd_len; - memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len); - hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd)); - - if (cmd->use_sg) - { - struct scatterlist *sg; /* Must be mid-level SCSI code scatterlist */ - - /* - * We must build an SG list in adapter format, as the kernel's SG list - * cannot be used directly because of data field size (__alpha__) - * differences and the kernel SG list uses virtual addresses where - * we need physical addresses. - */ - int i, use_sg; - - sg = (struct scatterlist *)cmd->request_buffer; - scb->sg_length = 0; - use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction)); - /* - * Copy the segments into the SG array. NOTE!!! - We used to - * have the first entry both in the data_pointer area and the first - * SG element. That has changed somewhat. We still have the first - * entry in both places, but now we download the address of - * scb->sg_list[1] instead of 0 to the sg pointer in the hscb. - */ - for (i = 0; i < use_sg; i++) - { - unsigned int len = sg_dma_len(sg+i); - scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i)); - scb->sg_list[i].length = cpu_to_le32(len); - scb->sg_length += len; - } - /* Copy the first SG into the data pointer area. */ - hscb->data_pointer = scb->sg_list[0].address; - hscb->data_count = scb->sg_list[0].length; - scb->sg_count = i; - hscb->SG_segment_count = i; - hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1])); - } - else - { - if (cmd->request_bufflen) - { - unsigned int address = pci_map_single(p->pdev, cmd->request_buffer, - cmd->request_bufflen, - scsi_to_pci_dma_dir(cmd->sc_data_direction)); - aic7xxx_mapping(cmd) = address; - scb->sg_list[0].address = cpu_to_le32(address); - scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen); - scb->sg_count = 1; - scb->sg_length = cmd->request_bufflen; - hscb->SG_segment_count = 1; - hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0])); - hscb->data_count = scb->sg_list[0].length; - hscb->data_pointer = scb->sg_list[0].address; - } - else - { - scb->sg_count = 0; - scb->sg_length = 0; - hscb->SG_segment_count = 0; - hscb->SG_list_pointer = 0; - hscb->data_count = 0; - hscb->data_pointer = 0; - } - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_queue - * - * Description: - * Queue a SCB to the controller. - *-F*************************************************************************/ -int -aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) -{ - struct aic7xxx_host *p; - struct aic7xxx_scb *scb; -#ifdef AIC7XXX_VERBOSE_DEBUGGING - int tindex = TARGET_INDEX(cmd); -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned long cpu_flags = 0; -#endif - - p = (struct aic7xxx_host *) cmd->host->hostdata; - /* - * Check to see if channel was scanned. - */ - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0)) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(INFO_LEAD "Scanning channel for devices.\n", - p->host_no, 0, -1, -1); - p->flags |= AHC_A_SCANNED; - } - else - { - if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1)) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(INFO_LEAD "Scanning channel for devices.\n", - p->host_no, 1, -1, -1); - p->flags |= AHC_B_SCANNED; - } - } - - if (p->dev_active_cmds[tindex] > (cmd->device->queue_depth + 1)) - { - printk(WARN_LEAD "Commands queued exceeds queue " - "depth, active=%d\n", - p->host_no, CTL_OF_CMD(cmd), - p->dev_active_cmds[tindex]); - if ( p->dev_active_cmds[tindex] > 220 ) - p->dev_active_cmds[tindex] = 0; - } -#endif - - scb = scbq_remove_head(&p->scb_data->free_scbs); - if (scb == NULL) - { - DRIVER_LOCK - aic7xxx_allocate_scb(p); - DRIVER_UNLOCK - scb = scbq_remove_head(&p->scb_data->free_scbs); - } - if (scb == NULL) - { - printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, - CTL_OF_CMD(cmd)); - cmd->result = (DID_BUS_BUSY << 16); - DRIVER_LOCK - aic7xxx_queue_cmd_complete(p, cmd); - DRIVER_UNLOCK - return 0; - } - else - { - scb->cmd = cmd; - aic7xxx_position(cmd) = scb->hscb->tag; - - /* - * Construct the SCB beforehand, so the sequencer is - * paused a minimal amount of time. - */ - aic7xxx_buildscb(p, cmd, scb); - - /* - * Make sure the Scsi_Cmnd pointer is saved, the struct it points to - * is set up properly, and the parity error flag is reset, then send - * the SCB to the sequencer and watch the fun begin. - */ - cmd->scsi_done = fn; - cmd->result = DID_OK; - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - aic7xxx_error(cmd) = DID_OK; - aic7xxx_status(cmd) = 0; - cmd->host_scribble = NULL; - - scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; - - DRIVER_LOCK - scbq_insert_tail(&p->waiting_scbs, scb); - if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0) - { - aic7xxx_run_waiting_queues(p); - } - DRIVER_UNLOCK - } - return (0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_bus_device_reset - * - * Description: - * Abort or reset the current SCSI command(s). If the scb has not - * previously been aborted, then we attempt to send a BUS_DEVICE_RESET - * message to the target. If the scb has previously been unsuccessfully - * aborted, then we will reset the channel and have all devices renegotiate. - * Returns an enumerated type that indicates the status of the operation. - *-F*************************************************************************/ -static int -aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd) -{ - struct aic7xxx_scb *scb; - struct aic7xxx_hwscb *hscb; - int result = -1; - int channel; - unsigned char saved_scbptr, lastphase; - unsigned char hscb_index; - int disconnected; - - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - hscb = scb->hscb; - - lastphase = aic_inb(p, LASTPHASE); - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - { - printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ", - p->host_no, CTL_OF_SCB(scb), scb->flags); - switch (lastphase) - { - case P_DATAOUT: - printk("Data-Out phase\n"); - break; - case P_DATAIN: - printk("Data-In phase\n"); - break; - case P_COMMAND: - printk("Command phase\n"); - break; - case P_MESGOUT: - printk("Message-Out phase\n"); - break; - case P_STATUS: - printk("Status phase\n"); - break; - case P_MESGIN: - printk("Message-In phase\n"); - break; - default: - /* - * We're not in a valid phase, so assume we're idle. - */ - printk("while idle, LASTPHASE = 0x%x\n", lastphase); - break; - } - printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " - "0x%x\n", p->host_no, CTL_OF_SCB(scb), - aic_inb(p, SCSISIGI), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - } - - channel = cmd->channel; - - /* - * Send a Device Reset Message: - * The target that is holding up the bus may not be the same as - * the one that triggered this timeout (different commands have - * different timeout lengths). Our strategy here is to queue an - * abort message to the timed out target if it is disconnected. - * Otherwise, if we have an active target we stuff the message buffer - * with an abort message and assert ATN in the hopes that the target - * will let go of the bus and go to the mesgout phase. If this - * fails, we'll get another timeout a few seconds later which will - * attempt a bus reset. - */ - saved_scbptr = aic_inb(p, SCBPTR); - disconnected = FALSE; - - if (lastphase != P_BUSFREE) - { - if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs) - { - printk(WARN_LEAD "Invalid SCB ID %d is active, " - "SCB flags = 0x%x.\n", p->host_no, - CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags); - return(SCSI_RESET_ERROR); - } - if (scb->hscb->tag == aic_inb(p, SCB_TAG)) - { - if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Device reset message in " - "message buffer\n", p->host_no, CTL_OF_SCB(scb)); - scb->flags |= SCB_RESET | SCB_DEVICE_RESET; - aic7xxx_error(scb->cmd) = DID_RESET; - p->dev_flags[TARGET_INDEX(scb->cmd)] |= - BUS_DEVICE_RESET_PENDING; - /* Send the abort message to the active SCB. */ - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, lastphase | ATNO, SCSISIGO); - return(SCSI_RESET_PENDING); - } - else - { - /* We want to send out the message, but it could screw an already */ - /* in place and being used message. Instead, we return an error */ - /* to try and start the bus reset phase since this command is */ - /* probably hung (aborts failed, and now reset is failing). We */ - /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */ - /* any more on this device, but instead will escalate to a bus or */ - /* host reset (additionally, we won't try to abort any more). */ - printk(WARN_LEAD "Device reset, Message buffer " - "in use\n", p->host_no, CTL_OF_SCB(scb)); - scb->flags |= SCB_RESET | SCB_DEVICE_RESET; - aic7xxx_error(scb->cmd) = DID_RESET; - p->dev_flags[TARGET_INDEX(scb->cmd)] |= - BUS_DEVICE_RESET_PENDING; - return(SCSI_RESET_ERROR); - } - } - } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */ - hscb_index = aic7xxx_find_scb(p, scb); - if (hscb_index == SCB_LIST_NULL) - { - disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE; - } - else - { - aic_outb(p, hscb_index, SCBPTR); - if (aic_inb(p, SCB_CONTROL) & DISCONNECTED) - { - disconnected = TRUE; - } - } - if (disconnected) - { - /* - * Simply set the MK_MESSAGE flag and the SEQINT handler will do - * the rest on a reconnect. - */ - scb->hscb->control |= MK_MESSAGE; - scb->flags |= SCB_RESET | SCB_DEVICE_RESET; - p->dev_flags[TARGET_INDEX(scb->cmd)] |= - BUS_DEVICE_RESET_PENDING; - if (hscb_index != SCB_LIST_NULL) - { - unsigned char scb_control; - - aic_outb(p, hscb_index, SCBPTR); - scb_control = aic_inb(p, SCB_CONTROL); - aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL); - } - /* - * Actually requeue this SCB in case we can select the - * device before it reconnects. If the transaction we - * want to abort is not tagged, then this will be the only - * outstanding command and we can simply shove it on the - * qoutfifo and be done. If it is tagged, then it goes right - * in with all the others, no problem :) We need to add it - * to the qinfifo and let the sequencer know it is there. - * Now, the only problem left to deal with is, *IF* this - * command completes, in spite of the MK_MESSAGE bit in the - * control byte, then we need to pick that up in the interrupt - * routine and clean things up. This *shouldn't* ever happen. - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Queueing device reset " - "command.\n", p->host_no, CTL_OF_SCB(scb)); - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - scb->flags |= SCB_QUEUED_ABORT; - result = SCSI_RESET_PENDING; - } - else if (result == -1) - { - result = SCSI_RESET_ERROR; - } - aic_outb(p, saved_scbptr, SCBPTR); - return (result); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_panic_abort - * - * Description: - * Abort the current SCSI command(s). - *-F*************************************************************************/ -void -aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd) -{ - - printk("aic7xxx driver version %s/%s\n", AIC7XXX_C_VERSION, - UTS_RELEASE); - printk("Controller type:\n %s\n", board_names[p->board_name_index]); - printk("p->flags=0x%x, p->chip=0x%x, p->features=0x%x, " - "sequencer %s paused\n", - p->flags, p->chip, p->features, - (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" ); - pause_sequencer(p); - disable_irq(p->irq); - aic7xxx_print_card(p); - aic7xxx_print_scratch_ram(p); - spin_unlock_irq(&io_request_lock); - for(;;) barrier(); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_abort - * - * Description: - * Abort the current SCSI command(s). - *-F*************************************************************************/ -int -aic7xxx_abort(Scsi_Cmnd *cmd) -{ - struct aic7xxx_scb *scb = NULL; - struct aic7xxx_host *p; - int result, found=0; - unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned long cpu_flags = 0; -#endif - Scsi_Cmnd *cmd_next, *cmd_prev; - - p = (struct aic7xxx_host *) cmd->host->hostdata; - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - - /* - * I added a new config option to the driver: "panic_on_abort" that will - * cause the driver to panic and the machine to stop on the first abort - * or reset call into the driver. At that point, it prints out a lot of - * usefull information for me which I can then use to try and debug the - * problem. Simply enable the boot time prompt in order to activate this - * code. - */ - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, cmd); - - DRIVER_LOCK - -/* - * Run the isr to grab any command in the QOUTFIFO and any other misc. - * assundry tasks. This should also set up the bh handler if there is - * anything to be done, but it won't run until we are done here since - * we are following a straight code path without entering the scheduler - * code. - */ - pause_sequencer(p); - while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) - { - aic7xxx_isr(p->irq, p, (void *)NULL); - pause_sequencer(p); - aic7xxx_done_cmds_complete(p); - } - - if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout)) - /* Totally bogus cmd since it points beyond our */ - { /* valid SCB range or doesn't even match it's own*/ - /* timeout serial number. */ - if (aic7xxx_verbose & VERBOSE_ABORT_MID) - printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd " - "pointer.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_ABORT_NOT_RUNNING); - } - if (scb->cmd != cmd) /* Hmmm...either this SCB is currently free with a */ - { /* NULL cmd pointer (NULLed out when freed) or it */ - /* has already been recycled for another command */ - /* Either way, this SCB has nothing to do with this*/ - /* command and we need to deal with cmd without */ - /* touching the SCB. */ - /* The theory here is to return a value that will */ - /* make the queued for complete command actually */ - /* finish successfully, or to indicate that we */ - /* don't have this cmd any more and the mid level */ - /* code needs to find it. */ - cmd_next = p->completeq.head; - cmd_prev = NULL; - while (cmd_next != NULL) - { - if (cmd_next == cmd) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "Abort called for command " - "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd)); - if ( cmd_prev == NULL ) - p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble; - else - cmd_prev->host_scribble = cmd_next->host_scribble; - cmd_next->scsi_done(cmd_next); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful - * completion */ - } - cmd_prev = cmd_next; - cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; - } - if (aic7xxx_verbose & VERBOSE_ABORT_MID) - printk(INFO_LEAD "Abort called for already completed" - " command.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_ABORT_NOT_RUNNING); - } - -/* At this point we know the following: - * the SCB pointer is valid - * the command pointer passed in to us and the scb->cmd pointer match - * this then means that the command we need to abort is the same as the - * command held by the scb pointer and is a valid abort request. - * Now, we just have to figure out what to do from here. Current plan is: - * if we have already been here on this command, escalate to a reset - * if scb is on waiting list or QINFIFO, send it back as aborted, but - * we also need to be aware of the possibility that we could be using - * a faked negotiation command that is holding this command up, if - * so we need to take care of that command instead, which means we - * would then treat this one like it was sitting around disconnected - * instead. - * if scb is on WAITING_SCB list in sequencer, free scb and send back - * if scb is disconnected and not completed, abort with abort message - * if scb is currently running, then it may be causing the bus to hang - * so we want a return value that indicates a reset would be appropriate - * if the command does not finish shortly - * if scb is already complete but not on completeq, we're screwed because - * this can't happen (except if the command is in the QOUTFIFO, in which - * case we would like it to complete successfully instead of having to - * to be re-done) - * All other scenarios already dealt with by previous code. - */ - - if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) ) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB aborted once already, " - "escalating.\n", p->host_no, CTL_OF_SCB(scb)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_ABORT_SNOOZE); - } - if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || - (p->dev_flags[TARGET_INDEX(scb->cmd)] & - BUS_DEVICE_RESET_PENDING) ) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "Reset/Abort pending for this " - "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_ABORT_PENDING); - } - - found = 0; - p->flags |= AHC_IN_ABORT; - if (aic7xxx_verbose & VERBOSE_ABORT) - printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); - -/* - * First, let's check to see if the currently running command is our target - * since if it is, the return is fairly easy and quick since we don't want - * to touch the command in case it might complete, but we do want a timeout - * in case it's actually hung, so we really do nothing, but tell the mid - * level code to reset the timeout. - */ - - if ( scb->hscb->tag == aic_inb(p, SCB_TAG) ) - { - /* - * Check to see if the sequencer is just sitting on this command, or - * if it's actively being run. - */ - result = aic_inb(p, LASTPHASE); - switch (result) - { - case P_DATAOUT: /* For any of these cases, we can assume we are */ - case P_DATAIN: /* an active command and act according. For */ - case P_COMMAND: /* anything else we are going to fall on through*/ - case P_STATUS: /* The SCSI_ABORT_SNOOZE will give us two abort */ - case P_MESGOUT: /* chances to finish and then escalate to a */ - case P_MESGIN: /* reset call */ - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB is currently active. " - "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb)); - unpause_sequencer(p, FALSE); - p->flags &= ~AHC_IN_ABORT; - scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */ - p->flags |= AHC_ABORT_PENDING; /* here so we will know not to */ - DRIVER_UNLOCK /* muck with other SCBs if this */ - return(SCSI_ABORT_PENDING); /* one doesn't complete and clear */ - break; /* out. */ - default: - break; - } - } - - if ((found == 0) && (scb->flags & SCB_WAITINGQ)) - { - int tindex = TARGET_INDEX(cmd); - unsigned short mask; - - mask = (1 << tindex); - - if (p->dtr_pending & mask) - { - if (p->dev_dtr_cmnd[tindex]->next != cmd) - found = 1; - else - found = 0; - } - else - { - found = 1; - } - if (found == 0) - { - /* - * OK..this means the command we are currently getting an abort - * for has an outstanding negotiation command in front of it. - * We don't really have a way to tie back into the negotiation - * commands, so we just send this back as pending, then it - * will get reset in 2 seconds. - */ - unpause_sequencer(p, TRUE); - scb->flags |= SCB_ABORT; - DRIVER_UNLOCK - return(SCSI_ABORT_PENDING); - } - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB found on waiting list and " - "aborted.\n", p->host_no, CTL_OF_SCB(scb)); - scbq_remove(&p->waiting_scbs, scb); - scbq_remove(&p->delayed_scbs[tindex], scb); - p->dev_active_cmds[tindex]++; - p->activescbs++; - scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE); - scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE; - found = 1; - } - -/* - * We just checked the waiting_q, now for the QINFIFO - */ - if ( found == 0 ) - { - if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, - cmd->channel, - cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE, - FALSE, NULL)) != 0) && - (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)) - printk(INFO_LEAD "SCB found in QINFIFO and " - "aborted.\n", p->host_no, CTL_OF_SCB(scb)); - } - -/* - * QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card - */ - - if ( found == 0 ) - { - unsigned char scb_next_ptr; - prev_hscbptr = SCB_LIST_NULL; - saved_hscbptr = aic_inb(p, SCBPTR); - next_hscbptr = aic_inb(p, WAITING_SCBH); - while ( next_hscbptr != SCB_LIST_NULL ) - { - aic_outb(p, next_hscbptr, SCBPTR ); - if ( scb->hscb->tag == aic_inb(p, SCB_TAG) ) - { - found = 1; - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB found on hardware waiting" - " list and aborted.\n", p->host_no, CTL_OF_SCB(scb)); - if ( prev_hscbptr == SCB_LIST_NULL ) - { - aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH); - /* stop the selection since we just - * grabbed the scb out from under the - * card - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - } - else - { - scb_next_ptr = aic_inb(p, SCB_NEXT); - aic_outb(p, prev_hscbptr, SCBPTR); - aic_outb(p, scb_next_ptr, SCB_NEXT); - aic_outb(p, next_hscbptr, SCBPTR); - } - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - aic7xxx_add_curscb_to_free_list(p); - scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE; - break; - } - prev_hscbptr = next_hscbptr; - next_hscbptr = aic_inb(p, SCB_NEXT); - } - aic_outb(p, saved_hscbptr, SCBPTR ); - } - -/* - * Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked. - * OK...the sequencer's paused, interrupts are off, and we haven't found the - * command anyplace where it could be easily aborted. Time for the hard - * work. We also know the command is valid. This essentially means the - * command is disconnected, or connected but not into any phases yet, which - * we know due to the tests we ran earlier on the current active scb phase. - * At this point we can queue the abort tag and go on with life. - */ - - if ( found == 0 ) - { - p->flags |= AHC_ABORT_PENDING; - scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB; - scb->hscb->control |= MK_MESSAGE; - result=aic7xxx_find_scb(p, scb); - if ( result != SCB_LIST_NULL ) - { - saved_hscbptr = aic_inb(p, SCBPTR); - aic_outb(p, result, SCBPTR); - tmp_char = aic_inb(p, SCB_CONTROL); - aic_outb(p, tmp_char | MK_MESSAGE, SCB_CONTROL); - aic_outb(p, saved_hscbptr, SCBPTR); - } - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB disconnected. Queueing Abort" - " SCB.\n", p->host_no, CTL_OF_SCB(scb)); - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - } - if (found) - { - aic7xxx_run_done_queue(p, TRUE); - aic7xxx_run_waiting_queues(p); - } - p->flags &= ~AHC_IN_ABORT; - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - -/* - * On the return value. If we found the command and aborted it, then we know - * it's already sent back and there is no reason for a further timeout, so - * we use SCSI_ABORT_SUCCESS. On the queued abort side, we aren't so certain - * there hasn't been a bus hang or something that might keep the abort from - * from completing. Therefore, we use SCSI_ABORT_PENDING. The first time this - * is passed back, the timeout on the command gets extended, the second time - * we pass this back, the mid level SCSI code calls our reset function, which - * would shake loose a hung bus. - */ - if ( found != 0 ) - return(SCSI_ABORT_SUCCESS); - else - return(SCSI_ABORT_PENDING); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_reset - * - * Description: - * Resetting the bus always succeeds - is has to, otherwise the - * kernel will panic! Try a surgical technique - sending a BUS - * DEVICE RESET message - on the offending target before pulling - * the SCSI bus reset line. - *-F*************************************************************************/ -int -aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags) -{ - struct aic7xxx_scb *scb = NULL; - struct aic7xxx_host *p; - int tindex; - int result = -1; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) - unsigned long cpu_flags = 0; -#endif -#define DEVICE_RESET 0x01 -#define BUS_RESET 0x02 -#define HOST_RESET 0x04 -#define FAIL 0x08 -#define RESET_DELAY 0x10 - int action; - Scsi_Cmnd *cmd_prev, *cmd_next; - - - if ( cmd == NULL ) - { - printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd " - "pointer, failing.\n"); - return(SCSI_RESET_SNOOZE); - } - - p = (struct aic7xxx_host *) cmd->host->hostdata; - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - tindex = TARGET_INDEX(cmd); - - /* - * I added a new config option to the driver: "panic_on_abort" that will - * cause the driver to panic and the machine to stop on the first abort - * or reset call into the driver. At that point, it prints out a lot of - * usefull information for me which I can then use to try and debug the - * problem. Simply enable the boot time prompt in order to activate this - * code. - */ - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, cmd); - - DRIVER_LOCK - - pause_sequencer(p); - while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) - { - aic7xxx_isr(p->irq, p, (void *)NULL ); - pause_sequencer(p); - aic7xxx_done_cmds_complete(p); - } - - if (scb == NULL) - { - if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd" - "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd)); - if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) - { - action = HOST_RESET; - } - else - { - action = BUS_RESET; - } - } - else if (scb->cmd != cmd) - { - if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called with recycled SCB " - "for cmd.\n", p->host_no, CTL_OF_CMD(cmd)); - cmd_prev = NULL; - cmd_next = p->completeq.head; - while ( cmd_next != NULL ) - { - if (cmd_next == cmd) - { - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Reset, found cmd on completeq" - ", completing.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_NOT_RUNNING); - } - cmd_prev = cmd_next; - cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; - } - if ( !(flags & SCSI_RESET_SYNCHRONOUS) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Reset, cmd not found," - " failing.\n", p->host_no, CTL_OF_CMD(cmd)); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_NOT_RUNNING); - } - else - { - if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called, no scb, " - "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags); - scb = NULL; - action = HOST_RESET; - } - } - else - { - if (aic7xxx_verbose & VERBOSE_RESET_MID) - printk(INFO_LEAD "Reset called, scb %d, flags " - "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); - if ( aic7xxx_scb_on_qoutfifo(p, scb) ) - { - if(aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no, - CTL_OF_SCB(scb)); - if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0) - printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no, - CTL_OF_SCB(scb)); - aic7xxx_handle_command_completion_intr(p); - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_SUCCESS); - } - if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) - { - action = HOST_RESET; - } - else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET ) - { - action = BUS_RESET; - } - else - { - action = DEVICE_RESET; - } - } - if ( (action & DEVICE_RESET) && - (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Bus device reset already sent to " - "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd)); - action = BUS_RESET; - } - if ( (action & DEVICE_RESET) && - (scb->flags & SCB_QUEUED_ABORT) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - { - printk(INFO_LEAD "Have already attempted to reach " - "device with queued\n", p->host_no, CTL_OF_CMD(cmd)); - printk(INFO_LEAD "message, will escalate to bus " - "reset.\n", p->host_no, CTL_OF_CMD(cmd)); - } - action = BUS_RESET; - } - if ( (action & DEVICE_RESET) && - (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Bus device reset stupid when " - "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd)); - action = BUS_RESET; - } - if ( (action & BUS_RESET) && !(p->features & AHC_TWIN) ) - { - action = HOST_RESET; - } - if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) && - !(action & (HOST_RESET | BUS_RESET))) - { - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - { - printk(INFO_LEAD "Reset called too soon after last " - "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd)); - printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no, - CTL_OF_CMD(cmd)); - } - action = BUS_RESET; - } - if ( (p->flags & AHC_RESET_DELAY) && - (action & (HOST_RESET | BUS_RESET)) ) - { - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Reset called too soon after " - "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd)); - action = RESET_DELAY; - } -/* - * By this point, we want to already know what we are going to do and - * only have the following code implement our course of action. - */ - switch (action) - { - case RESET_DELAY: - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_PENDING); - break; - case FAIL: - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(SCSI_RESET_ERROR); - break; - case DEVICE_RESET: - p->flags |= AHC_IN_RESET; - result = aic7xxx_bus_device_reset(p, cmd); - aic7xxx_run_done_queue(p, TRUE); - /* We can't rely on run_waiting_queues to unpause the sequencer for - * PCI based controllers since we use AAP */ - aic7xxx_run_waiting_queues(p); - unpause_sequencer(p, FALSE); - p->flags &= ~AHC_IN_RESET; - DRIVER_UNLOCK - return(result); - break; - case BUS_RESET: - case HOST_RESET: - default: - p->flags |= AHC_IN_RESET | AHC_RESET_DELAY; - p->dev_expires[p->scsi_id] = jiffies + (3 * HZ); - p->dev_timer_active |= (0x01 << p->scsi_id); - if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) || - time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) ) - { - mod_timer(&p->dev_timer, p->dev_expires[p->scsi_id]); - p->dev_timer_active |= (0x01 << MAX_TARGETS); - } - aic7xxx_reset_channel(p, cmd->channel, TRUE); - if ( (p->features & AHC_TWIN) && (action & HOST_RESET) ) - { - aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE); - restart_sequencer(p); - } - if (action != HOST_RESET) - result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; - else - { - result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), - SIMODE1); - aic7xxx_clear_intstat(p); - p->flags &= ~AHC_HANDLING_REQINITS; - p->msg_type = MSG_TYPE_NONE; - p->msg_index = 0; - p->msg_len = 0; - } - aic7xxx_run_done_queue(p, TRUE); - /* - * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is - * in need of being re-started, so send it on through to aic7xxx_queue - * and let it set until the delay is over. This keeps it from dying - * entirely and avoids getting a bogus dead command back through the - * mid-level code due to too many retries. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132) - if ( flags & SCSI_RESET_SYNCHRONOUS ) - { - cmd->result = DID_BUS_BUSY << 16; - cmd->done(cmd); - } -#endif - p->flags &= ~AHC_IN_RESET; - /* - * We can't rely on run_waiting_queues to unpause the sequencer for - * PCI based controllers since we use AAP. NOTE: this also sets - * the timer for the one command we might have queued in the case - * of a synch reset. - */ - aic7xxx_run_waiting_queues(p); - unpause_sequencer(p, FALSE); - DRIVER_UNLOCK - return(result); - break; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_biosparam - * - * Description: - * Return the disk geometry for the given SCSI device. - *-F*************************************************************************/ -int -aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) -{ - int heads, sectors, cylinders, ret; - struct aic7xxx_host *p; - struct buffer_head *bh; - - p = (struct aic7xxx_host *) disk->device->host->hostdata; - bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024); - - if ( bh ) - { - ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]); - brelse(bh); - if ( ret != -1 ) - return(ret); - } - - heads = 64; - sectors = 32; - cylinders = disk->capacity / (heads * sectors); - - if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024)) - { - heads = 255; - sectors = 63; - cylinders = disk->capacity / (heads * sectors); - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return (0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_release - * - * Description: - * Free the passed in Scsi_Host memory structures prior to unloading the - * module. - *-F*************************************************************************/ -int -aic7xxx_release(struct Scsi_Host *host) -{ - struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata; - struct aic7xxx_host *next, *prev; - - if(p->irq) - free_irq(p->irq, p); - if(p->base) - release_region(p->base, MAXREG - MINREG); -#ifdef MMAPIO - if(p->maddr) - { - iounmap((void *) (((unsigned long) p->maddr) & PAGE_MASK)); - } -#endif /* MMAPIO */ - prev = NULL; - next = first_aic7xxx; - while(next != NULL) - { - if(next == p) - { - if(prev == NULL) - first_aic7xxx = next->next; - else - prev->next = next->next; - } - else - { - prev = next; - } - next = next->next; - } - aic7xxx_free(p); - return(0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_card - * - * Description: - * Print out all of the control registers on the card - * - * NOTE: This function is not yet safe for use on the VLB and EISA - * controllers, so it isn't used on those controllers at all. - *-F*************************************************************************/ -static void -aic7xxx_print_card(struct aic7xxx_host *p) -{ - int i, j, k, chip; - static struct register_ranges { - int num_ranges; - int range_val[32]; - } cards_ds[] = { - { 0, {0,} }, /* none */ - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} }, - { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/ - 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/ - 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f, - 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc, - 0xfe, 0xff} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, - 0x9f, 0x9f, 0xe0, 0xf1} }, - {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f, - 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc, - 0xfe, 0xff} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, - 0xe0, 0xf1, 0xf4, 0xfc} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, - 0xe0, 0xf1, 0xf4, 0xfc} }, - }; - chip = p->chip & AHC_CHIPID_MASK; - printk("%s at ", - board_names[p->board_name_index]); - switch(p->chip & ~AHC_CHIPID_MASK) - { - case AHC_VL: - printk("VLB Slot %d.\n", p->pci_device_fn); - break; - case AHC_EISA: - printk("EISA Slot %d.\n", p->pci_device_fn); - break; - case AHC_PCI: - default: - printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn), - PCI_FUNC(p->pci_device_fn)); - break; - } - - /* - * the registers on the card.... - */ - printk("Card Dump:\n"); - k = 0; - for(i=0; ifeatures & AHC_QUEUE_REGS) - { - aic_outb(p, 0, SDSCB_QOFF); - aic_outb(p, 0, SNSCB_QOFF); - aic_outb(p, 0, HNSCB_QOFF); - } - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_scratch_ram - * - * Description: - * Print out the scratch RAM values on the card. - *-F*************************************************************************/ -static void -aic7xxx_print_scratch_ram(struct aic7xxx_host *p) -{ - int i, k; - - k = 0; - printk("Scratch RAM:\n"); - for(i = SRAM_BASE; i < SEQCTL; i++) - { - printk("%02x:%02x ", i, aic_inb(p, i)); - if(++k == 13) - { - printk("\n"); - k=0; - } - } - if (p->features & AHC_MORE_SRAM) - { - for(i = TARG_OFFSET; i < 0x80; i++) - { - printk("%02x:%02x ", i, aic_inb(p, i)); - if(++k == 13) - { - printk("\n"); - k=0; - } - } - } - printk("\n"); -} - - -#include "aic7xxx_proc.c" - -/* Eventually this will go into an include file, but this will be later */ -static Scsi_Host_Template driver_template = AIC7XXX; - -#include "scsi_module.c" - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h --- v2.4.2/linux/drivers/scsi/aic7xxx.h Wed Jun 21 17:25:03 2000 +++ linux/drivers/scsi/aic7xxx.h Wed Dec 31 16:00:00 1969 @@ -1,73 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $ - *-M*************************************************************************/ -#ifndef _aic7xxx_h -#define _aic7xxx_h - -#define AIC7XXX_H_VERSION "5.2.0" - -/* - * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields - * to do with card config are filled in after the card is detected. - */ -#define AIC7XXX { \ - next: NULL, \ - module: NULL, \ - proc_info: aic7xxx_proc_info, \ - name: NULL, \ - detect: aic7xxx_detect, \ - release: aic7xxx_release, \ - info: aic7xxx_info, \ - command: NULL, \ - queuecommand: aic7xxx_queue, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: aic7xxx_abort, \ - reset: aic7xxx_reset, \ - slave_attach: NULL, \ - bios_param: aic7xxx_biosparam, \ - can_queue: 255, /* max simultaneous cmds */\ - this_id: -1, /* scsi id of host adapter */\ - sg_tablesize: 0, /* max scatter-gather cmds */\ - cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ - present: 0, /* number of 7xxx's present */\ - unchecked_isa_dma: 0, /* no memory DMA restrictions */\ - use_clustering: ENABLE_CLUSTERING, \ - use_new_eh_code: 0 \ -} - -extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -extern int aic7xxx_biosparam(Disk *, kdev_t, int[]); -extern int aic7xxx_detect(Scsi_Host_Template *); -extern int aic7xxx_command(Scsi_Cmnd *); -extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int); -extern int aic7xxx_abort(Scsi_Cmnd *); -extern int aic7xxx_release(struct Scsi_Host *); - -extern const char *aic7xxx_info(struct Scsi_Host *); - -extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int); - -#endif /* _aic7xxx_h */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/README.aic7xxx linux/drivers/scsi/aic7xxx_old/README.aic7xxx --- v2.4.2/linux/drivers/scsi/aic7xxx_old/README.aic7xxx Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/README.aic7xxx Sun Mar 4 14:30:18 2001 @@ -0,0 +1,511 @@ + AIC7xxx Driver for Linux + +Introduction +---------------------------- +The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com) +SCSI controllers and chipsets. Major portions of the driver and driver +development are shared between both Linux and FreeBSD. Support for the +AIC-7xxx chipsets have been in the default Linux kernel since approximately +linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD +2.1.0 or later. + + Supported cards/chipsets + ---------------------------- + Adaptec Cards + ---------------------------- + AHA-274x + AHA-274xT + AHA-2842 + AHA-2910B + AHA-2920C + AHA-2930 + AHA-2930U + AHA-2930CU + AHA-2930U2 + AHA-2940 + AHA-2940W + AHA-2940U + AHA-2940UW + AHA-2940UW-PRO + AHA-2940AU + AHA-2940U2W + AHA-2940U2 + AHA-2940U2B + AHA-2940U2BOEM + AHA-2944D + AHA-2944WD + AHA-2944UD + AHA-2944UWD + AHA-2950U2 + AHA-2950U2W + AHA-2950U2B + AHA-29160M + AHA-3940 + AHA-3940U + AHA-3940W + AHA-3940UW + AHA-3940AUW + AHA-3940U2W + AHA-3950U2B + AHA-3950U2D + AHA-3960D + AHA-39160M + AHA-3985 + AHA-3985U + AHA-3985W + AHA-3985UW + + Motherboard Chipsets + ---------------------------- + AIC-777x + AIC-785x + AIC-786x + AIC-787x + AIC-788x + AIC-789x + AIC-3860 + + Bus Types + ---------------------------- + W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support + SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s. + U - Ultra SCSI, transfer rates up to 40MB/s. + U2- Ultra 2 SCSI, transfer rates up to 80MB/s. + D - Differential SCSI. + T - Twin Channel SCSI. Up to 14 SCSI devices. + + AHA-274x - EISA SCSI controller + AHA-284x - VLB SCSI controller + AHA-29xx - PCI SCSI controller + AHA-394x - PCI controllers with two separate SCSI controllers on-board. + AHA-398x - PCI RAID controllers with three separate SCSI controllers + on-board. + + Not Supported Devices + ------------------------------ + Adaptec Cards + ---------------------------- + AHA-2920 (Only the cards that use the Future Domain chipset are not + supported, any 2920 cards based on Adaptec AIC chipsets, + such as the 2920C, are supported) + AAA-13x Raid Adapters + AAA-113x Raid Port Card + + Motherboard Chipsets + ---------------------------- + AIC-7810 + + Bus Types + ---------------------------- + R - Raid Port busses are not supported. + + The hardware RAID devices sold by Adaptec are *NOT* supported by this + driver (and will people please stop emailing me about them, they are + a totally separate beast from the bare SCSI controllers and this driver + can not be retrofitted in any sane manner to support the hardware RAID + features on those cards - Doug Ledford). + + + People + ------------------------------ + Justin T Gibbs gibbs@plutotech.com + (BSD Driver Author) + Dan Eischen deischen@iworks.InterWorks.org + (Original Linux Driver Co-maintainer) + Dean Gehnert deang@teleport.com + (Original Linux FTP/patch maintainer) + Jess Johnson jester@frenzy.com + (AIC7xxx FAQ author) + Doug Ledford dledford@redhat.com + (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer) + + Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original + author of the driver. John has since retired from the project. Thanks + again for all his work! + + Mailing list + ------------------------------ + There is a mailing list available for users who want to track development + and converse with other users and developers. This list is for both + FreeBSD and Linux support of the AIC7xxx chipsets. + + To subscribe to the AIC7xxx mailing list send mail to the list server, + with "subscribe AIC7xxx" in the body (no Subject: required): + To: majordomo@FreeBSD.ORG + --- + subscribe AIC7xxx + + To unsubscribe from the list, send mail to the list server with: + To: majordomo@FreeBSD.ORG + --- + unsubscribe AIC7xxx + + Send regular messages and replies to: AIC7xxx@FreeBSD.ORG + + Boot Command line options + ------------------------------ + "aic7xxx=no_reset" - Eliminate the SCSI bus reset during startup. + Some SCSI devices need the initial reset that this option disables + in order to work. If you have problems at bootup, please make sure + you aren't using this option. + + "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at + bootup by scanning from the highest numbered PCI device to the + lowest numbered PCI device, others do just the opposite and scan + from lowest to highest numbered PCI device. There is no reliable + way to autodetect this ordering. So, we default to the most common + order, which is lowest to highest. Then, in case your motherboard + scans from highest to lowest, we have this option. If your BIOS + finds the drives on controller A before controller B but the linux + kernel finds your drives on controller B before A, then you should + use this option. + + "aic7xxx=extended" - Force the driver to detect extended drive translation + on your controller. This helps those people who have cards without + a SEEPROM make sure that linux and all other operating systems think + the same way about your hard drives. + + "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to + give the card more hardware SCB slots. This allows the driver to use + that SCB RAM. Without this option, the driver won't touch the SCB + RAM because it is known to cause problems on a few cards out there + (such as 3985 class cards). + + "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel + to use the correct IRQ type for your card. This only applies to EISA + based controllers. On these controllers, 0 is for Edge triggered + interrupts, and 1 is for Level triggered interrupts. If you aren't + sure or don't know which IRQ trigger type your EISA card uses, then + let the kernel autodetect the trigger type. + + "aic7xxx=verbose" - This option can be used in one of two ways. If you + simply specify aic7xxx=verbose, then the kernel will automatically + pick the default set of verbose messages for you to see. + Alternatively, you can specify the command as + "aic7xxx=verbose:0xXXXX" where the X entries are replaced with + hexadecimal digits. This option is a bit field type option. For + a full listing of the available options, search for the + #define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want + verbose messages, then it is recommended that you simply use the + aic7xxx=verbose variant of this command. + + "aic7xxx=pci_parity:x" - This option controls whether or not the driver + enables PCI parity error checking on the PCI bus. By default, this + checking is disabled. To enable the checks, simply specify pci_parity + with no value afterwords. To reverse the parity from even to odd, + supply any number other than 0 or 255. In short: + pci_parity - Even parity checking (even is the normal PCI parity) + pci_parity:x - Where x > 0, Odd parity checking + pci_parity:0 - No check (default) + NOTE: In order to get Even PCI parity checking, you must use the + version of the option that does not include the : and a number at + the end (unless you want to enter exactly 2^32 - 1 as the number). + + "aic7xxx=no_probe" - This option will disable the probing for any VLB + based 2842 controllers and any EISA based controllers. This is + needed on certain newer motherboards where the normal EISA I/O ranges + have been claimed by other PCI devices. Probing on those machines + will often result in the machine crashing or spontaneously rebooting + during startup. Examples of machines that need this are the + Dell PowerEdge 6300 machines. + + "aic7xxx=seltime:2" - This option controls how long the card waits + during a device selection sequence for the device to respond. + The original SCSI spec says that this "should be" 256ms. This + is generally not required with modern devices. However, some + very old SCSI I devices need the full 256ms. Most modern devices + can run fine with only 64ms. The default for this option is + 64ms. If you need to change this option, then use the following + table to set the proper value in the example above: + 0 - 256ms + 1 - 128ms + 2 - 64ms + 3 - 32ms + + "aic7xxx=panic_on_abort" - This option is for debugging and will cause + the driver to panic the linux kernel and freeze the system the first + time the drivers abort or reset routines are called. This is most + helpful when some problem causes infinite reset loops that scroll too + fast to see. By using this option, you can write down what the errors + actually are and send that information to me so it can be fixed. + + "aic7xxx=dump_card" - This option will print out the *entire* set of + configuration registers on the card during the init sequence. This + is a debugging aid used to see exactly what state the card is in + when we finally finish our initialization routines. If you don't + have documentation on the chipsets, this will do you absolutely + no good unless you are simply trying to write all the information + down in order to send it to me. + + "aic7xxx=dump_sequencer" - This is the same as the above options except + that instead of dumping the register contents on the card, this + option dumps the contents of the sequencer program RAM. This gives + the ability to verify that the instructions downloaded to the + card's sequencer are indeed what they are suppossed to be. Again, + unless you have documentation to tell you how to interpret these + numbers, then it is totally useless. + + "aic7xxx=override_term:0xffffffff" - This option is used to force the + termination on your SCSI controllers to a particular setting. This + is a bit mask variable that applies for up to 8 aic7xxx SCSI channels. + Each channel gets 4 bits, divided as follows: + bit 3 2 1 0 + | | | Enable/Disable Single Ended Low Byte Termination + | | En/Disable Single Ended High Byte Termination + | En/Disable Low Byte LVD Termination + En/Disable High Byte LVD Termination + + The upper 2 bits that deal with LVD termination only apply to Ultra2 + controllers. Futhermore, due to the current Ultra2 controller + designs, these bits are tied together such that setting either bit + enables both low and high byte LVD termination. It is not possible + to only set high or low byte LVD termination in this manner. This is + an artifact of the BIOS definition on Ultra2 controllers. For other + controllers, the only important bits are the two lowest bits. Setting + the higher bits on non-Ultra2 controllers has no effect. A few + examples of how to use this option: + + Enable low and high byte termination on a non-ultra2 controller that + is the first aic7xxx controller (the correct bits are 0011), + aic7xxx=override_term:0x3 + + Enable all termination on the third aic7xxx controller, high byte + termination on the second aic7xxx controller, and low and high byte + SE termination on the first aic7xxx controller + (bits are 1111 0010 0011), + aic7xxx=override_term:0xf23 + + No attempt has been made to make this option non-cryptic. It really + shouldn't be used except in dire circumstances, and if that happens, + I'm probably going to be telling you what to set this to anyway :) + + "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV + bit in the DEVCONFIG PCI register. Currently, this is one of the + very few registers that we have absolutely *no* way of detecting + what the variable should be. It depends entirely on how the chipset + and external terminators were coupled by the card/motherboard maker. + Further, a chip reset (at power up) always sets this bit to 0. If + there is no BIOS to run on the chipset/card (such as with a 2910C + or a motherboard controller with the BIOS totally disabled) then + the variable may not get set properly. Of course, if the proper + setting was 0, then that's what it would be after the reset, but if + the proper setting is actually 1.....you get the picture. Now, since + we can't detect this at all, I've added this option to force the + setting. If you have a BIOS on your controller then you should never + need to use this option. However, if you are having lots of SCSI + reset problems and can't seem to get them knocked out, this may help. + + Here's a test to know for certain if you need this option. Make + a boot floppy that you can use to boot your computer up and that + will detect the aic7xxx controller. Next, power down your computer. + While it's down, unplug all SCSI cables from your Adaptec SCSI + controller. Boot the system back up to the Adaptec EZ-SCSI BIOS + and then make sure that termination is enabled on your adapter (if + you have an Adaptec BIOS of course). Next, boot up the floppy you + made and wait for it to detect the aic7xxx controller. If the kernel + finds the controller fine, says scsi : x hosts and then tries to + detect your devices like normal, up to the point where it fails to + mount your root file system and panics, then you're fine. If, on + the other hand, the system goes into an infinite reset loop, then + you need to use this option and/or the previous option to force the + proper termination settings on your controller. If this happens, + then you next need to figure out what your settings should be. + + To find the correct settings, power your machine back down, connect + back up the SCSI cables, and boot back into your machine like normal. + However, boot with the aic7xxx=verbose:0x39 option. Record the + initial DEVCONFIG values for each of your aic7xxx controllers as + they are listed, and also record what the machine is detecting as + the proper termination on your controllers. NOTE: the order in + which the initial DEVCONFIG values are printed out is not gauranteed + to be the same order as the SCSI controllers are registered. The + above option and this option both work on the order of the SCSI + controllers as they are registered, so make sure you match the right + DEVCONFIG values with the right controllers if you have more than + one aic7xxx controller. + + Once you have the detected termination settings and the initial + DEVCONFIG values for each controller, then figure out what the + termination on each of the controllers *should* be. Hopefully, that + part is correct, but it could possibly be wrong if there is + bogus cable detection logic on your controller or something similar. + If all the controllers have the correct termination settings, then + don't set the aic7xxx=override_term variable at all, leave it alone. + Next, on any controllers that go into an infinite reset loop when + you unplug all the SCSI cables, get the starting DEVCONFIG value. + If the initial DEVCONFIG value is divisible by 2, then the correct + setting for that controller is 0. If it's an odd number, then + the correct setting for that controller is 1. For any other + controllers that didn't have an infinite reset problem, then reverse + the above options. If DEVCONFIG was even, then the correct setting + is 1, if not then the correct setting is 0. + + Now that you know what the correct setting was for each controller, + we need to encode that into the aic7xxx=stpwlev:0x... variable. + This variable is a bit field encoded variable. Bit 0 is for the first + aic7xxx controller, bit 1 for the next, etc. Put all these bits + together and you get a number. For example, if the third aic7xxx + needed a 1, but the second and first both needed a 0, then the bits + would be 100 in binary. This then translates to 0x04. You would + therefore set aic7xxx=stpwlev:0x04. This is fairly standard binary + to hexadecimal conversions here. If you aren't up to speed on the + binary->hex conversion then send an email to the aic7xxx mailing + list and someone can help you out. + + "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable + or enable Tagged Command Queueing (TCQ) on specific devices. As of + driver version 5.1.11, TCQ is now either on or off by default + according to the setting you choose during the make config process. + In order to en/disable TCQ for certian devices at boot time, a user + may use this boot param. The driver will then parse this message out + and en/disable the specific device entries that are present based upon + the value given. The param line is parsed in the following manner: + + { - first instance indicates the start of this parameter values + second instance is the start of entries for a particular + device entry + } - end the entries for a particular host adapter, or end the entire + set of parameter entries + , - move to next entry. Inside of a set of device entries, this + moves us to the next device on the list. Outside of device + entries, this moves us to the next host adapter + . - Same effect as , but is safe to use with insmod. + x - the number to enter into the array at this position. + 0 = Enable tagged queueing on this device and use the default + queue depth + 1-254 = Enable tagged queueing on this device and use this + number as the queue depth + 255 = Disable tagged queueing on this device. + Note: anything above 32 for an actual queue depth is wasteful + and not recommended. + + A few examples of how this can be used: + + tag_info:{{8,12,,0,,255,4}} + This line will only effect the first aic7xxx card registered. It + will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2 + at the default, set id 3 to tagged queueing enabled and use the + default queue depth, id 4 default, id 5 disabled, and id 6 to 4. + Any not specified entries stay at the default value, repeated + commas with no value specified will simply increment to the next id + without changing anything for the missing values. + + tag_info:{,,,{,,,255}} + First, second, and third adapters at default values. Fourth + adapter, id 3 is disabled. Notice that leading commas simply + increment what the first number effects, and there are no need + for trailing commas. When you close out an adapter, or the + entire entry, anything not explicitly set stays at the default + value. + + A final note on this option. The scanner I used for this isn't + perfect or highly robust. If you mess the line up, the worst that + should happen is that the line will get ignored. If you don't + close out the entire entry with the final bracket, then any other + aic7xxx options after this will get ignored. So, in general, be + sure of what you are entering, and after you have it right, just + add it to the lilo.conf file so there won't be any mistakes. As + a means of checking this parser, the entire tag_info array for + each card is now printed out in the /proc/scsi/aic7xxx/x file. You + can use that to verify that your options were parsed correctly. + + Boot command line options may be combined to form the proper set of options + a user might need. For example, the following is valid: + + aic7xxx=verbose,extended,irq_trigger:1 + + The only requirement is that individual options be separated by a comma or + a period on the command line. + + Module Loading command options + ------------------------------ + When loading the aic7xxx driver as a module, the exact same options are + available to the user. However, the syntax to specify the options changes + slightly. For insmod, you need to wrap the aic7xxx= argument in quotes + and replace all ',' with '.'. So, for example, a valid insmod line + would be: + + insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended' + + This line should result in the *exact* same behaviour as if you typed + it in at the lilo prompt and the driver was compiled into the kernel + instead of being a module. The reason for the single quote is so that + the shell won't try to interpret anything in the line, such as {. + Insmod assumes any options starting with a letter instead of a number + is a character string (which is what we want) and by switching all of + the commas to periods, insmod won't interpret this as more than one + string and write junk into our binary image. I consider it a bug in + the insmod program that even if you wrap your string in quotes (quotes + that pass the shell mind you and that insmod sees) it still treates + a comma inside of those quotes as starting a new variable, resulting + in memory scribbles if you don't switch the commas to periods. + + + Kernel Compile options + ------------------------------ + The various kernel compile time options for this driver are now fairly + well documented in the file Documentation/Configure.help. In order to + see this documentation, you need to use one of the advanced configuration + programs (menuconfig and xconfig). If you are using the "make menuconfig" + method of configuring your kernel, then you would simply highlight the + option in question and hit the ? key. If you are using the "make xconfig" + method of configuring your kernel, then simply click on the help button + next to the option you have questions about. The help information from + the Configure.help file will then get automatically displayed. + + /proc support + ------------------------------ + The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/ + directory. That directory contains a file for each SCSI controller in + the system. Each file presents the current configuration and transfer + statistics (enabled with #define in aic7xxx.c) for each controller. + + Thanks to Michael Neuffer for his upper-level SCSI help, and + Matthew Jacob for statistics support. + + Debugging the driver + ------------------------------ + Should you have problems with this driver, and would like some help in + getting them solved, there are a couple debugging items built into + the driver to facilitate getting the needed information from the system. + In general, I need a complete description of the problem, with as many + logs as possible concerning what happens. To help with this, there is + a command option aic7xxx=panic_on_abort. This option, when set, forces + the driver to panic the kernel on the first SCSI abort issued by the + mid level SCSI code. If your system is going to reset loops and you + can't read the screen, then this is what you need. Not only will it + stop the system, but it also prints out a large amount of state + information in the process. Second, if you specify the option + "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much + information as it runs that you won't be able to see anything. + However, this can actually be very usefull if your machine simply + locks up when trying to boot, since it will pin-point what was last + happening (in regards to the aic7xxx driver) immediately prior to + the lockup. This is really only usefull if your machine simply can + not boot up successfully. If you can get your machine to run, then + this will produce far too much information. + + FTP sites + ------------------------------ + ftp://ftp.redhat.com/pub/aic/ + - Out of date. I used to keep stuff here, but too many people + complained about having a hard time getting into Red Hat's ftp + server. So use the web site below instead. + ftp://ftp.pcnet.com/users/eischen/Linux/ + - Dan Eischen's driver distribution area + ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/ + - European Linux mirror of Teleport site + + Web sites + ------------------------------ + http://people.redhat.com/dledford/ + - My web site, also the primary aic7xxx site with several related + pages. + +Dean W. Gehnert +deang@teleport.com + +$Revision: 3.0 $ + +Modified by Doug Ledford 1998-2000 + diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.h linux/drivers/scsi/aic7xxx_old/aic7xxx.h --- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx.h Sun Mar 4 14:30:18 2001 @@ -0,0 +1,73 @@ +/*+M************************************************************************* + * Adaptec AIC7xxx device driver for Linux. + * + * Copyright (c) 1994 John Aycock + * The University of Calgary Department of Computer Science. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $ + *-M*************************************************************************/ +#ifndef _aic7xxx_h +#define _aic7xxx_h + +#define AIC7XXX_H_VERSION "5.2.0" + +/* + * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields + * to do with card config are filled in after the card is detected. + */ +#define AIC7XXX { \ + next: NULL, \ + module: NULL, \ + proc_info: aic7xxx_proc_info, \ + name: NULL, \ + detect: aic7xxx_detect, \ + release: aic7xxx_release, \ + info: aic7xxx_info, \ + command: NULL, \ + queuecommand: aic7xxx_queue, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: NULL, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: NULL, \ + abort: aic7xxx_abort, \ + reset: aic7xxx_reset, \ + slave_attach: NULL, \ + bios_param: aic7xxx_biosparam, \ + can_queue: 255, /* max simultaneous cmds */\ + this_id: -1, /* scsi id of host adapter */\ + sg_tablesize: 0, /* max scatter-gather cmds */\ + cmd_per_lun: 3, /* cmds per lun (linked cmds) */\ + present: 0, /* number of 7xxx's present */\ + unchecked_isa_dma: 0, /* no memory DMA restrictions */\ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0 \ +} + +extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); +extern int aic7xxx_biosparam(Disk *, kdev_t, int[]); +extern int aic7xxx_detect(Scsi_Host_Template *); +extern int aic7xxx_command(Scsi_Cmnd *); +extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int); +extern int aic7xxx_abort(Scsi_Cmnd *); +extern int aic7xxx_release(struct Scsi_Host *); + +extern const char *aic7xxx_info(struct Scsi_Host *); + +extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int); + +#endif /* _aic7xxx_h */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg linux/drivers/scsi/aic7xxx_old/aic7xxx.reg --- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx.reg Sun Mar 4 14:30:19 2001 @@ -0,0 +1,1396 @@ +/* + * Aic7xxx register and scratch ram definitions. + * + * Copyright (c) 1994-1998 Justin Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $ + */ + +/* + * This file is processed by the aic7xxx_asm utility for use in assembling + * firmware for the aic7xxx family of SCSI host adapters as well as to generate + * a C header file for use in the kernel portion of the Aic7xxx driver. + * + * All page numbers refer to the Adaptec AIC-7770 Data Book available from + * Adaptec's Technical Documents Department 1-800-934-2766 + */ + +/* + * SCSI Sequence Control (p. 3-11). + * Each bit, when set starts a specific SCSI sequence on the bus + */ +register SCSISEQ { + address 0x000 + access_mode RW + bit TEMODE 0x80 + bit ENSELO 0x40 + bit ENSELI 0x20 + bit ENRSELI 0x10 + bit ENAUTOATNO 0x08 + bit ENAUTOATNI 0x04 + bit ENAUTOATNP 0x02 + bit SCSIRSTO 0x01 +} + +/* + * SCSI Transfer Control 0 Register (pp. 3-13). + * Controls the SCSI module data path. + */ +register SXFRCTL0 { + address 0x001 + access_mode RW + bit DFON 0x80 + bit DFPEXP 0x40 + bit FAST20 0x20 + bit CLRSTCNT 0x10 + bit SPIOEN 0x08 + bit SCAMEN 0x04 + bit CLRCHN 0x02 +} + +/* + * SCSI Transfer Control 1 Register (pp. 3-14,15). + * Controls the SCSI module data path. + */ +register SXFRCTL1 { + address 0x002 + access_mode RW + bit BITBUCKET 0x80 + bit SWRAPEN 0x40 + bit ENSPCHK 0x20 + mask STIMESEL 0x18 + bit ENSTIMER 0x04 + bit ACTNEGEN 0x02 + bit STPWEN 0x01 /* Powered Termination */ +} + +/* + * SCSI Control Signal Read Register (p. 3-15). + * Reads the actual state of the SCSI bus pins + */ +register SCSISIGI { + address 0x003 + access_mode RO + bit CDI 0x80 + bit IOI 0x40 + bit MSGI 0x20 + bit ATNI 0x10 + bit SELI 0x08 + bit BSYI 0x04 + bit REQI 0x02 + bit ACKI 0x01 +/* + * Possible phases in SCSISIGI + */ + mask PHASE_MASK CDI|IOI|MSGI + mask P_DATAOUT 0x00 + mask P_DATAIN IOI + mask P_COMMAND CDI + mask P_MESGOUT CDI|MSGI + mask P_STATUS CDI|IOI + mask P_MESGIN CDI|IOI|MSGI +} + +/* + * SCSI Control Signal Write Register (p. 3-16). + * Writing to this register modifies the control signals on the bus. Only + * those signals that are allowed in the current mode (Initiator/Target) are + * asserted. + */ +register SCSISIGO { + address 0x003 + access_mode WO + bit CDO 0x80 + bit IOO 0x40 + bit MSGO 0x20 + bit ATNO 0x10 + bit SELO 0x08 + bit BSYO 0x04 + bit REQO 0x02 + bit ACKO 0x01 +/* + * Possible phases to write into SCSISIG0 + */ + mask PHASE_MASK CDI|IOI|MSGI + mask P_DATAOUT 0x00 + mask P_DATAIN IOI + mask P_COMMAND CDI + mask P_MESGOUT CDI|MSGI + mask P_STATUS CDI|IOI + mask P_MESGIN CDI|IOI|MSGI +} + +/* + * SCSI Rate Control (p. 3-17). + * Contents of this register determine the Synchronous SCSI data transfer + * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the + * SOFS (3:0) bits disables synchronous data transfers. Any offset value + * greater than 0 enables synchronous transfers. + */ +register SCSIRATE { + address 0x004 + access_mode RW + bit WIDEXFER 0x80 /* Wide transfer control */ + mask SXFR 0x70 /* Sync transfer rate */ + mask SXFR_ULTRA2 0x7f /* Sync transfer rate */ + mask SOFS 0x0f /* Sync offset */ +} + +/* + * SCSI ID (p. 3-18). + * Contains the ID of the board and the current target on the + * selected channel. + */ +register SCSIID { + address 0x005 + access_mode RW + mask TID 0xf0 /* Target ID mask */ + mask OID 0x0f /* Our ID mask */ + /* + * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book) + * The aic7890/91 allow an offset of up to 127 transfers in both wide + * and narrow mode. + */ + alias SCSIOFFSET + mask SOFS_ULTRA2 0x7f /* Sync offset U2 chips */ +} + +/* + * SCSI Latched Data (p. 3-19). + * Read/Write latches used to transfer data on the SCSI bus during + * Automatic or Manual PIO mode. SCSIDATH can be used for the + * upper byte of a 16bit wide asynchronouse data phase transfer. + */ +register SCSIDATL { + address 0x006 + access_mode RW +} + +register SCSIDATH { + address 0x007 + access_mode RW +} + +/* + * SCSI Transfer Count (pp. 3-19,20) + * These registers count down the number of bytes transferred + * across the SCSI bus. The counter is decremented only once + * the data has been safely transferred. SDONE in SSTAT0 is + * set when STCNT goes to 0 + */ +register STCNT { + address 0x008 + size 3 + access_mode RW +} + +/* + * Option Mode Register (Alternate Mode) (p. 5-198) + * This register is used to set certain options on Ultra3 based chips. + * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set) + */ +register OPTIONMODE { + address 0x008 + access_mode RW + bit AUTORATEEN 0x80 + bit AUTOACKEN 0x40 + bit ATNMGMNTEN 0x20 + bit BUSFREEREV 0x10 + bit EXPPHASEDIS 0x08 + bit SCSIDATL_IMGEN 0x04 + bit AUTO_MSGOUT_DE 0x02 + bit DIS_MSGIN_DUALEDGE 0x01 +} + + +/* + * Clear SCSI Interrupt 0 (p. 3-20) + * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0. + */ +register CLRSINT0 { + address 0x00b + access_mode WO + bit CLRSELDO 0x40 + bit CLRSELDI 0x20 + bit CLRSELINGO 0x10 + bit CLRSWRAP 0x08 + bit CLRSPIORDY 0x02 +} + +/* + * SCSI Status 0 (p. 3-21) + * Contains one set of SCSI Interrupt codes + * These are most likely of interest to the sequencer + */ +register SSTAT0 { + address 0x00b + access_mode RO + bit TARGET 0x80 /* Board acting as target */ + bit SELDO 0x40 /* Selection Done */ + bit SELDI 0x20 /* Board has been selected */ + bit SELINGO 0x10 /* Selection In Progress */ + bit SWRAP 0x08 /* 24bit counter wrap */ + bit IOERR 0x08 /* LVD Tranceiver mode changed */ + bit SDONE 0x04 /* STCNT = 0x000000 */ + bit SPIORDY 0x02 /* SCSI PIO Ready */ + bit DMADONE 0x01 /* DMA transfer completed */ +} + +/* + * Clear SCSI Interrupt 1 (p. 3-23) + * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. + */ +register CLRSINT1 { + address 0x00c + access_mode WO + bit CLRSELTIMEO 0x80 + bit CLRATNO 0x40 + bit CLRSCSIRSTI 0x20 + bit CLRBUSFREE 0x08 + bit CLRSCSIPERR 0x04 + bit CLRPHASECHG 0x02 + bit CLRREQINIT 0x01 +} + +/* + * SCSI Status 1 (p. 3-24) + */ +register SSTAT1 { + address 0x00c + access_mode RO + bit SELTO 0x80 + bit ATNTARG 0x40 + bit SCSIRSTI 0x20 + bit PHASEMIS 0x10 + bit BUSFREE 0x08 + bit SCSIPERR 0x04 + bit PHASECHG 0x02 + bit REQINIT 0x01 +} + +/* + * SCSI Status 2 (pp. 3-25,26) + */ +register SSTAT2 { + address 0x00d + access_mode RO + bit OVERRUN 0x80 + bit SHVALID 0x40 + bit WIDE_RES 0x20 + bit EXP_ACTIVE 0x10 /* SCSI Expander Active */ + bit CRCVALERR 0x08 /* CRC Value Error */ + bit CRCENDERR 0x04 /* CRC End Error */ + bit CRCREQERR 0x02 /* CRC REQ Error */ + bit DUAL_EDGE_ERROR 0x01 /* Invalid pins for Dual Edge phase */ + mask SFCNT 0x1f +} + +/* + * SCSI Status 3 (p. 3-26) + */ +register SSTAT3 { + address 0x00e + access_mode RO + mask SCSICNT 0xf0 + mask OFFCNT 0x0f +} + +/* + * SCSI ID for the aic7890/91 chips + */ +register SCSIID_ULTRA2 { + address 0x00f + access_mode RW + mask TID 0xf0 /* Target ID mask */ + mask OID 0x0f /* Our ID mask */ +} + +/* + * SCSI Interrupt Mode 1 (p. 3-28) + * Setting any bit will enable the corresponding function + * in SIMODE0 to interrupt via the IRQ pin. + */ +register SIMODE0 { + address 0x010 + access_mode RW + bit ENSELDO 0x40 + bit ENSELDI 0x20 + bit ENSELINGO 0x10 + bit ENSWRAP 0x08 + bit ENIOERR 0x08 /* LVD Tranceiver mode changes */ + bit ENSDONE 0x04 + bit ENSPIORDY 0x02 + bit ENDMADONE 0x01 +} + +/* + * SCSI Interrupt Mode 1 (pp. 3-28,29) + * Setting any bit will enable the corresponding function + * in SIMODE1 to interrupt via the IRQ pin. + */ +register SIMODE1 { + address 0x011 + access_mode RW + bit ENSELTIMO 0x80 + bit ENATNTARG 0x40 + bit ENSCSIRST 0x20 + bit ENPHASEMIS 0x10 + bit ENBUSFREE 0x08 + bit ENSCSIPERR 0x04 + bit ENPHASECHG 0x02 + bit ENREQINIT 0x01 +} + +/* + * SCSI Data Bus (High) (p. 3-29) + * This register reads data on the SCSI Data bus directly. + */ +register SCSIBUSL { + address 0x012 + access_mode RO +} + +register SCSIBUSH { + address 0x013 + access_mode RO +} + +/* + * SCSI/Host Address (p. 3-30) + * These registers hold the host address for the byte about to be + * transferred on the SCSI bus. They are counted up in the same + * manner as STCNT is counted down. SHADDR should always be used + * to determine the address of the last byte transferred since HADDR + * can be skewed by write ahead. + */ +register SHADDR { + address 0x014 + size 4 + access_mode RO +} + +/* + * Selection Timeout Timer (p. 3-30) + */ +register SELTIMER { + address 0x018 + access_mode RW + bit STAGE6 0x20 + bit STAGE5 0x10 + bit STAGE4 0x08 + bit STAGE3 0x04 + bit STAGE2 0x02 + bit STAGE1 0x01 +} + +/* + * Selection/Reselection ID (p. 3-31) + * Upper four bits are the device id. The ONEBIT is set when the re/selecting + * device did not set its own ID. + */ +register SELID { + address 0x019 + access_mode RW + mask SELID_MASK 0xf0 + bit ONEBIT 0x08 +} + +/* + * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book) + * Indicates if external logic has been attached to the chip to + * perform the tasks of accessing a serial eeprom, testing termination + * strength, and performing cable detection. On the aic7860, most of + * these features are handled on chip, but on the aic7855 an attached + * aic3800 does the grunt work. + */ +register SPIOCAP { + address 0x01b + access_mode RW + bit SOFT1 0x80 + bit SOFT0 0x40 + bit SOFTCMDEN 0x20 + bit HAS_BRDCTL 0x10 /* External Board control */ + bit SEEPROM 0x08 /* External serial eeprom logic */ + bit EEPROM 0x04 /* Writable external BIOS ROM */ + bit ROM 0x02 /* Logic for accessing external ROM */ + bit SSPIOCPS 0x01 /* Termination and cable detection */ +} + +/* + * SCSI Block Control (p. 3-32) + * Controls Bus type and channel selection. In a twin channel configuration + * addresses 0x00-0x1e are gated to the appropriate channel based on this + * register. SELWIDE allows for the coexistence of 8bit and 16bit devices + * on a wide bus. + */ +register SBLKCTL { + address 0x01f + access_mode RW + bit DIAGLEDEN 0x80 /* Aic78X0 only */ + bit DIAGLEDON 0x40 /* Aic78X0 only */ + bit AUTOFLUSHDIS 0x20 + bit SELBUSB 0x08 + bit ENAB40 0x08 /* LVD transceiver active */ + bit ENAB20 0x04 /* SE/HVD transceiver active */ + bit SELWIDE 0x02 + bit XCVR 0x01 /* External transceiver active */ +} + +/* + * Sequencer Control (p. 3-33) + * Error detection mode and speed configuration + */ +register SEQCTL { + address 0x060 + access_mode RW + bit PERRORDIS 0x80 + bit PAUSEDIS 0x40 + bit FAILDIS 0x20 + bit FASTMODE 0x10 + bit BRKADRINTEN 0x08 + bit STEP 0x04 + bit SEQRESET 0x02 + bit LOADRAM 0x01 +} + +/* + * Sequencer RAM Data (p. 3-34) + * Single byte window into the Scratch Ram area starting at the address + * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write + * four bytes in succession. The SEQADDRs will increment after the most + * significant byte is written + */ +register SEQRAM { + address 0x061 + access_mode RW +} + +/* + * Sequencer Address Registers (p. 3-35) + * Only the first bit of SEQADDR1 holds addressing information + */ +register SEQADDR0 { + address 0x062 + access_mode RW +} + +register SEQADDR1 { + address 0x063 + access_mode RW + mask SEQADDR1_MASK 0x01 +} + +/* + * Accumulator + * We cheat by passing arguments in the Accumulator up to the kernel driver + */ +register ACCUM { + address 0x064 + access_mode RW + accumulator +} + +register SINDEX { + address 0x065 + access_mode RW + sindex +} + +register DINDEX { + address 0x066 + access_mode RW +} + +register ALLONES { + address 0x069 + access_mode RO + allones +} + +register ALLZEROS { + address 0x06a + access_mode RO + allzeros +} + +register NONE { + address 0x06a + access_mode WO + none +} + +register FLAGS { + address 0x06b + access_mode RO + bit ZERO 0x02 + bit CARRY 0x01 +} + +register SINDIR { + address 0x06c + access_mode RO +} + +register DINDIR { + address 0x06d + access_mode WO +} + +register FUNCTION1 { + address 0x06e + access_mode RW +} + +register STACK { + address 0x06f + access_mode RO +} + +/* + * Board Control (p. 3-43) + */ +register BCTL { + address 0x084 + access_mode RW + bit ACE 0x08 + bit ENABLE 0x01 +} + +register DSCOMMAND0 { + address 0x084 + access_mode RW + bit CACHETHEN 0x80 + bit DPARCKEN 0x40 + bit MPARCKEN 0x20 + bit EXTREQLCK 0x10 + bit INTSCBRAMSEL 0x08 + bit RAMPS 0x04 + bit USCBSIZE32 0x02 + bit CIOPARCKEN 0x01 +} + +/* + * On the aic78X0 chips, Board Control is replaced by the DSCommand + * register (p. 4-64) + */ +register DSCOMMAND { + address 0x084 + access_mode RW + bit CACHETHEN 0x80 /* Cache Threshold enable */ + bit DPARCKEN 0x40 /* Data Parity Check Enable */ + bit MPARCKEN 0x20 /* Memory Parity Check Enable */ + bit EXTREQLCK 0x10 /* External Request Lock */ +} + +/* + * Bus On/Off Time (p. 3-44) + */ +register BUSTIME { + address 0x085 + access_mode RW + mask BOFF 0xf0 + mask BON 0x0f +} + +/* + * Bus Speed (p. 3-45) + */ +register BUSSPD { + address 0x086 + access_mode RW + mask DFTHRSH 0xc0 + mask STBOFF 0x38 + mask STBON 0x07 + mask DFTHRSH_100 0xc0 +} + +/* + * Host Control (p. 3-47) R/W + * Overall host control of the device. + */ +register HCNTRL { + address 0x087 + access_mode RW + bit POWRDN 0x40 + bit SWINT 0x10 + bit IRQMS 0x08 + bit PAUSE 0x04 + bit INTEN 0x02 + bit CHIPRST 0x01 + bit CHIPRSTACK 0x01 +} + +/* + * Host Address (p. 3-48) + * This register contains the address of the byte about + * to be transferred across the host bus. + */ +register HADDR { + address 0x088 + size 4 + access_mode RW +} + +register HCNT { + address 0x08c + size 3 + access_mode RW +} + +/* + * SCB Pointer (p. 3-49) + * Gate one of the four SCBs into the SCBARRAY window. + */ +register SCBPTR { + address 0x090 + access_mode RW +} + +/* + * Interrupt Status (p. 3-50) + * Status for system interrupts + */ +register INTSTAT { + address 0x091 + access_mode RW + bit BRKADRINT 0x08 + bit SCSIINT 0x04 + bit CMDCMPLT 0x02 + bit SEQINT 0x01 + mask BAD_PHASE SEQINT /* unknown scsi bus phase */ + mask SEND_REJECT 0x10|SEQINT /* sending a message reject */ + mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/ + mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */ + mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */ + mask WIDE_RESIDUE 0x50|SEQINT /* need kernel to back up */ + /* the SG array for us */ + mask REJECT_MSG 0x60|SEQINT /* Reject message received */ + mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ + mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */ + mask AWAITING_MSG 0xa0|SEQINT /* + * Kernel requested to specify + * a message to this target + * (command was null), so tell + * it that it can fill the + * message buffer. + */ + mask TRACEPOINT 0xb0|SEQINT + mask TRACEPOINT2 0xc0|SEQINT + mask MSGIN_PHASEMIS 0xd0|SEQINT /* + * Target changed phase on us + * when we were expecting + * another msgin byte. + */ + mask DATA_OVERRUN 0xe0|SEQINT /* + * Target attempted to write + * beyond the bounds of its + * command. + */ + + mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */ + mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT) +} + +/* + * Hard Error (p. 3-53) + * Reporting of catastrophic errors. You usually cannot recover from + * these without a full board reset. + */ +register ERROR { + address 0x092 + access_mode RO + bit CIOPARERR 0x80 /* Ultra2 only */ + bit PCIERRSTAT 0x40 /* PCI only */ + bit MPARERR 0x20 /* PCI only */ + bit DPARERR 0x10 /* PCI only */ + bit SQPARERR 0x08 + bit ILLOPCODE 0x04 + bit ILLSADDR 0x02 + bit DSCTMOUT 0x02 /* Ultra3 only */ + bit ILLHADDR 0x01 +} + +/* + * Clear Interrupt Status (p. 3-52) + */ +register CLRINT { + address 0x092 + access_mode WO + bit CLRPARERR 0x10 /* PCI only */ + bit CLRBRKADRINT 0x08 + bit CLRSCSIINT 0x04 + bit CLRCMDINT 0x02 + bit CLRSEQINT 0x01 +} + +register DFCNTRL { + address 0x093 + access_mode RW + bit PRELOADEN 0x80 /* aic7890 only */ + bit WIDEODD 0x40 + bit SCSIEN 0x20 + bit SDMAEN 0x10 + bit SDMAENACK 0x10 + bit HDMAEN 0x08 + bit HDMAENACK 0x08 + bit DIRECTION 0x04 + bit FIFOFLUSH 0x02 + bit FIFORESET 0x01 +} + +register DFSTATUS { + address 0x094 + access_mode RO + bit PRELOAD_AVAIL 0x80 + bit DWORDEMP 0x20 + bit MREQPEND 0x10 + bit HDONE 0x08 + bit DFTHRESH 0x04 + bit FIFOFULL 0x02 + bit FIFOEMP 0x01 +} + +register DFDAT { + address 0x099 + access_mode RW +} + +/* + * SCB Auto Increment (p. 3-59) + * Byte offset into the SCB Array and an optional bit to allow auto + * incrementing of the address during download and upload operations + */ +register SCBCNT { + address 0x09a + access_mode RW + bit SCBAUTO 0x80 + mask SCBCNT_MASK 0x1f +} + +/* + * Queue In FIFO (p. 3-60) + * Input queue for queued SCBs (commands that the seqencer has yet to start) + */ +register QINFIFO { + address 0x09b + access_mode RW +} + +/* + * Queue In Count (p. 3-60) + * Number of queued SCBs + */ +register QINCNT { + address 0x09c + access_mode RO +} + +/* + * SCSIDATL IMAGE Register (p. 5-104) + * Write to this register also go to SCSIDATL but this register will preserve + * the data for later reading as long as the SCSIDATL_IMGEN bit in the + * OPTIONMODE register is set. + */ +register SCSIDATL_IMG { + address 0x09c + access_mode RW +} + +/* + * Queue Out FIFO (p. 3-61) + * Queue of SCBs that have completed and await the host + */ +register QOUTFIFO { + address 0x09d + access_mode WO +} + +/* + * CRC Control 1 Register (p. 5-105) + * Control bits for the Ultra 160/m CRC facilities + */ +register CRCCONTROL1 { + address 0x09d + access_mode RW + bit CRCONSEEN 0x80 /* CRC ON Single Edge ENable */ + bit CRCVALCHKEN 0x40 /* CRC Value Check Enable */ + bit CRCENDCHKEN 0x20 /* CRC End Check Enable */ + bit CRCREQCHKEN 0x10 + bit TARGCRCENDEN 0x08 /* Enable End CRC transfer when target */ + bit TARGCRCCNTEN 0x04 /* Enable CRC transfer when target */ +} + +/* + * Queue Out Count (p. 3-61) + * Number of queued SCBs in the Out FIFO + */ +register QOUTCNT { + address 0x09e + access_mode RO +} + +/* + * SCSI Phase Register (p. 5-106) + * Current bus phase + */ +register SCSIPHASE { + address 0x09e + access_mode RO + bit SP_STATUS 0x20 + bit SP_COMMAND 0x10 + bit SP_MSG_IN 0x08 + bit SP_MSG_OUT 0x04 + bit SP_DATA_IN 0x02 + bit SP_DATA_OUT 0x01 +} + +/* + * Special Function + */ +register SFUNCT { + address 0x09f + access_mode RW + bit ALT_MODE 0x80 +} + +/* + * SCB Definition (p. 5-4) + */ +scb { + address 0x0a0 + SCB_CONTROL { + size 1 + bit MK_MESSAGE 0x80 + bit DISCENB 0x40 + bit TAG_ENB 0x20 + bit DISCONNECTED 0x04 + mask SCB_TAG_TYPE 0x03 + } + SCB_TCL { + size 1 + bit SELBUSB 0x08 + mask TID 0xf0 + mask LID 0x07 + } + SCB_TARGET_STATUS { + size 1 + } + SCB_SGCOUNT { + size 1 + } + SCB_SGPTR { + size 4 + } + SCB_RESID_SGCNT { + size 1 + } + SCB_RESID_DCNT { + size 3 + } + SCB_DATAPTR { + size 4 + } + SCB_DATACNT { + /* + * Really only 3 bytes, but padded to make + * the kernel's job easier. + */ + size 4 + } + SCB_CMDPTR { + size 4 + } + SCB_CMDLEN { + size 1 + } + SCB_TAG { + size 1 + } + SCB_NEXT { + size 1 + } + SCB_PREV { + size 1 + } + SCB_BUSYTARGETS { + size 4 + } +} + +const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ + +/* --------------------- AHA-2840-only definitions -------------------- */ + +register SEECTL_2840 { + address 0x0c0 + access_mode RW + bit CS_2840 0x04 + bit CK_2840 0x02 + bit DO_2840 0x01 +} + +register STATUS_2840 { + address 0x0c1 + access_mode RW + bit EEPROM_TF 0x80 + mask BIOS_SEL 0x60 + mask ADSEL 0x1e + bit DI_2840 0x01 +} + +/* --------------------- AIC-7870-only definitions -------------------- */ + +register DSPCISTATUS { + address 0x086 + mask DFTHRSH_100 0xc0 +} + +register CCHADDR { + address 0x0E0 + size 8 +} + +register CCHCNT { + address 0x0E8 +} + +register CCSGRAM { + address 0x0E9 +} + +register CCSGADDR { + address 0x0EA +} + +register CCSGCTL { + address 0x0EB + bit CCSGDONE 0x80 + bit CCSGEN 0x08 + bit FLAG 0x02 + bit CCSGRESET 0x01 +} + +register CCSCBCNT { + address 0xEF +} + +register CCSCBCTL { + address 0x0EE + bit CCSCBDONE 0x80 + bit ARRDONE 0x40 /* SCB Array prefetch done */ + bit CCARREN 0x10 + bit CCSCBEN 0x08 + bit CCSCBDIR 0x04 + bit CCSCBRESET 0x01 +} + +register CCSCBADDR { + address 0x0ED +} + +register CCSCBRAM { + address 0xEC +} + +register CCSCBPTR { + address 0x0F1 +} + +register HNSCB_QOFF { + address 0x0F4 +} + +register HESCB_QOFF { + address 0x0F5 +} + +register SNSCB_QOFF { + address 0x0F6 +} + +register SESCB_QOFF { + address 0x0F7 +} + +register SDSCB_QOFF { + address 0x0F8 +} + +register QOFF_CTLSTA { + address 0x0FA + bit ESTABLISH_SCB_AVAIL 0x80 + bit SCB_AVAIL 0x40 + bit SNSCB_ROLLOVER 0x20 + bit SDSCB_ROLLOVER 0x10 + bit SESCB_ROLLOVER 0x08 + mask SCB_QSIZE 0x07 + mask SCB_QSIZE_256 0x06 +} + +register DFF_THRSH { + address 0x0FB + mask WR_DFTHRSH 0x70 + mask RD_DFTHRSH 0x07 + mask RD_DFTHRSH_MIN 0x00 + mask RD_DFTHRSH_25 0x01 + mask RD_DFTHRSH_50 0x02 + mask RD_DFTHRSH_63 0x03 + mask RD_DFTHRSH_75 0x04 + mask RD_DFTHRSH_85 0x05 + mask RD_DFTHRSH_90 0x06 + mask RD_DFTHRSH_MAX 0x07 + mask WR_DFTHRSH_MIN 0x00 + mask WR_DFTHRSH_25 0x10 + mask WR_DFTHRSH_50 0x20 + mask WR_DFTHRSH_63 0x30 + mask WR_DFTHRSH_75 0x40 + mask WR_DFTHRSH_85 0x50 + mask WR_DFTHRSH_90 0x60 + mask WR_DFTHRSH_MAX 0x70 +} + +register SG_CACHEPTR { + access_mode RW + address 0x0fc + mask SG_USER_DATA 0xfc + bit LAST_SEG 0x02 + bit LAST_SEG_DONE 0x01 +} + +register BRDCTL { + address 0x01d + bit BRDDAT7 0x80 + bit BRDDAT6 0x40 + bit BRDDAT5 0x20 + bit BRDSTB 0x10 + bit BRDCS 0x08 + bit BRDRW 0x04 + bit BRDCTL1 0x02 + bit BRDCTL0 0x01 + /* 7890 Definitions */ + bit BRDDAT4 0x10 + bit BRDDAT3 0x08 + bit BRDDAT2 0x04 + bit BRDRW_ULTRA2 0x02 + bit BRDSTB_ULTRA2 0x01 +} + +/* + * Serial EEPROM Control (p. 4-92 in 7870 Databook) + * Controls the reading and writing of an external serial 1-bit + * EEPROM Device. In order to access the serial EEPROM, you must + * first set the SEEMS bit that generates a request to the memory + * port for access to the serial EEPROM device. When the memory + * port is not busy servicing another request, it reconfigures + * to allow access to the serial EEPROM. When this happens, SEERDY + * gets set high to verify that the memory port access has been + * granted. + * + * After successful arbitration for the memory port, the SEECS bit of + * the SEECTL register is connected to the chip select. The SEECK, + * SEEDO, and SEEDI are connected to the clock, data out, and data in + * lines respectively. The SEERDY bit of SEECTL is useful in that it + * gives us an 800 nsec timer. After a write to the SEECTL register, + * the SEERDY goes high 800 nsec later. The one exception to this is + * when we first request access to the memory port. The SEERDY goes + * high to signify that access has been granted and, for this case, has + * no implied timing. + * + * See 93cx6.c for detailed information on the protocol necessary to + * read the serial EEPROM. + */ +register SEECTL { + address 0x01e + bit EXTARBACK 0x80 + bit EXTARBREQ 0x40 + bit SEEMS 0x20 + bit SEERDY 0x10 + bit SEECS 0x08 + bit SEECK 0x04 + bit SEEDO 0x02 + bit SEEDI 0x01 +} +/* ---------------------- Scratch RAM Offsets ------------------------- */ +/* These offsets are either to values that are initialized by the board's + * BIOS or are specified by the sequencer code. + * + * The host adapter card (at least the BIOS) uses 20-2f for SCSI + * device information, 32-33 and 5a-5f as well. As it turns out, the + * BIOS trashes 20-2f, writing the synchronous negotiation results + * on top of the BIOS values, so we re-use those for our per-target + * scratchspace (actually a value that can be copied directly into + * SCSIRATE). The kernel driver will enable synchronous negotiation + * for all targets that have a value other than 0 in the lower four + * bits of the target scratch space. This should work regardless of + * whether the bios has been installed. + */ + +scratch_ram { + address 0x020 + + /* + * 1 byte per target starting at this address for configuration values + */ + TARG_SCSIRATE { + size 16 + } + /* + * Bit vector of targets that have ULTRA enabled. + */ + ULTRA_ENB { + size 2 + } + /* + * Bit vector of targets that have disconnection disabled. + */ + DISC_DSB { + size 2 + } + /* + * Single byte buffer used to designate the type or message + * to send to a target. + */ + MSG_OUT { + size 1 + } + /* Parameters for DMA Logic */ + DMAPARAMS { + size 1 + bit PRELOADEN 0x80 + bit WIDEODD 0x40 + bit SCSIEN 0x20 + bit SDMAEN 0x10 + bit SDMAENACK 0x10 + bit HDMAEN 0x08 + bit HDMAENACK 0x08 + bit DIRECTION 0x04 + bit FIFOFLUSH 0x02 + bit FIFORESET 0x01 + } + SEQ_FLAGS { + size 1 + bit IDENTIFY_SEEN 0x80 + bit SCBPTR_VALID 0x20 + bit DPHASE 0x10 + bit AMTARGET 0x08 + bit WIDE_BUS 0x02 + bit TWIN_BUS 0x01 + } + /* + * Temporary storage for the + * target/channel/lun of a + * reconnecting target + */ + SAVED_TCL { + size 1 + } + /* Working value of the number of SG segments left */ + SG_COUNT { + size 1 + } + /* Working value of SG pointer */ + SG_NEXT { + size 4 + } + /* + * The last bus phase as seen by the sequencer. + */ + LASTPHASE { + size 1 + bit CDI 0x80 + bit IOI 0x40 + bit MSGI 0x20 + mask PHASE_MASK CDI|IOI|MSGI + mask P_DATAOUT 0x00 + mask P_DATAIN IOI + mask P_COMMAND CDI + mask P_MESGOUT CDI|MSGI + mask P_STATUS CDI|IOI + mask P_MESGIN CDI|IOI|MSGI + mask P_BUSFREE 0x01 + } + /* + * head of list of SCBs awaiting + * selection + */ + WAITING_SCBH { + size 1 + } + /* + * head of list of SCBs that are + * disconnected. Used for SCB + * paging. + */ + DISCONNECTED_SCBH { + size 1 + } + /* + * head of list of SCBs that are + * not in use. Used for SCB paging. + */ + FREE_SCBH { + size 1 + } + /* + * Address of the hardware scb array in the host. + */ + HSCB_ADDR { + size 4 + } + /* + * Address of the 256 byte array storing the SCBID of outstanding + * untagged SCBs indexed by TCL. + */ + SCBID_ADDR { + size 4 + } + /* + * Address of the array of command descriptors used to store + * information about incoming selections. + */ + TMODE_CMDADDR { + size 4 + } + KERNEL_QINPOS { + size 1 + } + QINPOS { + size 1 + } + QOUTPOS { + size 1 + } + /* + * Offset into the command descriptor array for the next + * available desciptor to use. + */ + TMODE_CMDADDR_NEXT { + size 1 + } + ARG_1 { + size 1 + mask SEND_MSG 0x80 + mask SEND_SENSE 0x40 + mask SEND_REJ 0x20 + mask MSGOUT_PHASEMIS 0x10 + alias RETURN_1 + } + ARG_2 { + size 1 + alias RETURN_2 + } + + /* + * Snapshot of MSG_OUT taken after each message is sent. + */ + LAST_MSG { + size 1 + } + + /* + * Number of times we have filled the CCSGRAM with prefetched + * SG elements. + */ + PREFETCH_CNT { + size 1 + } + + + /* + * These are reserved registers in the card's scratch ram. Some of + * the values are specified in the AHA2742 technical reference manual + * and are initialized by the BIOS at boot time. + */ + SCSICONF { + address 0x05a + size 1 + bit TERM_ENB 0x80 + bit RESET_SCSI 0x40 + mask HSCSIID 0x07 /* our SCSI ID */ + mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ + } + HOSTCONF { + address 0x05d + size 1 + } + HA_274_BIOSCTRL { + address 0x05f + size 1 + mask BIOSMODE 0x30 + mask BIOSDISABLED 0x30 + bit CHANNEL_B_PRIMARY 0x08 + } + /* + * Per target SCSI offset values for Ultra2 controllers. + */ + TARG_OFFSET { + address 0x070 + size 16 + } +} + +const SCB_LIST_NULL 0xff + +const CCSGADDR_MAX 0x80 +const CCSGRAM_MAXSEGS 16 + +/* Offsets into the SCBID array where different data is stored */ +const UNTAGGEDSCB_OFFSET 0 +const QOUTFIFO_OFFSET 1 +const QINFIFO_OFFSET 2 + +/* WDTR Message values */ +const BUS_8_BIT 0x00 +const BUS_16_BIT 0x01 +const BUS_32_BIT 0x02 + +/* Offset maximums */ +const MAX_OFFSET_8BIT 0x0f +const MAX_OFFSET_16BIT 0x08 +const MAX_OFFSET_ULTRA2 0x7f +const HOST_MSG 0xff + +/* Target mode command processing constants */ +const CMD_GROUP_CODE_SHIFT 0x05 +const CMD_GROUP0_BYTE_DELTA -4 +const CMD_GROUP2_BYTE_DELTA -6 +const CMD_GROUP4_BYTE_DELTA 4 +const CMD_GROUP5_BYTE_DELTA 11 + +/* + * Downloaded (kernel inserted) constants + */ + +/* + * Number of command descriptors in the command descriptor array. + */ +const TMODE_NUMCMDS download diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq linux/drivers/scsi/aic7xxx_old/aic7xxx.seq --- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx.seq Sun Mar 4 14:30:19 2001 @@ -0,0 +1,1411 @@ +/* + * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. + * + * Copyright (c) 1994-1999 Justin Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License (GPL) and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $ + */ + +#include "aic7xxx.reg" +#include "scsi_message.h" + +/* + * A few words on the waiting SCB list: + * After starting the selection hardware, we check for reconnecting targets + * as well as for our selection to complete just in case the reselection wins + * bus arbitration. The problem with this is that we must keep track of the + * SCB that we've already pulled from the QINFIFO and started the selection + * on just in case the reselection wins so that we can retry the selection at + * a later time. This problem cannot be resolved by holding a single entry + * in scratch ram since a reconnecting target can request sense and this will + * create yet another SCB waiting for selection. The solution used here is to + * use byte 27 of the SCB as a pseudo-next pointer and to thread a list + * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, + * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to + * this list everytime a request sense occurs or after completing a non-tagged + * command for which a second SCB has been queued. The sequencer will + * automatically consume the entries. + */ + +reset: + clr SCSISIGO; /* De-assert BSY */ + and SXFRCTL1, ~BITBUCKET; + /* Always allow reselection */ + mvi SCSISEQ, ENRSELI|ENAUTOATNP; + + if ((p->features & AHC_CMD_CHAN) != 0) { + /* Ensure that no DMA operations are in progress */ + clr CCSGCTL; + clr CCSCBCTL; + } + + call clear_target_state; +poll_for_work: + and SXFRCTL0, ~SPIOEN; + if ((p->features & AHC_QUEUE_REGS) == 0) { + mov A, QINPOS; + } +poll_for_work_loop: + if ((p->features & AHC_QUEUE_REGS) == 0) { + and SEQCTL, ~PAUSEDIS; + } + test SSTAT0, SELDO|SELDI jnz selection; + test SCSISEQ, ENSELO jnz poll_for_work; + if ((p->features & AHC_TWIN) != 0) { + /* + * Twin channel devices cannot handle things like SELTO + * interrupts on the "background" channel. So, if we + * are selecting, keep polling the current channel util + * either a selection or reselection occurs. + */ + xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ + test SSTAT0, SELDO|SELDI jnz selection; + test SCSISEQ, ENSELO jnz poll_for_work; + xor SBLKCTL,SELBUSB; /* Toggle back */ + } + cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; +test_queue: + /* Has the driver posted any work for us? */ + if ((p->features & AHC_QUEUE_REGS) != 0) { + test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; + mov NONE, SNSCB_QOFF; + inc QINPOS; + } else { + or SEQCTL, PAUSEDIS; + cmp KERNEL_QINPOS, A je poll_for_work_loop; + inc QINPOS; + and SEQCTL, ~PAUSEDIS; + } + +/* + * We have at least one queued SCB now and we don't have any + * SCBs in the list of SCBs awaiting selection. If we have + * any SCBs available for use, pull the tag from the QINFIFO + * and get to work on it. + */ + if ((p->flags & AHC_PAGESCBS) != 0) { + mov ALLZEROS call get_free_or_disc_scb; + } + +dequeue_scb: + add A, -1, QINPOS; + mvi QINFIFO_OFFSET call fetch_byte; + + if ((p->flags & AHC_PAGESCBS) == 0) { + /* In the non-paging case, the SCBID == hardware SCB index */ + mov SCBPTR, RETURN_2; + } +dma_queued_scb: +/* + * DMA the SCB from host ram into the current SCB location. + */ + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + mov RETURN_2 call dma_scb; + +/* + * Preset the residual fields in case we never go through a data phase. + * This isn't done by the host so we can avoid a DMA to clear these + * fields for the normal case of I/O that completes without underrun + * or overrun conditions. + */ + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, SCB_DATACNT, 3; + } else { + mov SCB_RESID_DCNT[0],SCB_DATACNT[0]; + mov SCB_RESID_DCNT[1],SCB_DATACNT[1]; + mov SCB_RESID_DCNT[2],SCB_DATACNT[2]; + } + mov SCB_RESID_SGCNT, SCB_SGCOUNT; + +start_scb: + /* + * Place us on the waiting list in case our selection + * doesn't win during bus arbitration. + */ + mov SCB_NEXT,WAITING_SCBH; + mov WAITING_SCBH, SCBPTR; +start_waiting: + /* + * Pull the first entry off of the waiting SCB list. + */ + mov SCBPTR, WAITING_SCBH; + call start_selection; + jmp poll_for_work; + +start_selection: + if ((p->features & AHC_TWIN) != 0) { + and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ + and A,SELBUSB,SCB_TCL; /* Get new channel bit */ + or SINDEX,A; + mov SBLKCTL,SINDEX; /* select channel */ + } +initialize_scsiid: + if ((p->features & AHC_ULTRA2) != 0) { + and A, TID, SCB_TCL; /* Get target ID */ + and SCSIID_ULTRA2, OID; /* Clear old target */ + or SCSIID_ULTRA2, A; + } else { + and A, TID, SCB_TCL; /* Get target ID */ + and SCSIID, OID; /* Clear old target */ + or SCSIID, A; + } + mov SCSIDATL, ALLZEROS; /* clear out the latched */ + /* data register, this */ + /* fixes a bug on some */ + /* controllers where the */ + /* last byte written to */ + /* this register can leak */ + /* onto the data bus at */ + /* bad times, such as during */ + /* selection timeouts */ + mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; + +/* + * Initialize Ultra mode setting and clear the SCSI channel. + * SINDEX should contain any additional bit's the client wants + * set in SXFRCTL0. + */ +initialize_channel: + or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; + if ((p->features & AHC_ULTRA) != 0) { +ultra: + mvi SINDEX, ULTRA_ENB+1; + test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ + dec SINDEX; +ultra_2: + mov FUNCTION1,SAVED_TCL; + mov A,FUNCTION1; + test SINDIR, A jz ndx_dtr; + or SXFRCTL0, FAST20; + } +/* + * Initialize SCSIRATE with the appropriate value for this target. + * The SCSIRATE settings for each target are stored in an array + * based at TARG_SCSIRATE. + */ +ndx_dtr: + shr A,4,SAVED_TCL; + if ((p->features & AHC_TWIN) != 0) { + test SBLKCTL,SELBUSB jz ndx_dtr_2; + or SAVED_TCL, SELBUSB; + or A,0x08; /* Channel B entries add 8 */ +ndx_dtr_2: + } + + if ((p->features & AHC_ULTRA2) != 0) { + add SINDEX, TARG_OFFSET, A; + mov SCSIOFFSET, SINDIR; + } + + add SINDEX,TARG_SCSIRATE,A; + mov SCSIRATE,SINDIR ret; + + +selection: + test SSTAT0,SELDO jnz select_out; +/* + * Reselection has been initiated by a target. Make a note that we've been + * reselected, but haven't seen an IDENTIFY message from the target yet. + */ +initiator_reselect: + mvi CLRSINT0, CLRSELDI; + /* XXX test for and handle ONE BIT condition */ + and SAVED_TCL, SELID_MASK, SELID; + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; /* + * We aren't expecting a + * bus free, so interrupt + * the kernel driver if it + * happens. + */ + mvi SPIOEN call initialize_channel; + mvi MSG_OUT, MSG_NOOP; /* No message to send */ + jmp ITloop; + +/* + * After the selection, remove this SCB from the "waiting SCB" + * list. This is achieved by simply moving our "next" pointer into + * WAITING_SCBH. Our next pointer will be set to null the next time this + * SCB is used, so don't bother with it now. + */ +select_out: + /* Turn off the selection hardware */ + mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* + * ATN on parity errors + * for "in" phases + */ + mvi CLRSINT0, CLRSELDO; + mov SCBPTR, WAITING_SCBH; + mov WAITING_SCBH,SCB_NEXT; + mov SAVED_TCL, SCB_TCL; + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; /* + * We aren't expecting a + * bus free, so interrupt + * the kernel driver if it + * happens. + */ + mvi SPIOEN call initialize_channel; +/* + * As soon as we get a successful selection, the target should go + * into the message out phase since we have ATN asserted. + */ + mvi MSG_OUT, MSG_IDENTIFYFLAG; + or SEQ_FLAGS, IDENTIFY_SEEN; + +/* + * Main loop for information transfer phases. Wait for the target + * to assert REQ before checking MSG, C/D and I/O for the bus phase. + */ +ITloop: + call phase_lock; + + mov A, LASTPHASE; + + test A, ~P_DATAIN jz p_data; + cmp A,P_COMMAND je p_command; + cmp A,P_MESGOUT je p_mesgout; + cmp A,P_STATUS je p_status; + cmp A,P_MESGIN je p_mesgin; + + mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ + jmp ITloop; /* Try reading the bus again. */ + +await_busfree: + and SIMODE1, ~ENBUSFREE; + call clear_target_state; + mov NONE, SCSIDATL; /* Ack the last byte */ + and SXFRCTL0, ~SPIOEN; + test SSTAT1,REQINIT|BUSFREE jz .; + test SSTAT1, BUSFREE jnz poll_for_work; + mvi INTSTAT, BAD_PHASE; + +clear_target_state: + /* + * We assume that the kernel driver may reset us + * at any time, even in the middle of a DMA, so + * clear DFCNTRL too. + */ + clr DFCNTRL; + + /* + * We don't know the target we will connect to, + * so default to narrow transfers to avoid + * parity problems. + */ + if ((p->features & AHC_ULTRA2) != 0) { + bmov SCSIRATE, ALLZEROS, 2; + } else { + clr SCSIRATE; + and SXFRCTL0, ~(FAST20); + } + mvi LASTPHASE, P_BUSFREE; + /* clear target specific flags */ + clr SEQ_FLAGS ret; + +/* + * If we re-enter the data phase after going through another phase, the + * STCNT may have been cleared, so restore it from the residual field. + */ +data_phase_reinit: + if ((p->features & AHC_ULTRA2) != 0) { + bmov HADDR, SHADDR, 4; + bmov HCNT, SCB_RESID_DCNT, 3; + } + if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + bmov STCNT, SCB_RESID_DCNT, 3; + } + if ((p->features & AHC_CMD_CHAN) == 0) { + mvi DINDEX, STCNT; + mvi SCB_RESID_DCNT call bcopy_3; + } + jmp data_phase_loop; + +p_data: + if ((p->features & AHC_ULTRA2) != 0) { + mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; + } else { + mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; + } + test LASTPHASE, IOI jnz . + 2; + or DMAPARAMS, DIRECTION; + call assert; /* + * Ensure entering a data + * phase is okay - seen identify, etc. + */ + if ((p->features & AHC_CMD_CHAN) != 0) { + mvi CCSGADDR, CCSGADDR_MAX; + } + test SEQ_FLAGS, DPHASE jnz data_phase_reinit; + + /* We have seen a data phase */ + or SEQ_FLAGS, DPHASE; + + /* + * Initialize the DMA address and counter from the SCB. + * Also set SG_COUNT and SG_NEXT in memory since we cannot + * modify the values in the SCB itself until we see a + * save data pointers message. + */ + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov HADDR, SCB_DATAPTR, 7; + bmov STCNT, HCNT, 3; + bmov SG_COUNT, SCB_SGCOUNT, 5; + } else { + mvi DINDEX, HADDR; + mvi SCB_DATAPTR call bcopy_7; + call set_stcnt_from_hcnt; + mvi DINDEX, SG_COUNT; + mvi SCB_SGCOUNT call bcopy_5; + } + +data_phase_loop: +/* Guard against overruns */ + test SG_COUNT, 0xff jnz data_phase_inbounds; +/* + * Turn on 'Bit Bucket' mode, set the transfer count to + * 16meg and let the target run until it changes phase. + * When the transfer completes, notify the host that we + * had an overrun. + */ + or SXFRCTL1,BITBUCKET; + and DMAPARAMS, ~(HDMAEN|SDMAEN); + if ((p->features & AHC_CMD_CHAN) != 0) { + if ((p->features & AHC_ULTRA2) != 0) { + bmov HCNT, ALLONES, 3; + } + bmov STCNT, ALLONES, 3; + } else { + mvi STCNT[0], 0xFF; + mvi STCNT[1], 0xFF; + mvi STCNT[2], 0xFF; + } +data_phase_inbounds: +/* If we are the last SG block, tell the hardware. */ + cmp SG_COUNT,0x01 jne data_phase_wideodd; + if ((p->features & AHC_ULTRA2) == 0) { + and DMAPARAMS, ~WIDEODD; + } else { + mvi SG_CACHEPTR, LAST_SEG; + } +data_phase_wideodd: + if ((p->features & AHC_ULTRA2) != 0) { + mov SINDEX, ALLONES; + mov DFCNTRL, DMAPARAMS; + test SSTAT0, SDONE jnz .; +data_phase_dma_loop: + test SSTAT0, SDONE jnz data_phase_dma_done; + test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */ +data_phase_dma_phasemis: + test SSTAT0,SDONE jnz data_phase_dma_done; + clr SINDEX; /* Remember the phasemiss */ + } else { + mov DMAPARAMS call dma; + } + +data_phase_dma_done: +/* Go tell the host about any overruns */ + test SXFRCTL1,BITBUCKET jnz data_phase_overrun; + +/* Exit if we had an underrun. dma clears SINDEX in this case. */ + test SINDEX,0xff jz data_phase_finish; + +/* + * Advance the scatter-gather pointers if needed + */ +sg_advance: + dec SG_COUNT; /* one less segment to go */ + + test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */ +/* + * Load a struct scatter and set up the data address and length. + * If the working value of the SG count is nonzero, then + * we need to load a new set of values. + * + * This, like all DMA's, assumes little-endian host data storage. + */ +sg_load: + if ((p->features & AHC_CMD_CHAN) != 0) { + /* + * Do we have any prefetch left??? + */ + cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; + + /* + * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. + */ + add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; + mvi A, CCSGADDR_MAX; + jc . + 2; + shl A, 3, SG_COUNT; + mov CCHCNT, A; + bmov CCHADDR, SG_NEXT, 4; + mvi CCSGCTL, CCSGEN|CCSGRESET; + test CCSGCTL, CCSGDONE jz .; + and CCSGCTL, ~CCSGEN; + test CCSGCTL, CCSGEN jnz .; + mvi CCSGCTL, CCSGRESET; +prefetched_segs_avail: + bmov HADDR, CCSGRAM, 8; + if ((p->features & AHC_ULTRA2) == 0) { + bmov STCNT, HCNT, 3; + } + } else { + mvi DINDEX, HADDR; + mvi SG_NEXT call bcopy_4; + + mvi HCNT[0],SG_SIZEOF; + clr HCNT[1]; + clr HCNT[2]; + + or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; + + call dma_finish; + + /* + * Copy data from FIFO into SCB data pointer and data count. + * This assumes that the SG segments are of the form: + * struct ahc_dma_seg { + * u_int32_t addr; four bytes, little-endian order + * u_int32_t len; four bytes, little endian order + * }; + */ + mvi HADDR call dfdat_in_7; + call set_stcnt_from_hcnt; + } + +/* Advance the SG pointer */ + clr A; /* add sizeof(struct scatter) */ + add SG_NEXT[0],SG_SIZEOF; + adc SG_NEXT[1],A; + + test SSTAT1, REQINIT jz .; + test SSTAT1,PHASEMIS jz data_phase_loop; + +/* This drops the last SG segment down to the shadow layer for us */ + if ((p->features & AHC_ULTRA2) != 0) { + mov DFCNTRL, DMAPARAMS; + test SSTAT0, SDONE jnz .; + } + +data_phase_finish: +/* + * After a DMA finishes, save the SG and STCNT residuals back into the SCB + * We use STCNT instead of HCNT, since it's a reflection of how many bytes + * were transferred on the SCSI (as opposed to the host) bus. + */ + if ((p->features & AHC_ULTRA2) != 0) { + call ultra2_dmafinish; + } + if ((p->features & AHC_ULTRA2) == 0) { + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_RESID_DCNT, STCNT, 3; + mov SCB_RESID_SGCNT, SG_COUNT; + } else { + mov SCB_RESID_DCNT[0],STCNT[0]; + mov SCB_RESID_DCNT[1],STCNT[1]; + mov SCB_RESID_DCNT[2],STCNT[2]; + mov SCB_RESID_SGCNT, SG_COUNT; + } + } + + jmp ITloop; + +data_phase_overrun: + if ((p->features & AHC_ULTRA2) != 0) { + call ultra2_dmafinish; + } +/* + * Turn off BITBUCKET mode and notify the host + */ + and SXFRCTL1, ~BITBUCKET; + mvi INTSTAT,DATA_OVERRUN; + jmp ITloop; + +ultra2_dmafinish: + if ((p->features & AHC_ULTRA2) != 0) { + test DFCNTRL, DIRECTION jnz ultra2_dmahalt; + and DFCNTRL, ~SCSIEN; + test DFCNTRL, SCSIEN jnz .; +ultra2_dmafifoflush: + or DFCNTRL, FIFOFLUSH; + test DFSTATUS, FIFOEMP jz . - 1; + /* + * hardware bug alert! This needless set of jumps is to + * protect against a FIFOEMP status bit glitch in the + * silicon. + */ + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; + test DFSTATUS, MREQPEND jnz .; +ultra2_dmahalt: + test SCSIOFFSET, 0x7f jnz ultra2_shutdown; +ultra2_await_nreq: + test SCSISIGI, REQI jz ultra2_shutdown; + test SSTAT1, (PHASEMIS|REQINIT) jz ultra2_await_nreq; +ultra2_shutdown: + and DFCNTRL, ~(HDMAEN|SCSIEN); + test DFCNTRL, (HDMAEN|SCSIEN) jnz .; + bmov SCB_RESID_DCNT, STCNT, 3; + mov SCB_RESID_SGCNT, SG_COUNT; + or SXFRCTL0, CLRSTCNT|CLRCHN; + ret; + } + +/* + * Command phase. Set up the DMA registers and let 'er rip. + */ +p_command: + call assert; + +/* + * Load HADDR and HCNT. + */ + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov HADDR, SCB_CMDPTR, 5; + bmov HCNT[1], ALLZEROS, 2; + if ((p->features & AHC_ULTRA2) == 0) { + bmov STCNT, HCNT, 3; + } + } else { + mvi DINDEX, HADDR; + mvi SCB_CMDPTR call bcopy_5; + clr HCNT[1]; + clr HCNT[2]; + call set_stcnt_from_hcnt; + } + + if ((p->features & AHC_ULTRA2) == 0) { + mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; + } else { + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); + test SSTAT0, SDONE jnz .; +p_command_dma_loop: + test SSTAT0, SDONE jnz p_command_ultra2_dma_done; + test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */ +p_command_ultra2_dma_done: + test SCSISIGI, REQI jz p_command_ultra2_shutdown; + test SSTAT1, (PHASEMIS|REQINIT) jz p_command_ultra2_dma_done; +p_command_ultra2_shutdown: + and DFCNTRL, ~(HDMAEN|SCSIEN); + test DFCNTRL, (HDMAEN|SCSIEN) jnz .; + or SXFRCTL0, CLRSTCNT|CLRCHN; + } + jmp ITloop; + +/* + * Status phase. Wait for the data byte to appear, then read it + * and store it into the SCB. + */ +p_status: + call assert; + + mov SCB_TARGET_STATUS, SCSIDATL; + jmp ITloop; + +/* + * Message out phase. If MSG_OUT is 0x80, build I full indentify message + * sequence and send it to the target. In addition, if the MK_MESSAGE bit + * is set in the SCB_CONTROL byte, interrupt the host and allow it to send + * it's own message. + * + * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. + * This is done to allow the hsot to send messages outside of an identify + * sequence while protecting the seqencer from testing the MK_MESSAGE bit + * on an SCB that might not be for the current nexus. (For example, a + * BDR message in responce to a bad reselection would leave us pointed to + * an SCB that doesn't have anything to do with the current target). + * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, + * bus device reset). + * + * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, + * in case the target decides to put us in this phase for some strange + * reason. + */ +p_mesgout_retry: + or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ +p_mesgout: + mov SINDEX, MSG_OUT; + cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; +p_mesgout_identify: + if ((p->features & AHC_WIDE) != 0) { + and SINDEX,0xf,SCB_TCL; /* lun */ + } else { + and SINDEX,0x7,SCB_TCL; /* lun */ + } + and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ + or SINDEX,A; /* or in disconnect privledge */ + or SINDEX,MSG_IDENTIFYFLAG; +p_mesgout_mk_message: + test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag; + mov SCSIDATL, SINDEX; /* Send the last byte */ + jmp p_mesgout_from_host + 1;/* Skip HOST_MSG test */ +/* + * Send a tag message if TAG_ENB is set in the SCB control block. + * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. + */ +p_mesgout_tag: + test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; + mov SCSIDATL, SINDEX; /* Send the identify message */ + call phase_lock; + cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; + and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; + call phase_lock; + cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; + mov SCB_TAG jmp p_mesgout_onebyte; +/* + * Interrupt the driver, and allow it to send a message + * if it asks. + */ +p_mesgout_from_host: + cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; + mvi INTSTAT,AWAITING_MSG; + nop; + /* + * Did the host detect a phase change? + */ + cmp RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done; + +p_mesgout_onebyte: + mvi CLRSINT1, CLRATNO; + mov SCSIDATL, SINDEX; + +/* + * If the next bus phase after ATN drops is a message out, it means + * that the target is requesting that the last message(s) be resent. + */ + call phase_lock; + cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; + +p_mesgout_done: + mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ + mov LAST_MSG, MSG_OUT; + cmp MSG_OUT, MSG_IDENTIFYFLAG jne . + 2; + and SCB_CONTROL, ~MK_MESSAGE; + mvi MSG_OUT, MSG_NOOP; /* No message left */ + jmp ITloop; + +/* + * Message in phase. Bytes are read using Automatic PIO mode. + */ +p_mesgin: + mvi ACCUM call inb_first; /* read the 1st message byte */ + + test A,MSG_IDENTIFYFLAG jnz mesgin_identify; + cmp A,MSG_DISCONNECT je mesgin_disconnect; + cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; + cmp ALLZEROS,A je mesgin_complete; + cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; + cmp A,MSG_EXTENDED je mesgin_extended; + cmp A,MSG_MESSAGE_REJECT je mesgin_reject; + cmp A,MSG_NOOP je mesgin_done; + cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_wide_residue; + +rej_mesgin: +/* + * We have no idea what this message in is, so we issue a message reject + * and hope for the best. In any case, rejection should be a rare + * occurrence - signal the driver when it happens. + */ + mvi INTSTAT,SEND_REJECT; /* let driver know */ + + mvi MSG_MESSAGE_REJECT call mk_mesg; + +mesgin_done: + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + jmp ITloop; + + +mesgin_complete: +/* + * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, + * and trigger a completion interrupt. Before doing so, check to see if there + * is a residual or the status byte is something other than STATUS_GOOD (0). + * In either of these conditions, we upload the SCB back to the host so it can + * process this information. In the case of a non zero status byte, we + * additionally interrupt the kernel driver synchronously, allowing it to + * decide if sense should be retrieved. If the kernel driver wishes to request + * sense, it will fill the kernel SCB with a request sense command and set + * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload + * the SCB, and process it as the next command by adding it to the waiting list. + * If the kernel driver does not wish to request sense, it need only clear + * RETURN_1, and the command is allowed to complete normally. We don't bother + * to post to the QOUTFIFO in the error cases since it would require extra + * work in the kernel driver to ensure that the entry was removed before the + * command complete code tried processing it. + */ + +/* + * First check for residuals + */ + test SCB_RESID_SGCNT,0xff jnz upload_scb; + test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */ +upload_scb: + mvi DMAPARAMS, FIFORESET; + mov SCB_TAG call dma_scb; +check_status: + test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ + mvi INTSTAT,BAD_STATUS; /* let driver know */ + nop; + cmp RETURN_1, SEND_SENSE jne complete; + /* This SCB becomes the next to execute as it will retrieve sense */ + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + mov SCB_TAG call dma_scb; +add_to_waiting_list: + mov SCB_NEXT,WAITING_SCBH; + mov WAITING_SCBH, SCBPTR; + /* + * Prepare our selection hardware before the busfree so we have a + * high probability of winning arbitration. + */ + call start_selection; + jmp await_busfree; + +complete: + /* If we are untagged, clear our address up in host ram */ + test SCB_CONTROL, TAG_ENB jnz complete_post; + mov A, SAVED_TCL; + mvi UNTAGGEDSCB_OFFSET call post_byte_setup; + mvi SCB_LIST_NULL call post_byte; + +complete_post: + /* Post the SCB and issue an interrupt */ + if ((p->features & AHC_QUEUE_REGS) != 0) { + mov A, SDSCB_QOFF; + } else { + mov A, QOUTPOS; + } + mvi QOUTFIFO_OFFSET call post_byte_setup; + mov SCB_TAG call post_byte; + if ((p->features & AHC_QUEUE_REGS) == 0) { + inc QOUTPOS; + } + mvi INTSTAT,CMDCMPLT; + +add_to_free_list: + call add_scb_to_free_list; + jmp await_busfree; + +/* + * Is it an extended message? Copy the message to our message buffer and + * notify the host. The host will tell us whether to reject this message, + * respond to it with the message that the host placed in our message buffer, + * or simply to do nothing. + */ +mesgin_extended: + mvi INTSTAT,EXTENDED_MSG; /* let driver know */ + jmp ITloop; + +/* + * Is it a disconnect message? Set a flag in the SCB to remind us + * and await the bus going free. + */ +mesgin_disconnect: + or SCB_CONTROL,DISCONNECTED; + call add_scb_to_disc_list; + jmp await_busfree; + +/* + * Save data pointers message: + * Copying RAM values back to SCB, for Save Data Pointers message, but + * only if we've actually been into a data phase to change them. This + * protects against bogus data in scratch ram and the residual counts + * since they are only initialized when we go into data_in or data_out. + */ +mesgin_sdptrs: + test SEQ_FLAGS, DPHASE jz mesgin_done; + /* + * The SCB SGPTR becomes the next one we'll download, + * and the SCB DATAPTR becomes the current SHADDR. + * Use the residual number since STCNT is corrupted by + * any message transfer. + */ + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov SCB_SGCOUNT, SG_COUNT, 5; + bmov SCB_DATAPTR, SHADDR, 4; + bmov SCB_DATACNT, SCB_RESID_DCNT, 3; + } else { + mvi DINDEX, SCB_SGCOUNT; + mvi SG_COUNT call bcopy_5; + mvi DINDEX, SCB_DATAPTR; + mvi SHADDR call bcopy_4; + mvi SCB_RESID_DCNT call bcopy_3; + } + jmp mesgin_done; + +/* + * Restore pointers message? Data pointers are recopied from the + * SCB anytime we enter a data phase for the first time, so all + * we need to do is clear the DPHASE flag and let the data phase + * code do the rest. + */ +mesgin_rdptrs: + and SEQ_FLAGS, ~DPHASE; /* + * We'll reload them + * the next time through + * the dataphase. + */ + jmp mesgin_done; + +/* + * Identify message? For a reconnecting target, this tells us the lun + * that the reconnection is for - find the correct SCB and switch to it, + * clearing the "disconnected" bit so we don't "find" it by accident later. + */ +mesgin_identify: + + if ((p->features & AHC_WIDE) != 0) { + and A,0x0f; /* lun in lower four bits */ + } else { + and A,0x07; /* lun in lower three bits */ + } + or SAVED_TCL,A; /* SAVED_TCL should be complete now */ + + mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ + call get_untagged_SCBID; + cmp ARG_1, SCB_LIST_NULL je snoop_tag; + if ((p->flags & AHC_PAGESCBS) != 0) { + test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; + } + /* + * If the SCB was found in the disconnected list (as is + * always the case in non-paging scenarios), SCBPTR is already + * set to the correct SCB. So, simply setup the SCB and get + * on with things. + */ + mov SCBPTR call rem_scb_from_disc_list; + jmp setup_SCB; +/* + * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. + * If we get one, we use the tag returned to find the proper + * SCB. With SCB paging, this requires using search for both tagged + * and non-tagged transactions since the SCB may exist in any slot. + * If we're not using SCB paging, we can use the tag as the direct + * index to the SCB. + */ +snoop_tag: + mov NONE,SCSIDATL; /* ACK Identify MSG */ +snoop_tag_loop: + call phase_lock; + cmp LASTPHASE, P_MESGIN jne not_found; + cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; +get_tag: + mvi ARG_1 call inb_next; /* tag value */ + +use_retrieveSCB: + call retrieveSCB; +setup_SCB: + mov A, SAVED_TCL; + cmp SCB_TCL, A jne not_found_cleanup_scb; + test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; + and SCB_CONTROL,~DISCONNECTED; + or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ + /* See if the host wants to send a message upon reconnection */ + test SCB_CONTROL, MK_MESSAGE jz mesgin_done; + and SCB_CONTROL, ~MK_MESSAGE; + mvi HOST_MSG call mk_mesg; + jmp mesgin_done; + +not_found_cleanup_scb: + test SCB_CONTROL, DISCONNECTED jz . + 3; + call add_scb_to_disc_list; + jmp not_found; + call add_scb_to_free_list; +not_found: + mvi INTSTAT, NO_MATCH; + mvi MSG_BUS_DEV_RESET call mk_mesg; + jmp mesgin_done; + +/* + * Message reject? Let the kernel driver handle this. If we have an + * outstanding WDTR or SDTR negotiation, assume that it's a response from + * the target selecting 8bit or asynchronous transfer, otherwise just ignore + * it since we have no clue what it pertains to. + */ +mesgin_reject: + mvi INTSTAT, REJECT_MSG; + jmp mesgin_done; + +/* + * Wide Residue. We handle the simple cases, but pass of the one hard case + * to the kernel (when the residue byte happened to cause us to advance our + * sg element array, so we know have to back that advance out). + */ +mesgin_wide_residue: + mvi ARG_1 call inb_next; /* ACK the wide_residue and get */ + /* the size byte */ +/* + * In order for this to be reliable, we have to do all sorts of horrible + * magic in terms of resetting the datafifo and reloading the shadow layer + * with the correct new values (so that a subsequent save data pointers + * message will do the right thing). We let the kernel do that work. + */ + mvi INTSTAT, WIDE_RESIDUE; + jmp mesgin_done; + +/* + * [ ADD MORE MESSAGE HANDLING HERE ] + */ + +/* + * Locking the driver out, build a one-byte message passed in SINDEX + * if there is no active message already. SINDEX is returned intact. + */ +mk_mesg: + or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ + mov MSG_OUT,SINDEX ret; + +/* + * Functions to read data in Automatic PIO mode. + * + * According to Adaptec's documentation, an ACK is not sent on input from + * the target until SCSIDATL is read from. So we wait until SCSIDATL is + * latched (the usual way), then read the data byte directly off the bus + * using SCSIBUSL. When we have pulled the ATN line, or we just want to + * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI + * spec guarantees that the target will hold the data byte on the bus until + * we send our ACK. + * + * The assumption here is that these are called in a particular sequence, + * and that REQ is already set when inb_first is called. inb_{first,next} + * use the same calling convention as inb. + */ + +inb_next: + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ +inb_next_wait: + /* + * If there is a parity error, wait for the kernel to + * see the interrupt and prepare our message response + * before continuing. + */ + test SSTAT1, REQINIT jz inb_next_wait; + test SSTAT1, SCSIPERR jnz .; + and LASTPHASE, PHASE_MASK, SCSISIGI; + cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; +inb_first: + mov DINDEX,SINDEX; + mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ +inb_last: + mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ + +mesgin_phasemis: +/* + * We expected to receive another byte, but the target changed phase + */ + mvi INTSTAT, MSGIN_PHASEMIS; + jmp ITloop; + +/* + * DMA data transfer. HADDR and HCNT must be loaded first, and + * SINDEX should contain the value to load DFCNTRL with - 0x3d for + * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared + * during initialization. + */ +if ((p->features & AHC_ULTRA2) == 0) { +dma: + mov DFCNTRL,SINDEX; +dma_loop: + test SSTAT0,DMADONE jnz dma_dmadone; + test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ +dma_phasemis: + test SSTAT0,SDONE jnz dma_checkfifo; + mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ + +/* + * We will be "done" DMAing when the transfer count goes to zero, or + * the target changes the phase (in light of this, it makes sense that + * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are + * doing a SCSI->Host transfer, the data FIFO should be flushed auto- + * magically on STCNT=0 or a phase change, so just wait for FIFO empty + * status. + */ +dma_checkfifo: + test DFCNTRL,DIRECTION jnz dma_fifoempty; +dma_fifoflush: + test DFSTATUS,FIFOEMP jz dma_fifoflush; + +dma_fifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz dma_fifoempty; +/* + * Now shut the DMA enables off and make sure that the DMA enables are + * actually off first lest we get an ILLSADDR. + */ +dma_dmadone: + cmp LASTPHASE, P_COMMAND je dma_await_nreq; + test SCSIRATE, 0x0f jnz dma_shutdown; +dma_await_nreq: + test SCSISIGI, REQI jz dma_shutdown; + test SSTAT1, (PHASEMIS|REQINIT) jz dma_await_nreq; +dma_shutdown: + and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); +dma_halt: + /* + * Some revisions of the aic7880 have a problem where, if the + * data fifo is full, but the PCI input latch is not empty, + * HDMAEN cannot be cleared. The fix used here is to attempt + * to drain the data fifo until there is space for the input + * latch to drain and HDMAEN de-asserts. + */ + mov NONE, DFDAT; + test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; +} +return: + ret; + +/* + * Assert that if we've been reselected, then we've seen an IDENTIFY + * message. + */ +assert: + test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ + + mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ + +/* + * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) + * or by the SCBID ARG_1. The search begins at the SCB index passed in + * via SINDEX which is an SCB that must be on the disconnected list. If + * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR + * is set to the proper SCB. + */ +findSCB: + mov SCBPTR,SINDEX; /* Initialize SCBPTR */ + cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; + mov A, SAVED_TCL; + mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */ +findSCB_by_SCBID: + mov A, ARG_1; /* Tag passed in ARG_1 */ + mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ +findSCB_next: + mov ARG_2, SCBPTR; + cmp SCB_NEXT, SCB_LIST_NULL je notFound; + mov SCBPTR,SCB_NEXT; + dec SINDEX; /* Last comparison moved us too far */ +findSCB_loop: + cmp SINDIR, A jne findSCB_next; + mov SINDEX, SCBPTR ret; +notFound: + mvi SINDEX, SCB_LIST_NULL ret; + +/* + * Retrieve an SCB by SCBID first searching the disconnected list falling + * back to DMA'ing the SCB down from the host. This routine assumes that + * ARG_1 is the SCBID of interrest and that SINDEX is the position in the + * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, + * we go directly to the host for the SCB. + */ +retrieveSCB: + test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; + mov SCBPTR call findSCB; /* Continue the search */ + cmp SINDEX, SCB_LIST_NULL je retrieve_from_host; + +/* + * This routine expects SINDEX to contain the index of the SCB to be + * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the + * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL + * if it is at the head. + */ +rem_scb_from_disc_list: +/* Remove this SCB from the disconnection list */ + cmp ARG_2, SCB_LIST_NULL je rHead; + mov DINDEX, SCB_NEXT; + mov SCBPTR, ARG_2; + mov SCB_NEXT, DINDEX; + mov SCBPTR, SINDEX ret; +rHead: + mov DISCONNECTED_SCBH,SCB_NEXT ret; + +retrieve_from_host: +/* + * We didn't find it. Pull an SCB and DMA down the one we want. + * We should never get here in the non-paging case. + */ + mov ALLZEROS call get_free_or_disc_scb; + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + /* Jump instead of call as we want to return anyway */ + mov ARG_1 jmp dma_scb; + +/* + * Determine whether a target is using tagged or non-tagged transactions + * by first looking for a matching transaction based on the TCL and if + * that fails, looking up this device in the host's untagged SCB array. + * The TCL to search for is assumed to be in SAVED_TCL. The value is + * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). + * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information + * in an SCB instead of having to go to the host. + */ +get_untagged_SCBID: + cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; + mvi ARG_1, SCB_LIST_NULL; + mov DISCONNECTED_SCBH call findSCB; + cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; + or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ + test SCB_CONTROL, TAG_ENB jnz . + 2; + mov ARG_1, SCB_TAG ret; + mvi ARG_1, SCB_LIST_NULL ret; + +/* + * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) + * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. + */ +fetch_byte: + mov ARG_2, SINDEX; + if ((p->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi CCHCNT, 1; + mvi CCSGCTL, CCSGEN|CCSGRESET; + test CCSGCTL, CCSGDONE jz .; + mvi CCSGCTL, CCSGRESET; + bmov RETURN_2, CCSGRAM, 1 ret; + } else { + mvi DINDEX, HADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi HCNT[0], 1; + clr HCNT[1]; + clr HCNT[2]; + mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; + call dma_finish; + mov RETURN_2, DFDAT ret; + } + +/* + * Prepare the hardware to post a byte to host memory given an + * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. + */ +post_byte_setup: + mov ARG_2, SINDEX; + if ((p->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi CCHCNT, 1; + mvi CCSCBCTL, CCSCBRESET ret; + } else { + mvi DINDEX, HADDR; + mvi SCBID_ADDR call set_1byte_addr; + mvi HCNT[0], 1; + clr HCNT[1]; + clr HCNT[2]; + mvi DFCNTRL, FIFORESET ret; + } + +post_byte: + if ((p->features & AHC_CMD_CHAN) != 0) { + bmov CCSCBRAM, SINDEX, 1; + or CCSCBCTL, CCSCBEN|CCSCBRESET; + test CCSCBCTL, CCSCBDONE jz .; + clr CCSCBCTL ret; + } else { + mov DFDAT, SINDEX; + or DFCNTRL, HDMAEN|FIFOFLUSH; + jmp dma_finish; + } + +get_SCBID_from_host: + mov A, SAVED_TCL; + mvi UNTAGGEDSCB_OFFSET call fetch_byte; + mov RETURN_1, RETURN_2 ret; + +phase_lock: + test SSTAT1, REQINIT jz phase_lock; + test SSTAT1, SCSIPERR jnz phase_lock; + and SCSISIGO, PHASE_MASK, SCSISIGI; + and LASTPHASE, PHASE_MASK, SCSISIGI ret; + +if ((p->features & AHC_CMD_CHAN) == 0) { +set_stcnt_from_hcnt: + mov STCNT[0], HCNT[0]; + mov STCNT[1], HCNT[1]; + mov STCNT[2], HCNT[2] ret; + +bcopy_7: + mov DINDIR, SINDIR; + mov DINDIR, SINDIR; +bcopy_5: + mov DINDIR, SINDIR; +bcopy_4: + mov DINDIR, SINDIR; +bcopy_3: + mov DINDIR, SINDIR; + mov DINDIR, SINDIR; + mov DINDIR, SINDIR ret; +} + +/* + * Setup addr assuming that A is an index into + * an array of 32byte objects, SINDEX contains + * the base address of that array, and DINDEX + * contains the base address of the location + * to store the indexed address. + */ +set_32byte_addr: + shr ARG_2, 3, A; + shl A, 5; +/* + * Setup addr assuming that A + (ARG_1 * 256) is an + * index into an array of 1byte objects, SINDEX contains + * the base address of that array, and DINDEX contains + * the base address of the location to store the computed + * address. + */ +set_1byte_addr: + add DINDIR, A, SINDIR; + mov A, ARG_2; + adc DINDIR, A, SINDIR; + clr A; + adc DINDIR, A, SINDIR; + adc DINDIR, A, SINDIR ret; + +/* + * Either post or fetch and SCB from host memory based on the + * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. + */ +dma_scb: + mov A, SINDEX; + if ((p->features & AHC_CMD_CHAN) != 0) { + mvi DINDEX, CCHADDR; + mvi HSCB_ADDR call set_32byte_addr; + mov CCSCBPTR, SCBPTR; + mvi CCHCNT, 32; + test DMAPARAMS, DIRECTION jz dma_scb_tohost; + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; + jmp dma_scb_finish; +dma_scb_tohost: + if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { + mvi CCSCBCTL, CCSCBRESET; + bmov CCSCBRAM, SCB_CONTROL, 32; + or CCSCBCTL, CCSCBEN|CCSCBRESET; + test CCSCBCTL, CCSCBDONE jz .; + } else { + mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; + cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; + } +dma_scb_finish: + clr CCSCBCTL; + test CCSCBCTL, CCARREN|CCSCBEN jnz .; + ret; + } else { + mvi DINDEX, HADDR; + mvi HSCB_ADDR call set_32byte_addr; + mvi HCNT[0], 32; + clr HCNT[1]; + clr HCNT[2]; + mov DFCNTRL, DMAPARAMS; + test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; + /* Fill it with the SCB data */ +copy_scb_tofifo: + mvi SINDEX, SCB_CONTROL; + add A, 32, SINDEX; +copy_scb_tofifo_loop: + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + mov DFDAT,SINDIR; + cmp SINDEX, A jne copy_scb_tofifo_loop; + or DFCNTRL, HDMAEN|FIFOFLUSH; +dma_scb_fromhost: + call dma_finish; + /* If we were putting the SCB, we are done */ + test DMAPARAMS, DIRECTION jz return; + mvi SCB_CONTROL call dfdat_in_7; + call dfdat_in_7_continued; + call dfdat_in_7_continued; + jmp dfdat_in_7_continued; +dfdat_in_7: + mov DINDEX,SINDEX; +dfdat_in_7_continued: + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT; + mov DINDIR,DFDAT ret; + } + + +/* + * Wait for DMA from host memory to data FIFO to complete, then disable + * DMA and wait for it to acknowledge that it's off. + */ +if ((p->features & AHC_CMD_CHAN) == 0) { +dma_finish: + test DFSTATUS,HDONE jz dma_finish; + /* Turn off DMA */ + and DFCNTRL, ~HDMAEN; + test DFCNTRL, HDMAEN jnz .; + ret; +} + +add_scb_to_free_list: + if ((p->flags & AHC_PAGESCBS) != 0) { + mov SCB_NEXT, FREE_SCBH; + mov FREE_SCBH, SCBPTR; + } + mvi SCB_TAG, SCB_LIST_NULL ret; + +if ((p->flags & AHC_PAGESCBS) != 0) { +get_free_or_disc_scb: + cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; + cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; +return_error: + mvi SINDEX, SCB_LIST_NULL ret; +dequeue_disc_scb: + mov SCBPTR, DISCONNECTED_SCBH; +dma_up_scb: + mvi DMAPARAMS, FIFORESET; + mov SCB_TAG call dma_scb; +unlink_disc_scb: + mov DISCONNECTED_SCBH, SCB_NEXT ret; +dequeue_free_scb: + mov SCBPTR, FREE_SCBH; + mov FREE_SCBH, SCB_NEXT ret; +} + +add_scb_to_disc_list: +/* + * Link this SCB into the DISCONNECTED list. This list holds the + * candidates for paging out an SCB if one is needed for a new command. + * Modifying the disconnected list is a critical(pause dissabled) section. + */ + mov SCB_NEXT, DISCONNECTED_SCBH; + mov DISCONNECTED_SCBH, SCBPTR ret; diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c --- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Sun Mar 4 14:30:19 2001 @@ -0,0 +1,413 @@ +/*+M************************************************************************* + * Adaptec AIC7xxx device driver proc support for Linux. + * + * Copyright (c) 1995, 1996 Dean W. Gehnert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * ---------------------------------------------------------------- + * o Modified from the EATA-DMA /proc support. + * o Additional support for device block statistics provided by + * Matthew Jacob. + * o Correction of overflow by Heinz Mauelshagen + * o Adittional corrections by Doug Ledford + * + * Dean W. Gehnert, deang@teleport.com, 05/01/96 + * + * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ + *-M*************************************************************************/ + +#include + +#define BLS (&aic7xxx_buffer[size]) +#define HDRB \ +" < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+" + +#ifdef PROC_DEBUG +extern int vsprintf(char *, const char *, va_list); + +static void +proc_debug(const char *fmt, ...) +{ + va_list ap; + char buf[256]; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + printk(buf); + va_end(ap); +} +#else /* PROC_DEBUG */ +# define proc_debug(fmt, args...) +#endif /* PROC_DEBUG */ + +static int aic7xxx_buffer_size = 0; +static char *aic7xxx_buffer = NULL; + + +/*+F************************************************************************* + * Function: + * aic7xxx_set_info + * + * Description: + * Set parameters for the driver from the /proc filesystem. + *-F*************************************************************************/ +int +aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) +{ + proc_debug("aic7xxx_set_info(): %s\n", buffer); + return (-ENOSYS); /* Currently this is a no-op */ +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_proc_info + * + * Description: + * Return information to handle /proc support for the driver. + *-F*************************************************************************/ +int +aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, + int hostno, int inout) +{ + struct Scsi_Host *HBAptr; + struct aic7xxx_host *p; + int size = 0; + unsigned char i; + struct aic7xxx_xferstats *sp; + unsigned char target; + + HBAptr = NULL; + + for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next) + ; + + if (!p) + { + size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + if (size > length) + { + return (size); + } + else + { + return (length); + } + } + + HBAptr = p->host; + + if (inout == TRUE) /* Has data been written to the file? */ + { + return (aic7xxx_set_info(buffer, length, HBAptr)); + } + + p = (struct aic7xxx_host *) HBAptr->hostdata; + + /* + * It takes roughly 1K of space to hold all relevant card info, not + * counting any proc stats, so we start out with a 1.5k buffer size and + * if proc_stats is defined, then we sweep the stats structure to see + * how many drives we will be printing out for and add 384 bytes per + * device with active stats. + * + * Hmmmm...that 1.5k seems to keep growing as items get added so they + * can be easily viewed for debugging purposes. So, we bumped that + * 1.5k to 4k so we can quit having to bump it all the time. + */ + + size = 4096; + for (target = 0; target < MAX_TARGETS; target++) + { + if (p->dev_flags[target] & DEVICE_PRESENT) +#ifdef AIC7XXX_PROC_STATS + size += 512; +#else + size += 256; +#endif + } + if (aic7xxx_buffer_size != size) + { + if (aic7xxx_buffer != NULL) + { + kfree(aic7xxx_buffer); + aic7xxx_buffer_size = 0; + } + aic7xxx_buffer = kmalloc(size, GFP_KERNEL); + } + if (aic7xxx_buffer == NULL) + { + size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n", + __LINE__); + return size; + } + aic7xxx_buffer_size = size; + + size = 0; + size += sprintf(BLS, "Adaptec AIC7xxx driver version: "); + size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION); + size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Compile Options:\n"); +#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT + size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n"); +#else + size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n"); +#endif +#ifdef AIC7XXX_PROC_STATS + size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n"); +#else + size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); +#endif + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Adapter Configuration:\n"); + size += sprintf(BLS, " SCSI Adapter: %s\n", + board_names[p->board_name_index]); + if (p->flags & AHC_TWIN) + size += sprintf(BLS, " Twin Channel Controller "); + else + { + char *channel = ""; + char *ultra = ""; + char *wide = "Narrow "; + if (p->flags & AHC_MULTI_CHANNEL) + { + channel = " Channel A"; + if (p->flags & (AHC_CHNLB|AHC_CHNLC)) + channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C"; + } + if (p->features & AHC_WIDE) + wide = "Wide "; + if (p->features & AHC_ULTRA3) + { + switch(p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7892: + case AHC_AIC7899: + ultra = "Ultra-160/m LVD/SE "; + break; + default: + ultra = "Ultra-3 LVD/SE "; + break; + } + } + else if (p->features & AHC_ULTRA2) + ultra = "Ultra-2 LVD/SE "; + else if (p->features & AHC_ULTRA) + ultra = "Ultra "; + size += sprintf(BLS, " %s%sController%s ", + ultra, wide, channel); + } + switch(p->chip & ~AHC_CHIPID_MASK) + { + case AHC_VL: + size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn); + break; + case AHC_EISA: + size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn); + break; + default: + size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus, + PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn)); + break; + } + if( !(p->maddr) ) + { + size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base); + } + else + { + size += sprintf(BLS, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase); + } + if( (p->chip & (AHC_VL | AHC_EISA)) ) + { + size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address); + } + size += sprintf(BLS, " Adapter SEEPROM Config: %s\n", + (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." : + ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." : + "SEEPROM not found, using leftover BIOS values.") ); + size += sprintf(BLS, " Adaptec SCSI BIOS: %s\n", + (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled"); + size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); + size += sprintf(BLS, " SCBs: Active %d, Max Active %d,\n", + p->activescbs, p->max_activescbs); + size += sprintf(BLS, " Allocated %d, HW %d, " + "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs, + p->scb_data->maxscbs); + if (p->flags & AHC_EXTERNAL_SRAM) + size += sprintf(BLS, " Using External SCB SRAM\n"); + size += sprintf(BLS, " Interrupts: %ld", p->isr_count); + if (p->chip & AHC_EISA) + { + size += sprintf(BLS, " %s\n", + (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)"); + } + else + { + size += sprintf(BLS, "\n"); + } + size += sprintf(BLS, " BIOS Control Word: 0x%04x\n", + p->bios_control); + size += sprintf(BLS, " Adapter Control Word: 0x%04x\n", + p->adapter_control); + size += sprintf(BLS, " Extended Translation: %sabled\n", + (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis"); + size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable); + if (p->features & (AHC_ULTRA | AHC_ULTRA2)) + { + size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb); + } + size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable); + size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag); + size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE); + size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host " + "instance %d:\n", p->instance); + size += sprintf(BLS, " {"); + for(i=0; i < (MAX_TARGETS - 1); i++) + size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]); + size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]); + size += sprintf(BLS, " Actual queue depth per device for aic7xxx host " + "instance %d:\n", p->instance); + size += sprintf(BLS, " {"); + for(i=0; i < (MAX_TARGETS - 1); i++) + size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]); + size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]); + + size += sprintf(BLS, "\n"); + size += sprintf(BLS, "Statistics:\n\n"); + for (target = 0; target < MAX_TARGETS; target++) + { + sp = &p->stats[target]; + if ((p->dev_flags[target] & DEVICE_PRESENT) == 0) + { + continue; + } + if (p->features & AHC_TWIN) + { + size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", + p->host_no, (target >> 3), (target & 0x7), 0); + } + else + { + size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", + p->host_no, 0, target, 0); + } + size += sprintf(BLS, " Device using %s/%s", + (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ? + "Wide" : "Narrow", + (p->transinfo[target].cur_offset != 0) ? + "Sync transfers at " : "Async transfers.\n" ); + if (p->transinfo[target].cur_offset != 0) + { + struct aic7xxx_syncrate *sync_rate; + unsigned char options = p->transinfo[target].cur_options; + int period = p->transinfo[target].cur_period; + int rate = (p->transinfo[target].cur_width == + MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0; + + sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options); + if (sync_rate != NULL) + { + size += sprintf(BLS, "%s MByte/sec, offset %d\n", + sync_rate->rate[rate], + p->transinfo[target].cur_offset ); + } + else + { + size += sprintf(BLS, "3.3 MByte/sec, offset %d\n", + p->transinfo[target].cur_offset ); + } + } + size += sprintf(BLS, " Transinfo settings: "); + size += sprintf(BLS, "current(%d/%d/%d/%d), ", + p->transinfo[target].cur_period, + p->transinfo[target].cur_offset, + p->transinfo[target].cur_width, + p->transinfo[target].cur_options); + size += sprintf(BLS, "goal(%d/%d/%d/%d), ", + p->transinfo[target].goal_period, + p->transinfo[target].goal_offset, + p->transinfo[target].goal_width, + p->transinfo[target].goal_options); + size += sprintf(BLS, "user(%d/%d/%d/%d)\n", + p->transinfo[target].user_period, + p->transinfo[target].user_offset, + p->transinfo[target].user_width, + p->transinfo[target].user_options); +#ifdef AIC7XXX_PROC_STATS + size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", + sp->r_total + sp->w_total, sp->r_total, sp->w_total); + size += sprintf(BLS, "%s\n", HDRB); + size += sprintf(BLS, " Reads:"); + for (i = 0; i < NUMBER(sp->r_bins); i++) + { + size += sprintf(BLS, " %7ld", sp->r_bins[i]); + } + size += sprintf(BLS, "\n"); + size += sprintf(BLS, " Writes:"); + for (i = 0; i < NUMBER(sp->w_bins); i++) + { + size += sprintf(BLS, " %7ld", sp->w_bins[i]); + } + size += sprintf(BLS, "\n"); +#else + size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", + sp->r_total + sp->w_total, sp->r_total, sp->w_total); +#endif /* AIC7XXX_PROC_STATS */ + size += sprintf(BLS, "\n\n"); + } + + if (size >= aic7xxx_buffer_size) + { + printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n"); + } + + if (offset > size - 1) + { + kfree(aic7xxx_buffer); + aic7xxx_buffer = NULL; + aic7xxx_buffer_size = length = 0; + *start = NULL; + } + else + { + *start = buffer; + length = MIN(length, size - offset); + memcpy(buffer, &aic7xxx_buffer[offset], length); + } + + return (length); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 2 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h --- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h Sun Mar 4 14:30:19 2001 @@ -0,0 +1,629 @@ +/* + * DO NOT EDIT - This file is automatically generated. + */ + +#define SCSISEQ 0x00 +#define TEMODE 0x80 +#define ENSELO 0x40 +#define ENSELI 0x20 +#define ENRSELI 0x10 +#define ENAUTOATNO 0x08 +#define ENAUTOATNI 0x04 +#define ENAUTOATNP 0x02 +#define SCSIRSTO 0x01 + +#define SXFRCTL0 0x01 +#define DFON 0x80 +#define DFPEXP 0x40 +#define FAST20 0x20 +#define CLRSTCNT 0x10 +#define SPIOEN 0x08 +#define SCAMEN 0x04 +#define CLRCHN 0x02 + +#define SXFRCTL1 0x02 +#define BITBUCKET 0x80 +#define SWRAPEN 0x40 +#define ENSPCHK 0x20 +#define STIMESEL 0x18 +#define ENSTIMER 0x04 +#define ACTNEGEN 0x02 +#define STPWEN 0x01 + +#define SCSISIGO 0x03 +#define CDO 0x80 +#define IOO 0x40 +#define MSGO 0x20 +#define ATNO 0x10 +#define SELO 0x08 +#define BSYO 0x04 +#define REQO 0x02 +#define ACKO 0x01 + +#define SCSISIGI 0x03 +#define ATNI 0x10 +#define SELI 0x08 +#define BSYI 0x04 +#define REQI 0x02 +#define ACKI 0x01 + +#define SCSIRATE 0x04 +#define WIDEXFER 0x80 +#define SXFR_ULTRA2 0x7f +#define SXFR 0x70 +#define SOFS 0x0f + +#define SCSIID 0x05 +#define SCSIOFFSET 0x05 +#define SOFS_ULTRA2 0x7f + +#define SCSIDATL 0x06 + +#define SCSIDATH 0x07 + +#define STCNT 0x08 + +#define OPTIONMODE 0x08 +#define AUTORATEEN 0x80 +#define AUTOACKEN 0x40 +#define ATNMGMNTEN 0x20 +#define BUSFREEREV 0x10 +#define EXPPHASEDIS 0x08 +#define SCSIDATL_IMGEN 0x04 +#define AUTO_MSGOUT_DE 0x02 +#define DIS_MSGIN_DUALEDGE 0x01 + +#define CLRSINT0 0x0b +#define CLRSELDO 0x40 +#define CLRSELDI 0x20 +#define CLRSELINGO 0x10 +#define CLRSWRAP 0x08 +#define CLRSPIORDY 0x02 + +#define SSTAT0 0x0b +#define TARGET 0x80 +#define SELDO 0x40 +#define SELDI 0x20 +#define SELINGO 0x10 +#define IOERR 0x08 +#define SWRAP 0x08 +#define SDONE 0x04 +#define SPIORDY 0x02 +#define DMADONE 0x01 + +#define CLRSINT1 0x0c +#define CLRSELTIMEO 0x80 +#define CLRATNO 0x40 +#define CLRSCSIRSTI 0x20 +#define CLRBUSFREE 0x08 +#define CLRSCSIPERR 0x04 +#define CLRPHASECHG 0x02 +#define CLRREQINIT 0x01 + +#define SSTAT1 0x0c +#define SELTO 0x80 +#define ATNTARG 0x40 +#define SCSIRSTI 0x20 +#define PHASEMIS 0x10 +#define BUSFREE 0x08 +#define SCSIPERR 0x04 +#define PHASECHG 0x02 +#define REQINIT 0x01 + +#define SSTAT2 0x0d +#define OVERRUN 0x80 +#define SHVALID 0x40 +#define WIDE_RES 0x20 +#define SFCNT 0x1f +#define EXP_ACTIVE 0x10 +#define CRCVALERR 0x08 +#define CRCENDERR 0x04 +#define CRCREQERR 0x02 +#define DUAL_EDGE_ERROR 0x01 + +#define SSTAT3 0x0e +#define SCSICNT 0xf0 +#define OFFCNT 0x0f + +#define SCSIID_ULTRA2 0x0f +#define OID 0x0f + +#define SIMODE0 0x10 +#define ENSELDO 0x40 +#define ENSELDI 0x20 +#define ENSELINGO 0x10 +#define ENIOERR 0x08 +#define ENSWRAP 0x08 +#define ENSDONE 0x04 +#define ENSPIORDY 0x02 +#define ENDMADONE 0x01 + +#define SIMODE1 0x11 +#define ENSELTIMO 0x80 +#define ENATNTARG 0x40 +#define ENSCSIRST 0x20 +#define ENPHASEMIS 0x10 +#define ENBUSFREE 0x08 +#define ENSCSIPERR 0x04 +#define ENPHASECHG 0x02 +#define ENREQINIT 0x01 + +#define SCSIBUSL 0x12 + +#define SCSIBUSH 0x13 + +#define SHADDR 0x14 + +#define SELTIMER 0x18 +#define STAGE6 0x20 +#define STAGE5 0x10 +#define STAGE4 0x08 +#define STAGE3 0x04 +#define STAGE2 0x02 +#define STAGE1 0x01 + +#define SELID 0x19 +#define SELID_MASK 0xf0 +#define ONEBIT 0x08 + +#define SPIOCAP 0x1b +#define SOFT1 0x80 +#define SOFT0 0x40 +#define SOFTCMDEN 0x20 +#define HAS_BRDCTL 0x10 +#define SEEPROM 0x08 +#define EEPROM 0x04 +#define ROM 0x02 +#define SSPIOCPS 0x01 + +#define BRDCTL 0x1d +#define BRDDAT7 0x80 +#define BRDDAT6 0x40 +#define BRDDAT5 0x20 +#define BRDDAT4 0x10 +#define BRDSTB 0x10 +#define BRDCS 0x08 +#define BRDDAT3 0x08 +#define BRDDAT2 0x04 +#define BRDRW 0x04 +#define BRDRW_ULTRA2 0x02 +#define BRDCTL1 0x02 +#define BRDCTL0 0x01 +#define BRDSTB_ULTRA2 0x01 + +#define SEECTL 0x1e +#define EXTARBACK 0x80 +#define EXTARBREQ 0x40 +#define SEEMS 0x20 +#define SEERDY 0x10 +#define SEECS 0x08 +#define SEECK 0x04 +#define SEEDO 0x02 +#define SEEDI 0x01 + +#define SBLKCTL 0x1f +#define DIAGLEDEN 0x80 +#define DIAGLEDON 0x40 +#define AUTOFLUSHDIS 0x20 +#define ENAB40 0x08 +#define ENAB20 0x04 +#define SELWIDE 0x02 +#define XCVR 0x01 + +#define SRAM_BASE 0x20 + +#define TARG_SCSIRATE 0x20 + +#define ULTRA_ENB 0x30 + +#define DISC_DSB 0x32 + +#define MSG_OUT 0x34 + +#define DMAPARAMS 0x35 +#define PRELOADEN 0x80 +#define WIDEODD 0x40 +#define SCSIEN 0x20 +#define SDMAENACK 0x10 +#define SDMAEN 0x10 +#define HDMAEN 0x08 +#define HDMAENACK 0x08 +#define DIRECTION 0x04 +#define FIFOFLUSH 0x02 +#define FIFORESET 0x01 + +#define SEQ_FLAGS 0x36 +#define IDENTIFY_SEEN 0x80 +#define SCBPTR_VALID 0x20 +#define DPHASE 0x10 +#define AMTARGET 0x08 +#define WIDE_BUS 0x02 +#define TWIN_BUS 0x01 + +#define SAVED_TCL 0x37 + +#define SG_COUNT 0x38 + +#define SG_NEXT 0x39 + +#define LASTPHASE 0x3d +#define P_MESGIN 0xe0 +#define PHASE_MASK 0xe0 +#define P_STATUS 0xc0 +#define P_MESGOUT 0xa0 +#define P_COMMAND 0x80 +#define CDI 0x80 +#define IOI 0x40 +#define P_DATAIN 0x40 +#define MSGI 0x20 +#define P_BUSFREE 0x01 +#define P_DATAOUT 0x00 + +#define WAITING_SCBH 0x3e + +#define DISCONNECTED_SCBH 0x3f + +#define FREE_SCBH 0x40 + +#define HSCB_ADDR 0x41 + +#define SCBID_ADDR 0x45 + +#define TMODE_CMDADDR 0x49 + +#define KERNEL_QINPOS 0x4d + +#define QINPOS 0x4e + +#define QOUTPOS 0x4f + +#define TMODE_CMDADDR_NEXT 0x50 + +#define ARG_1 0x51 +#define RETURN_1 0x51 +#define SEND_MSG 0x80 +#define SEND_SENSE 0x40 +#define SEND_REJ 0x20 +#define MSGOUT_PHASEMIS 0x10 + +#define ARG_2 0x52 +#define RETURN_2 0x52 + +#define LAST_MSG 0x53 + +#define PREFETCH_CNT 0x54 + +#define SCSICONF 0x5a +#define TERM_ENB 0x80 +#define RESET_SCSI 0x40 +#define HWSCSIID 0x0f +#define HSCSIID 0x07 + +#define HOSTCONF 0x5d + +#define HA_274_BIOSCTRL 0x5f +#define BIOSMODE 0x30 +#define BIOSDISABLED 0x30 +#define CHANNEL_B_PRIMARY 0x08 + +#define SEQCTL 0x60 +#define PERRORDIS 0x80 +#define PAUSEDIS 0x40 +#define FAILDIS 0x20 +#define FASTMODE 0x10 +#define BRKADRINTEN 0x08 +#define STEP 0x04 +#define SEQRESET 0x02 +#define LOADRAM 0x01 + +#define SEQRAM 0x61 + +#define SEQADDR0 0x62 + +#define SEQADDR1 0x63 +#define SEQADDR1_MASK 0x01 + +#define ACCUM 0x64 + +#define SINDEX 0x65 + +#define DINDEX 0x66 + +#define ALLONES 0x69 + +#define ALLZEROS 0x6a + +#define NONE 0x6a + +#define FLAGS 0x6b +#define ZERO 0x02 +#define CARRY 0x01 + +#define SINDIR 0x6c + +#define DINDIR 0x6d + +#define FUNCTION1 0x6e + +#define STACK 0x6f + +#define TARG_OFFSET 0x70 + +#define BCTL 0x84 +#define ACE 0x08 +#define ENABLE 0x01 + +#define DSCOMMAND0 0x84 +#define INTSCBRAMSEL 0x08 +#define RAMPS 0x04 +#define USCBSIZE32 0x02 +#define CIOPARCKEN 0x01 + +#define DSCOMMAND 0x84 +#define CACHETHEN 0x80 +#define DPARCKEN 0x40 +#define MPARCKEN 0x20 +#define EXTREQLCK 0x10 + +#define BUSTIME 0x85 +#define BOFF 0xf0 +#define BON 0x0f + +#define BUSSPD 0x86 +#define DFTHRSH 0xc0 +#define STBOFF 0x38 +#define STBON 0x07 + +#define DSPCISTATUS 0x86 +#define DFTHRSH_100 0xc0 + +#define HCNTRL 0x87 +#define POWRDN 0x40 +#define SWINT 0x10 +#define IRQMS 0x08 +#define PAUSE 0x04 +#define INTEN 0x02 +#define CHIPRST 0x01 +#define CHIPRSTACK 0x01 + +#define HADDR 0x88 + +#define HCNT 0x8c + +#define SCBPTR 0x90 + +#define INTSTAT 0x91 +#define SEQINT_MASK 0xf1 +#define DATA_OVERRUN 0xe1 +#define MSGIN_PHASEMIS 0xd1 +#define TRACEPOINT2 0xc1 +#define TRACEPOINT 0xb1 +#define AWAITING_MSG 0xa1 +#define RESIDUAL 0x81 +#define BAD_STATUS 0x71 +#define REJECT_MSG 0x61 +#define WIDE_RESIDUE 0x51 +#define EXTENDED_MSG 0x41 +#define NO_MATCH 0x31 +#define NO_IDENT 0x21 +#define SEND_REJECT 0x11 +#define INT_PEND 0x0f +#define BRKADRINT 0x08 +#define SCSIINT 0x04 +#define CMDCMPLT 0x02 +#define BAD_PHASE 0x01 +#define SEQINT 0x01 + +#define CLRINT 0x92 +#define CLRPARERR 0x10 +#define CLRBRKADRINT 0x08 +#define CLRSCSIINT 0x04 +#define CLRCMDINT 0x02 +#define CLRSEQINT 0x01 + +#define ERROR 0x92 +#define CIOPARERR 0x80 +#define PCIERRSTAT 0x40 +#define MPARERR 0x20 +#define DPARERR 0x10 +#define SQPARERR 0x08 +#define ILLOPCODE 0x04 +#define DSCTMOUT 0x02 +#define ILLSADDR 0x02 +#define ILLHADDR 0x01 + +#define DFCNTRL 0x93 + +#define DFSTATUS 0x94 +#define PRELOAD_AVAIL 0x80 +#define DWORDEMP 0x20 +#define MREQPEND 0x10 +#define HDONE 0x08 +#define DFTHRESH 0x04 +#define FIFOFULL 0x02 +#define FIFOEMP 0x01 + +#define DFDAT 0x99 + +#define SCBCNT 0x9a +#define SCBAUTO 0x80 +#define SCBCNT_MASK 0x1f + +#define QINFIFO 0x9b + +#define QINCNT 0x9c + +#define SCSIDATL_IMG 0x9c + +#define QOUTFIFO 0x9d + +#define CRCCONTROL1 0x9d +#define CRCONSEEN 0x80 +#define CRCVALCHKEN 0x40 +#define CRCENDCHKEN 0x20 +#define CRCREQCHKEN 0x10 +#define TARGCRCENDEN 0x08 +#define TARGCRCCNTEN 0x04 + +#define QOUTCNT 0x9e + +#define SCSIPHASE 0x9e +#define SP_STATUS 0x20 +#define SP_COMMAND 0x10 +#define SP_MSG_IN 0x08 +#define SP_MSG_OUT 0x04 +#define SP_DATA_IN 0x02 +#define SP_DATA_OUT 0x01 + +#define SFUNCT 0x9f +#define ALT_MODE 0x80 + +#define SCB_CONTROL 0xa0 +#define MK_MESSAGE 0x80 +#define DISCENB 0x40 +#define TAG_ENB 0x20 +#define DISCONNECTED 0x04 +#define SCB_TAG_TYPE 0x03 + +#define SCB_BASE 0xa0 + +#define SCB_TCL 0xa1 +#define TID 0xf0 +#define SELBUSB 0x08 +#define LID 0x07 + +#define SCB_TARGET_STATUS 0xa2 + +#define SCB_SGCOUNT 0xa3 + +#define SCB_SGPTR 0xa4 + +#define SCB_RESID_SGCNT 0xa8 + +#define SCB_RESID_DCNT 0xa9 + +#define SCB_DATAPTR 0xac + +#define SCB_DATACNT 0xb0 + +#define SCB_CMDPTR 0xb4 + +#define SCB_CMDLEN 0xb8 + +#define SCB_TAG 0xb9 + +#define SCB_NEXT 0xba + +#define SCB_PREV 0xbb + +#define SCB_BUSYTARGETS 0xbc + +#define SEECTL_2840 0xc0 +#define CS_2840 0x04 +#define CK_2840 0x02 +#define DO_2840 0x01 + +#define STATUS_2840 0xc1 +#define EEPROM_TF 0x80 +#define BIOS_SEL 0x60 +#define ADSEL 0x1e +#define DI_2840 0x01 + +#define CCHADDR 0xe0 + +#define CCHCNT 0xe8 + +#define CCSGRAM 0xe9 + +#define CCSGADDR 0xea + +#define CCSGCTL 0xeb +#define CCSGDONE 0x80 +#define CCSGEN 0x08 +#define FLAG 0x02 +#define CCSGRESET 0x01 + +#define CCSCBRAM 0xec + +#define CCSCBADDR 0xed + +#define CCSCBCTL 0xee +#define CCSCBDONE 0x80 +#define ARRDONE 0x40 +#define CCARREN 0x10 +#define CCSCBEN 0x08 +#define CCSCBDIR 0x04 +#define CCSCBRESET 0x01 + +#define CCSCBCNT 0xef + +#define CCSCBPTR 0xf1 + +#define HNSCB_QOFF 0xf4 + +#define HESCB_QOFF 0xf5 + +#define SNSCB_QOFF 0xf6 + +#define SESCB_QOFF 0xf7 + +#define SDSCB_QOFF 0xf8 + +#define QOFF_CTLSTA 0xfa +#define ESTABLISH_SCB_AVAIL 0x80 +#define SCB_AVAIL 0x40 +#define SNSCB_ROLLOVER 0x20 +#define SDSCB_ROLLOVER 0x10 +#define SESCB_ROLLOVER 0x08 +#define SCB_QSIZE 0x07 +#define SCB_QSIZE_256 0x06 + +#define DFF_THRSH 0xfb +#define WR_DFTHRSH 0x70 +#define WR_DFTHRSH_MAX 0x70 +#define WR_DFTHRSH_90 0x60 +#define WR_DFTHRSH_85 0x50 +#define WR_DFTHRSH_75 0x40 +#define WR_DFTHRSH_63 0x30 +#define WR_DFTHRSH_50 0x20 +#define WR_DFTHRSH_25 0x10 +#define RD_DFTHRSH_MAX 0x07 +#define RD_DFTHRSH 0x07 +#define RD_DFTHRSH_90 0x06 +#define RD_DFTHRSH_85 0x05 +#define RD_DFTHRSH_75 0x04 +#define RD_DFTHRSH_63 0x03 +#define RD_DFTHRSH_50 0x02 +#define RD_DFTHRSH_25 0x01 +#define RD_DFTHRSH_MIN 0x00 +#define WR_DFTHRSH_MIN 0x00 + +#define SG_CACHEPTR 0xfc +#define SG_USER_DATA 0xfc +#define LAST_SEG 0x02 +#define LAST_SEG_DONE 0x01 + + +#define CMD_GROUP_CODE_SHIFT 0x05 +#define BUS_8_BIT 0x00 +#define QOUTFIFO_OFFSET 0x01 +#define CCSGRAM_MAXSEGS 0x10 +#define CMD_GROUP2_BYTE_DELTA 0xfa +#define MAX_OFFSET_8BIT 0x0f +#define BUS_16_BIT 0x01 +#define QINFIFO_OFFSET 0x02 +#define CMD_GROUP5_BYTE_DELTA 0x0b +#define MAX_OFFSET_ULTRA2 0x7f +#define MAX_OFFSET_16BIT 0x08 +#define UNTAGGEDSCB_OFFSET 0x00 +#define SCB_LIST_NULL 0xff +#define SG_SIZEOF 0x08 +#define CMD_GROUP4_BYTE_DELTA 0x04 +#define CMD_GROUP0_BYTE_DELTA 0xfc +#define HOST_MSG 0xff +#define BUS_32_BIT 0x02 +#define CCSGADDR_MAX 0x80 + + +/* Downloaded Constant Definitions */ +#define TMODE_NUMCMDS 0x00 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c --- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c Sun Mar 4 14:30:19 2001 @@ -0,0 +1,745 @@ +/* + * DO NOT EDIT - This file is automatically generated. + */ +static unsigned char seqprog[] = { + 0xff, 0x6a, 0x06, 0x08, + 0x7f, 0x02, 0x04, 0x08, + 0x12, 0x6a, 0x00, 0x00, + 0xff, 0x6a, 0xd6, 0x09, + 0xff, 0x6a, 0xdc, 0x09, + 0x00, 0x65, 0xca, 0x58, + 0xf7, 0x01, 0x02, 0x08, + 0xff, 0x4e, 0xc8, 0x08, + 0xbf, 0x60, 0xc0, 0x08, + 0x60, 0x0b, 0x86, 0x68, + 0x40, 0x00, 0x0c, 0x68, + 0x08, 0x1f, 0x3e, 0x10, + 0x60, 0x0b, 0x86, 0x68, + 0x40, 0x00, 0x0c, 0x68, + 0x08, 0x1f, 0x3e, 0x10, + 0xff, 0x3e, 0x48, 0x60, + 0x40, 0xfa, 0x10, 0x78, + 0xff, 0xf6, 0xd4, 0x08, + 0x01, 0x4e, 0x9c, 0x18, + 0x40, 0x60, 0xc0, 0x00, + 0x00, 0x4d, 0x10, 0x70, + 0x01, 0x4e, 0x9c, 0x18, + 0xbf, 0x60, 0xc0, 0x08, + 0x00, 0x6a, 0x3e, 0x5c, + 0xff, 0x4e, 0xc8, 0x18, + 0x02, 0x6a, 0x54, 0x5b, + 0xff, 0x52, 0x20, 0x09, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0x52, 0xca, 0x5b, + 0x03, 0xb0, 0x52, 0x31, + 0xff, 0xb0, 0x52, 0x09, + 0xff, 0xb1, 0x54, 0x09, + 0xff, 0xb2, 0x56, 0x09, + 0xff, 0xa3, 0x50, 0x09, + 0xff, 0x3e, 0x74, 0x09, + 0xff, 0x90, 0x7c, 0x08, + 0xff, 0x3e, 0x20, 0x09, + 0x00, 0x65, 0x4e, 0x58, + 0x00, 0x65, 0x0c, 0x40, + 0xf7, 0x1f, 0xca, 0x08, + 0x08, 0xa1, 0xc8, 0x08, + 0x00, 0x65, 0xca, 0x00, + 0xff, 0x65, 0x3e, 0x08, + 0xf0, 0xa1, 0xc8, 0x08, + 0x0f, 0x0f, 0x1e, 0x08, + 0x00, 0x0f, 0x1e, 0x00, + 0xf0, 0xa1, 0xc8, 0x08, + 0x0f, 0x05, 0x0a, 0x08, + 0x00, 0x05, 0x0a, 0x00, + 0xff, 0x6a, 0x0c, 0x08, + 0x5a, 0x6a, 0x00, 0x04, + 0x12, 0x65, 0x02, 0x00, + 0x31, 0x6a, 0xca, 0x00, + 0x80, 0x37, 0x6e, 0x68, + 0xff, 0x65, 0xca, 0x18, + 0xff, 0x37, 0xdc, 0x08, + 0xff, 0x6e, 0xc8, 0x08, + 0x00, 0x6c, 0x76, 0x78, + 0x20, 0x01, 0x02, 0x00, + 0x4c, 0x37, 0xc8, 0x28, + 0x08, 0x1f, 0x7e, 0x78, + 0x08, 0x37, 0x6e, 0x00, + 0x08, 0x64, 0xc8, 0x00, + 0x70, 0x64, 0xca, 0x18, + 0xff, 0x6c, 0x0a, 0x08, + 0x20, 0x64, 0xca, 0x18, + 0xff, 0x6c, 0x08, 0x0c, + 0x40, 0x0b, 0x96, 0x68, + 0x20, 0x6a, 0x16, 0x00, + 0xf0, 0x19, 0x6e, 0x08, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x11, 0x22, 0x00, + 0x08, 0x6a, 0x66, 0x58, + 0x08, 0x6a, 0x68, 0x00, + 0x00, 0x65, 0xaa, 0x40, + 0x12, 0x6a, 0x00, 0x00, + 0x40, 0x6a, 0x16, 0x00, + 0xff, 0x3e, 0x20, 0x09, + 0xff, 0xba, 0x7c, 0x08, + 0xff, 0xa1, 0x6e, 0x08, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x11, 0x22, 0x00, + 0x08, 0x6a, 0x66, 0x58, + 0x80, 0x6a, 0x68, 0x00, + 0x80, 0x36, 0x6c, 0x00, + 0x00, 0x65, 0x9e, 0x5b, + 0xff, 0x3d, 0xc8, 0x08, + 0xbf, 0x64, 0xe2, 0x78, + 0x80, 0x64, 0xac, 0x71, + 0xa0, 0x64, 0xdc, 0x71, + 0xc0, 0x64, 0xd4, 0x71, + 0xe0, 0x64, 0x1c, 0x72, + 0x01, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xaa, 0x40, + 0xf7, 0x11, 0x22, 0x08, + 0x00, 0x65, 0xca, 0x58, + 0xff, 0x06, 0xd4, 0x08, + 0xf7, 0x01, 0x02, 0x08, + 0x09, 0x0c, 0xc4, 0x78, + 0x08, 0x0c, 0x0c, 0x68, + 0x01, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0x26, 0x09, + 0x02, 0x6a, 0x08, 0x30, + 0xff, 0x6a, 0x08, 0x08, + 0xdf, 0x01, 0x02, 0x08, + 0x01, 0x6a, 0x7a, 0x00, + 0xff, 0x6a, 0x6c, 0x0c, + 0x04, 0x14, 0x10, 0x31, + 0x03, 0xa9, 0x18, 0x31, + 0x03, 0xa9, 0x10, 0x30, + 0x08, 0x6a, 0xcc, 0x00, + 0xa9, 0x6a, 0xb4, 0x5b, + 0x00, 0x65, 0x02, 0x41, + 0xa8, 0x6a, 0x6a, 0x00, + 0x79, 0x6a, 0x6a, 0x00, + 0x40, 0x3d, 0xea, 0x68, + 0x04, 0x35, 0x6a, 0x00, + 0x00, 0x65, 0x0e, 0x5b, + 0x80, 0x6a, 0xd4, 0x01, + 0x10, 0x36, 0xd6, 0x68, + 0x10, 0x36, 0x6c, 0x00, + 0x07, 0xac, 0x10, 0x31, + 0x03, 0x8c, 0x10, 0x30, + 0x05, 0xa3, 0x70, 0x30, + 0x88, 0x6a, 0xcc, 0x00, + 0xac, 0x6a, 0xac, 0x5b, + 0x00, 0x65, 0xa6, 0x5b, + 0x38, 0x6a, 0xcc, 0x00, + 0xa3, 0x6a, 0xb0, 0x5b, + 0xff, 0x38, 0x12, 0x69, + 0x80, 0x02, 0x04, 0x00, + 0xe7, 0x35, 0x6a, 0x08, + 0x03, 0x69, 0x18, 0x31, + 0x03, 0x69, 0x10, 0x30, + 0xff, 0x6a, 0x10, 0x00, + 0xff, 0x6a, 0x12, 0x00, + 0xff, 0x6a, 0x14, 0x00, + 0x01, 0x38, 0x18, 0x61, + 0xbf, 0x35, 0x6a, 0x08, + 0x02, 0x6a, 0xf8, 0x01, + 0xff, 0x69, 0xca, 0x08, + 0xff, 0x35, 0x26, 0x09, + 0x04, 0x0b, 0x1c, 0x69, + 0x04, 0x0b, 0x28, 0x69, + 0x10, 0x0c, 0x1e, 0x79, + 0x04, 0x0b, 0x28, 0x69, + 0xff, 0x6a, 0xca, 0x08, + 0x00, 0x35, 0xee, 0x5a, + 0x80, 0x02, 0x7c, 0x69, + 0xff, 0x65, 0x6c, 0x79, + 0xff, 0x38, 0x70, 0x18, + 0xff, 0x38, 0x6c, 0x79, + 0x80, 0xea, 0x48, 0x61, + 0xef, 0x38, 0xc8, 0x18, + 0x80, 0x6a, 0xc8, 0x00, + 0x00, 0x65, 0x3a, 0x49, + 0x33, 0x38, 0xc8, 0x28, + 0xff, 0x64, 0xd0, 0x09, + 0x04, 0x39, 0xc0, 0x31, + 0x09, 0x6a, 0xd6, 0x01, + 0x80, 0xeb, 0x40, 0x79, + 0xf7, 0xeb, 0xd6, 0x09, + 0x08, 0xeb, 0x44, 0x69, + 0x01, 0x6a, 0xd6, 0x01, + 0x08, 0xe9, 0x10, 0x31, + 0x03, 0x8c, 0x10, 0x30, + 0x88, 0x6a, 0xcc, 0x00, + 0x39, 0x6a, 0xb2, 0x5b, + 0x08, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x0d, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x30, 0x5c, + 0x88, 0x6a, 0x20, 0x5c, + 0x00, 0x65, 0xa6, 0x5b, + 0xff, 0x6a, 0xc8, 0x08, + 0x08, 0x39, 0x72, 0x18, + 0x00, 0x3a, 0x74, 0x20, + 0x01, 0x0c, 0x64, 0x79, + 0x10, 0x0c, 0x02, 0x79, + 0xff, 0x35, 0x26, 0x09, + 0x04, 0x0b, 0x6a, 0x69, + 0x00, 0x65, 0x84, 0x59, + 0x03, 0x08, 0x52, 0x31, + 0xff, 0x38, 0x50, 0x09, + 0xff, 0x08, 0x52, 0x09, + 0xff, 0x09, 0x54, 0x09, + 0xff, 0x0a, 0x56, 0x09, + 0xff, 0x38, 0x50, 0x09, + 0x00, 0x65, 0xaa, 0x40, + 0x00, 0x65, 0x84, 0x59, + 0x7f, 0x02, 0x04, 0x08, + 0xe1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xaa, 0x40, + 0x04, 0x93, 0x9a, 0x69, + 0xdf, 0x93, 0x26, 0x09, + 0x20, 0x93, 0x88, 0x69, + 0x02, 0x93, 0x26, 0x01, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x01, 0x94, 0x8a, 0x79, + 0x10, 0x94, 0x98, 0x69, + 0x7f, 0x05, 0xa0, 0x69, + 0x02, 0x03, 0xa0, 0x79, + 0x11, 0x0c, 0x9c, 0x79, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xa2, 0x69, + 0x03, 0x08, 0x52, 0x31, + 0xff, 0x38, 0x50, 0x09, + 0x12, 0x01, 0x02, 0x00, + 0xff, 0x6a, 0xd4, 0x0c, + 0x00, 0x65, 0x0e, 0x5b, + 0x05, 0xb4, 0x10, 0x31, + 0x02, 0x6a, 0x1a, 0x31, + 0x03, 0x8c, 0x10, 0x30, + 0x88, 0x6a, 0xcc, 0x00, + 0xb4, 0x6a, 0xb0, 0x5b, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x00, 0x65, 0xa6, 0x5b, + 0x3d, 0x6a, 0xee, 0x5a, + 0xac, 0x6a, 0x26, 0x01, + 0x04, 0x0b, 0xc2, 0x69, + 0x04, 0x0b, 0xc8, 0x69, + 0x10, 0x0c, 0xc4, 0x79, + 0x02, 0x03, 0xcc, 0x79, + 0x11, 0x0c, 0xc8, 0x79, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xce, 0x69, + 0x12, 0x01, 0x02, 0x00, + 0x00, 0x65, 0xaa, 0x40, + 0x00, 0x65, 0x0e, 0x5b, + 0xff, 0x06, 0x44, 0x09, + 0x00, 0x65, 0xaa, 0x40, + 0x10, 0x3d, 0x06, 0x00, + 0xff, 0x34, 0xca, 0x08, + 0x80, 0x65, 0x00, 0x62, + 0x0f, 0xa1, 0xca, 0x08, + 0x07, 0xa1, 0xca, 0x08, + 0x40, 0xa0, 0xc8, 0x08, + 0x00, 0x65, 0xca, 0x00, + 0x80, 0x65, 0xca, 0x00, + 0x80, 0xa0, 0xf0, 0x79, + 0xff, 0x65, 0x0c, 0x08, + 0x00, 0x65, 0x02, 0x42, + 0x20, 0xa0, 0x08, 0x7a, + 0xff, 0x65, 0x0c, 0x08, + 0x00, 0x65, 0x9e, 0x5b, + 0xa0, 0x3d, 0x10, 0x62, + 0x23, 0xa0, 0x0c, 0x08, + 0x00, 0x65, 0x9e, 0x5b, + 0xa0, 0x3d, 0x10, 0x62, + 0x00, 0xb9, 0x08, 0x42, + 0xff, 0x65, 0x08, 0x62, + 0xa1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x10, 0x51, 0x10, 0x72, + 0x40, 0x6a, 0x18, 0x00, + 0xff, 0x65, 0x0c, 0x08, + 0x00, 0x65, 0x9e, 0x5b, + 0xa0, 0x3d, 0xda, 0x71, + 0x40, 0x6a, 0x18, 0x00, + 0xff, 0x34, 0xa6, 0x08, + 0x80, 0x34, 0x18, 0x62, + 0x7f, 0xa0, 0x40, 0x09, + 0x08, 0x6a, 0x68, 0x00, + 0x00, 0x65, 0xaa, 0x40, + 0x64, 0x6a, 0xe4, 0x5a, + 0x80, 0x64, 0x8e, 0x6a, + 0x04, 0x64, 0x70, 0x72, + 0x02, 0x64, 0x76, 0x72, + 0x00, 0x6a, 0x38, 0x72, + 0x03, 0x64, 0x8a, 0x72, + 0x01, 0x64, 0x6c, 0x72, + 0x07, 0x64, 0xcc, 0x72, + 0x08, 0x64, 0x34, 0x72, + 0x23, 0x64, 0xd0, 0x72, + 0x11, 0x6a, 0x22, 0x01, + 0x07, 0x6a, 0xd6, 0x5a, + 0xff, 0x06, 0xd4, 0x08, + 0x00, 0x65, 0xaa, 0x40, + 0xff, 0xa8, 0x3c, 0x6a, + 0xff, 0xa2, 0x54, 0x7a, + 0x01, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0xca, 0x5b, + 0xff, 0xa2, 0x54, 0x7a, + 0x71, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x40, 0x51, 0x54, 0x62, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0xca, 0x5b, + 0xff, 0x3e, 0x74, 0x09, + 0xff, 0x90, 0x7c, 0x08, + 0x00, 0x65, 0x4e, 0x58, + 0x00, 0x65, 0xbc, 0x40, + 0x20, 0xa0, 0x5c, 0x6a, + 0xff, 0x37, 0xc8, 0x08, + 0x00, 0x6a, 0x74, 0x5b, + 0xff, 0x6a, 0x8a, 0x5b, + 0xff, 0xf8, 0xc8, 0x08, + 0xff, 0x4f, 0xc8, 0x08, + 0x01, 0x6a, 0x74, 0x5b, + 0x00, 0xb9, 0x8a, 0x5b, + 0x01, 0x4f, 0x9e, 0x18, + 0x02, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x38, 0x5c, + 0x00, 0x65, 0xbc, 0x40, + 0x41, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xaa, 0x40, + 0x04, 0xa0, 0x40, 0x01, + 0x00, 0x65, 0x50, 0x5c, + 0x00, 0x65, 0xbc, 0x40, + 0x10, 0x36, 0x34, 0x7a, + 0x05, 0x38, 0x46, 0x31, + 0x04, 0x14, 0x58, 0x31, + 0x03, 0xa9, 0x60, 0x31, + 0xa3, 0x6a, 0xcc, 0x00, + 0x38, 0x6a, 0xb0, 0x5b, + 0xac, 0x6a, 0xcc, 0x00, + 0x14, 0x6a, 0xb2, 0x5b, + 0xa9, 0x6a, 0xb4, 0x5b, + 0x00, 0x65, 0x34, 0x42, + 0xef, 0x36, 0x6c, 0x08, + 0x00, 0x65, 0x34, 0x42, + 0x0f, 0x64, 0xc8, 0x08, + 0x07, 0x64, 0xc8, 0x08, + 0x00, 0x37, 0x6e, 0x00, + 0xff, 0x6a, 0xa4, 0x00, + 0x00, 0x65, 0x44, 0x5b, + 0xff, 0x51, 0xa0, 0x72, + 0x20, 0x36, 0xaa, 0x7a, + 0x00, 0x90, 0x32, 0x5b, + 0x00, 0x65, 0xac, 0x42, + 0xff, 0x06, 0xd4, 0x08, + 0x00, 0x65, 0x9e, 0x5b, + 0xe0, 0x3d, 0xc6, 0x62, + 0x20, 0x12, 0xc6, 0x62, + 0x51, 0x6a, 0xda, 0x5a, + 0x00, 0x65, 0x2c, 0x5b, + 0xff, 0x37, 0xc8, 0x08, + 0x00, 0xa1, 0xbe, 0x62, + 0x04, 0xa0, 0xbe, 0x7a, + 0xfb, 0xa0, 0x40, 0x09, + 0x80, 0x36, 0x6c, 0x00, + 0x80, 0xa0, 0x34, 0x7a, + 0x7f, 0xa0, 0x40, 0x09, + 0xff, 0x6a, 0xd6, 0x5a, + 0x00, 0x65, 0x34, 0x42, + 0x04, 0xa0, 0xc4, 0x7a, + 0x00, 0x65, 0x50, 0x5c, + 0x00, 0x65, 0xc6, 0x42, + 0x00, 0x65, 0x38, 0x5c, + 0x31, 0x6a, 0x22, 0x01, + 0x0c, 0x6a, 0xd6, 0x5a, + 0x00, 0x65, 0x34, 0x42, + 0x61, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x34, 0x42, + 0x51, 0x6a, 0xda, 0x5a, + 0x51, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0x34, 0x42, + 0x10, 0x3d, 0x06, 0x00, + 0xff, 0x65, 0x68, 0x0c, + 0xff, 0x06, 0xd4, 0x08, + 0x01, 0x0c, 0xdc, 0x7a, + 0x04, 0x0c, 0xde, 0x6a, + 0xe0, 0x03, 0x7a, 0x08, + 0xe0, 0x3d, 0xea, 0x62, + 0xff, 0x65, 0xcc, 0x08, + 0xff, 0x12, 0xda, 0x0c, + 0xff, 0x06, 0xd4, 0x0c, + 0xd1, 0x6a, 0x22, 0x01, + 0x00, 0x65, 0xaa, 0x40, + 0xff, 0x65, 0x26, 0x09, + 0x01, 0x0b, 0xfe, 0x6a, + 0x10, 0x0c, 0xf0, 0x7a, + 0x04, 0x0b, 0xf8, 0x6a, + 0xff, 0x6a, 0xca, 0x08, + 0x04, 0x93, 0xfc, 0x6a, + 0x01, 0x94, 0xfa, 0x7a, + 0x10, 0x94, 0xfc, 0x6a, + 0x80, 0x3d, 0x02, 0x73, + 0x0f, 0x04, 0x06, 0x6b, + 0x02, 0x03, 0x06, 0x7b, + 0x11, 0x0c, 0x02, 0x7b, + 0xc7, 0x93, 0x26, 0x09, + 0xff, 0x99, 0xd4, 0x08, + 0x38, 0x93, 0x08, 0x6b, + 0xff, 0x6a, 0xd4, 0x0c, + 0x80, 0x36, 0x0c, 0x6b, + 0x21, 0x6a, 0x22, 0x05, + 0xff, 0x65, 0x20, 0x09, + 0xff, 0x51, 0x1a, 0x63, + 0xff, 0x37, 0xc8, 0x08, + 0xa1, 0x6a, 0x26, 0x43, + 0xff, 0x51, 0xc8, 0x08, + 0xb9, 0x6a, 0x26, 0x43, + 0xff, 0x90, 0xa4, 0x08, + 0xff, 0xba, 0x2a, 0x73, + 0xff, 0xba, 0x20, 0x09, + 0xff, 0x65, 0xca, 0x18, + 0x00, 0x6c, 0x1e, 0x63, + 0xff, 0x90, 0xca, 0x0c, + 0xff, 0x6a, 0xca, 0x04, + 0x20, 0x36, 0x3e, 0x7b, + 0x00, 0x90, 0x12, 0x5b, + 0xff, 0x65, 0x3e, 0x73, + 0xff, 0x52, 0x3c, 0x73, + 0xff, 0xba, 0xcc, 0x08, + 0xff, 0x52, 0x20, 0x09, + 0xff, 0x66, 0x74, 0x09, + 0xff, 0x65, 0x20, 0x0d, + 0xff, 0xba, 0x7e, 0x0c, + 0x00, 0x6a, 0x3e, 0x5c, + 0x0d, 0x6a, 0x6a, 0x00, + 0x00, 0x51, 0xca, 0x43, + 0xff, 0x3f, 0x98, 0x73, + 0xff, 0x6a, 0xa2, 0x00, + 0x00, 0x3f, 0x12, 0x5b, + 0xff, 0x65, 0x98, 0x73, + 0x20, 0x36, 0x6c, 0x00, + 0x20, 0xa0, 0x52, 0x6b, + 0xff, 0xb9, 0xa2, 0x0c, + 0xff, 0x6a, 0xa2, 0x04, + 0xff, 0x65, 0xa4, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0xbe, 0x5b, + 0x01, 0x6a, 0xd0, 0x01, + 0x09, 0x6a, 0xd6, 0x01, + 0x80, 0xeb, 0x5e, 0x7b, + 0x01, 0x6a, 0xd6, 0x01, + 0x01, 0xe9, 0xa4, 0x34, + 0x88, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0xbe, 0x5b, + 0x01, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x0d, 0x6a, 0x26, 0x01, + 0x00, 0x65, 0x30, 0x5c, + 0xff, 0x99, 0xa4, 0x0c, + 0xff, 0x65, 0xa4, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0xbe, 0x5b, + 0x01, 0x6a, 0xd0, 0x01, + 0x01, 0x6a, 0xdc, 0x05, + 0x88, 0x6a, 0xcc, 0x00, + 0x45, 0x6a, 0xbe, 0x5b, + 0x01, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0x01, 0x6a, 0x26, 0x05, + 0x01, 0x65, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0x8e, 0x7b, + 0xff, 0x6a, 0xdc, 0x0d, + 0xff, 0x65, 0x32, 0x09, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x30, 0x44, + 0xff, 0x37, 0xc8, 0x08, + 0x00, 0x6a, 0x54, 0x5b, + 0xff, 0x52, 0xa2, 0x0c, + 0x01, 0x0c, 0x9e, 0x7b, + 0x04, 0x0c, 0x9e, 0x6b, + 0xe0, 0x03, 0x06, 0x08, + 0xe0, 0x03, 0x7a, 0x0c, + 0xff, 0x8c, 0x10, 0x08, + 0xff, 0x8d, 0x12, 0x08, + 0xff, 0x8e, 0x14, 0x0c, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x08, + 0xff, 0x6c, 0xda, 0x0c, + 0x3d, 0x64, 0xa4, 0x28, + 0x55, 0x64, 0xc8, 0x28, + 0x00, 0x6c, 0xda, 0x18, + 0xff, 0x52, 0xc8, 0x08, + 0x00, 0x6c, 0xda, 0x20, + 0xff, 0x6a, 0xc8, 0x08, + 0x00, 0x6c, 0xda, 0x20, + 0x00, 0x6c, 0xda, 0x24, + 0xff, 0x65, 0xc8, 0x08, + 0xe0, 0x6a, 0xcc, 0x00, + 0x41, 0x6a, 0xba, 0x5b, + 0xff, 0x90, 0xe2, 0x09, + 0x20, 0x6a, 0xd0, 0x01, + 0x04, 0x35, 0xdc, 0x7b, + 0x1d, 0x6a, 0xdc, 0x01, + 0xdc, 0xee, 0xd8, 0x63, + 0x00, 0x65, 0xe8, 0x43, + 0x01, 0x6a, 0xdc, 0x01, + 0x20, 0xa0, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xe2, 0x7b, + 0x19, 0x6a, 0xdc, 0x01, + 0xd8, 0xee, 0xe6, 0x63, + 0xff, 0x6a, 0xdc, 0x09, + 0x18, 0xee, 0xea, 0x6b, + 0xff, 0x6a, 0xd4, 0x0c, + 0x88, 0x6a, 0xcc, 0x00, + 0x41, 0x6a, 0xba, 0x5b, + 0x20, 0x6a, 0x18, 0x01, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x09, + 0xff, 0x35, 0x26, 0x09, + 0x04, 0x35, 0x14, 0x6c, + 0xa0, 0x6a, 0xca, 0x00, + 0x20, 0x65, 0xc8, 0x18, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0xff, 0x6c, 0x32, 0x09, + 0x00, 0x65, 0x00, 0x64, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x30, 0x5c, + 0x04, 0x35, 0x0c, 0x7b, + 0xa0, 0x6a, 0x20, 0x5c, + 0x00, 0x65, 0x22, 0x5c, + 0x00, 0x65, 0x22, 0x5c, + 0x00, 0x65, 0x22, 0x44, + 0xff, 0x65, 0xcc, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x08, + 0xff, 0x99, 0xda, 0x0c, + 0x08, 0x94, 0x30, 0x7c, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x34, 0x6c, + 0xff, 0x6a, 0xd4, 0x0c, + 0xff, 0x40, 0x74, 0x09, + 0xff, 0x90, 0x80, 0x08, + 0xff, 0x6a, 0x72, 0x05, + 0xff, 0x40, 0x4c, 0x64, + 0xff, 0x3f, 0x44, 0x64, + 0xff, 0x6a, 0xca, 0x04, + 0xff, 0x3f, 0x20, 0x09, + 0x01, 0x6a, 0x6a, 0x00, + 0x00, 0xb9, 0xca, 0x5b, + 0xff, 0xba, 0x7e, 0x0c, + 0xff, 0x40, 0x20, 0x09, + 0xff, 0xba, 0x80, 0x0c, + 0xff, 0x3f, 0x74, 0x09, + 0xff, 0x90, 0x7e, 0x0c, +}; + +static int aic7xxx_patch12_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch12_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_WIDE) != 0); +} + +static int aic7xxx_patch11_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch11_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_ULTRA2) == 0); +} + +static int aic7xxx_patch10_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch10_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_CMD_CHAN) == 0); +} + +static int aic7xxx_patch9_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch9_func(struct aic7xxx_host *p) +{ + return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895); +} + +static int aic7xxx_patch8_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch8_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_ULTRA) != 0); +} + +static int aic7xxx_patch7_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch7_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_ULTRA2) != 0); +} + +static int aic7xxx_patch6_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch6_func(struct aic7xxx_host *p) +{ + return ((p->flags & AHC_PAGESCBS) == 0); +} + +static int aic7xxx_patch5_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch5_func(struct aic7xxx_host *p) +{ + return ((p->flags & AHC_PAGESCBS) != 0); +} + +static int aic7xxx_patch4_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch4_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_QUEUE_REGS) != 0); +} + +static int aic7xxx_patch3_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch3_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_TWIN) != 0); +} + +static int aic7xxx_patch2_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch2_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_QUEUE_REGS) == 0); +} + +static int aic7xxx_patch1_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch1_func(struct aic7xxx_host *p) +{ + return ((p->features & AHC_CMD_CHAN) != 0); +} + +static int aic7xxx_patch0_func(struct aic7xxx_host *p); + +static int +aic7xxx_patch0_func(struct aic7xxx_host *p) +{ + return (0); +} + +struct sequencer_patch { + int (*patch_func)(struct aic7xxx_host *); + unsigned int begin :10, + skip_instr :10, + skip_patch :12; +} sequencer_patches[] = { + { aic7xxx_patch1_func, 3, 2, 1 }, + { aic7xxx_patch2_func, 7, 1, 1 }, + { aic7xxx_patch2_func, 8, 1, 1 }, + { aic7xxx_patch3_func, 11, 4, 1 }, + { aic7xxx_patch4_func, 16, 3, 2 }, + { aic7xxx_patch0_func, 19, 4, 1 }, + { aic7xxx_patch5_func, 23, 1, 1 }, + { aic7xxx_patch6_func, 26, 1, 1 }, + { aic7xxx_patch1_func, 29, 1, 2 }, + { aic7xxx_patch0_func, 30, 3, 1 }, + { aic7xxx_patch3_func, 39, 4, 1 }, + { aic7xxx_patch7_func, 43, 3, 2 }, + { aic7xxx_patch0_func, 46, 3, 1 }, + { aic7xxx_patch8_func, 52, 7, 1 }, + { aic7xxx_patch3_func, 60, 3, 1 }, + { aic7xxx_patch7_func, 63, 2, 1 }, + { aic7xxx_patch7_func, 102, 1, 2 }, + { aic7xxx_patch0_func, 103, 2, 1 }, + { aic7xxx_patch7_func, 107, 2, 1 }, + { aic7xxx_patch9_func, 109, 1, 1 }, + { aic7xxx_patch10_func, 110, 2, 1 }, + { aic7xxx_patch7_func, 113, 1, 2 }, + { aic7xxx_patch0_func, 114, 1, 1 }, + { aic7xxx_patch1_func, 118, 1, 1 }, + { aic7xxx_patch1_func, 121, 3, 2 }, + { aic7xxx_patch0_func, 124, 5, 1 }, + { aic7xxx_patch1_func, 132, 2, 3 }, + { aic7xxx_patch7_func, 132, 1, 1 }, + { aic7xxx_patch0_func, 134, 3, 1 }, + { aic7xxx_patch11_func, 138, 1, 2 }, + { aic7xxx_patch0_func, 139, 1, 1 }, + { aic7xxx_patch7_func, 140, 7, 2 }, + { aic7xxx_patch0_func, 147, 1, 1 }, + { aic7xxx_patch1_func, 152, 14, 3 }, + { aic7xxx_patch11_func, 165, 1, 1 }, + { aic7xxx_patch0_func, 166, 9, 1 }, + { aic7xxx_patch7_func, 180, 2, 1 }, + { aic7xxx_patch7_func, 182, 1, 1 }, + { aic7xxx_patch11_func, 183, 6, 3 }, + { aic7xxx_patch1_func, 183, 2, 2 }, + { aic7xxx_patch0_func, 185, 4, 1 }, + { aic7xxx_patch7_func, 190, 1, 1 }, + { aic7xxx_patch7_func, 194, 20, 1 }, + { aic7xxx_patch1_func, 215, 3, 3 }, + { aic7xxx_patch11_func, 217, 1, 1 }, + { aic7xxx_patch0_func, 218, 5, 1 }, + { aic7xxx_patch11_func, 223, 1, 2 }, + { aic7xxx_patch0_func, 224, 9, 1 }, + { aic7xxx_patch12_func, 240, 1, 2 }, + { aic7xxx_patch0_func, 241, 1, 1 }, + { aic7xxx_patch4_func, 302, 1, 2 }, + { aic7xxx_patch0_func, 303, 1, 1 }, + { aic7xxx_patch2_func, 306, 1, 1 }, + { aic7xxx_patch1_func, 316, 3, 2 }, + { aic7xxx_patch0_func, 319, 5, 1 }, + { aic7xxx_patch12_func, 327, 1, 2 }, + { aic7xxx_patch0_func, 328, 1, 1 }, + { aic7xxx_patch5_func, 333, 1, 1 }, + { aic7xxx_patch11_func, 375, 15, 1 }, + { aic7xxx_patch1_func, 427, 7, 2 }, + { aic7xxx_patch0_func, 434, 8, 1 }, + { aic7xxx_patch1_func, 443, 4, 2 }, + { aic7xxx_patch0_func, 447, 6, 1 }, + { aic7xxx_patch1_func, 453, 4, 2 }, + { aic7xxx_patch0_func, 457, 3, 1 }, + { aic7xxx_patch10_func, 467, 10, 1 }, + { aic7xxx_patch1_func, 486, 17, 4 }, + { aic7xxx_patch9_func, 494, 4, 2 }, + { aic7xxx_patch0_func, 498, 2, 1 }, + { aic7xxx_patch0_func, 503, 33, 1 }, + { aic7xxx_patch10_func, 536, 4, 1 }, + { aic7xxx_patch5_func, 540, 2, 1 }, + { aic7xxx_patch5_func, 543, 9, 1 }, + +}; diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/scsi_message.h linux/drivers/scsi/aic7xxx_old/scsi_message.h --- v2.4.2/linux/drivers/scsi/aic7xxx_old/scsi_message.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/scsi_message.h Sun Mar 4 14:30:19 2001 @@ -0,0 +1,49 @@ +/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */ +#define MSG_CMDCOMPLETE 0x00 /* M/M */ +#define MSG_EXTENDED 0x01 /* O/O */ +#define MSG_SAVEDATAPOINTER 0x02 /* O/O */ +#define MSG_RESTOREPOINTERS 0x03 /* O/O */ +#define MSG_DISCONNECT 0x04 /* O/O */ +#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */ +#define MSG_ABORT 0x06 /* O/M */ +#define MSG_MESSAGE_REJECT 0x07 /* M/M */ +#define MSG_NOOP 0x08 /* M/M */ +#define MSG_PARITY_ERROR 0x09 /* M/M */ +#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */ +#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */ +#define MSG_BUS_DEV_RESET 0x0c /* O/M */ +#define MSG_ABORT_TAG 0x0d /* O/O */ +#define MSG_CLEAR_QUEUE 0x0e /* O/O */ +#define MSG_INIT_RECOVERY 0x0f /* O/O */ +#define MSG_REL_RECOVERY 0x10 /* O/O */ +#define MSG_TERM_IO_PROC 0x11 /* O/O */ + +/* Messages (2 byte) */ +#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ +#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */ +#define MSG_ORDERED_Q_TAG 0x22 /* O/O */ +#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */ + +/* Identify message */ /* M/M */ +#define MSG_IDENTIFYFLAG 0x80 +#define MSG_IDENTIFY_DISCFLAG 0x40 +#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun)) +#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG) + +/* Extended messages (opcode and length) */ +#define MSG_EXT_SDTR 0x01 +#define MSG_EXT_SDTR_LEN 0x03 + +#define MSG_EXT_WDTR 0x03 +#define MSG_EXT_WDTR_LEN 0x02 +#define MSG_EXT_WDTR_BUS_8_BIT 0x00 +#define MSG_EXT_WDTR_BUS_16_BIT 0x01 +#define MSG_EXT_WDTR_BUS_32_BIT 0x02 + +#define MSG_EXT_PPR 0x04 +#define MSG_EXT_PPR_LEN 0x06 +#define MSG_EXT_PPR_OPTION_ST 0x00 +#define MSG_EXT_PPR_OPTION_DT_CRC 0x02 +#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03 +#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04 +#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/sequencer.h linux/drivers/scsi/aic7xxx_old/sequencer.h --- v2.4.2/linux/drivers/scsi/aic7xxx_old/sequencer.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old/sequencer.h Sun Mar 4 14:30:19 2001 @@ -0,0 +1,135 @@ +/* + * Instruction formats for the sequencer program downloaded to + * Aic7xxx SCSI host adapters + * + * Copyright (c) 1997, 1998 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $ + */ + +#ifdef __LITTLE_ENDIAN_BITFIELD +struct ins_format1 { + unsigned int + immediate : 8, + source : 9, + destination : 9, + ret : 1, + opcode : 4, + parity : 1; +}; + +struct ins_format2 { + unsigned int + shift_control : 8, + source : 9, + destination : 9, + ret : 1, + opcode : 4, + parity : 1; +}; + +struct ins_format3 { + unsigned int + immediate : 8, + source : 9, + address : 10, + opcode : 4, + parity : 1; +}; +#elif defined(__BIG_ENDIAN_BITFIELD) +struct ins_format1 { + unsigned int + parity : 1, + opcode : 4, + ret : 1, + destination : 9, + source : 9, + immediate : 8; +}; + +struct ins_format2 { + unsigned int + parity : 1, + opcode : 4, + ret : 1, + destination : 9, + source : 9, + shift_control : 8; +}; + +struct ins_format3 { + unsigned int + parity : 1, + opcode : 4, + address : 10, + source : 9, + immediate : 8; +}; +#endif + +union ins_formats { + struct ins_format1 format1; + struct ins_format2 format2; + struct ins_format3 format3; + unsigned char bytes[4]; + unsigned int integer; +}; +struct instruction { + union ins_formats format; + unsigned int srcline; + struct symbol *patch_label; + struct { + struct instruction *stqe_next; + } links; +}; + +#define AIC_OP_OR 0x0 +#define AIC_OP_AND 0x1 +#define AIC_OP_XOR 0x2 +#define AIC_OP_ADD 0x3 +#define AIC_OP_ADC 0x4 +#define AIC_OP_ROL 0x5 +#define AIC_OP_BMOV 0x6 + +#define AIC_OP_JMP 0x8 +#define AIC_OP_JC 0x9 +#define AIC_OP_JNC 0xa +#define AIC_OP_CALL 0xb +#define AIC_OP_JNE 0xc +#define AIC_OP_JNZ 0xd +#define AIC_OP_JE 0xe +#define AIC_OP_JZ 0xf + +/* Pseudo Ops */ +#define AIC_OP_SHL 0x10 +#define AIC_OP_SHR 0x20 +#define AIC_OP_ROR 0x30 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c --- v2.4.2/linux/drivers/scsi/aic7xxx_old.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/aic7xxx_old.c Sun Mar 4 14:30:19 2001 @@ -0,0 +1,12242 @@ +/*+M************************************************************************* + * Adaptec AIC7xxx device driver for Linux. + * + * Copyright (c) 1994 John Aycock + * The University of Calgary Department of Computer Science. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F + * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA + * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide, + * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux, + * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file + * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual, + * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the + * ANSI SCSI-2 specification (draft 10c), ... + * + * -------------------------------------------------------------------------- + * + * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org): + * + * Substantially modified to include support for wide and twin bus + * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, + * SCB paging, and other rework of the code. + * + * Parts of this driver were also based on the FreeBSD driver by + * Justin T. Gibbs. His copyright follows: + * + * -------------------------------------------------------------------------- + * Copyright (c) 1994-1997 Justin Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $ + *--------------------------------------------------------------------------- + * + * Thanks also go to (in alphabetical order) the following: + * + * Rory Bolt - Sequencer bug fixes + * Jay Estabrook - Initial DEC Alpha support + * Doug Ledford - Much needed abort/reset bug fixes + * Kai Makisara - DMAing of SCBs + * + * A Boot time option was also added for not resetting the scsi bus. + * + * Form: aic7xxx=extended + * aic7xxx=no_reset + * aic7xxx=ultra + * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level + * aic7xxx=verbose + * + * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97 + * + * $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $ + *-M*************************************************************************/ + +/*+M************************************************************************** + * + * Further driver modifications made by Doug Ledford + * + * Copyright (c) 1997-1999 Doug Ledford + * + * These changes are released under the same licensing terms as the FreeBSD + * driver written by Justin Gibbs. Please see his Copyright notice above + * for the exact terms and conditions covering my changes as well as the + * warranty statement. + * + * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include + * but are not limited to: + * + * 1: Import of the latest FreeBSD sequencer code for this driver + * 2: Modification of kernel code to accomodate different sequencer semantics + * 3: Extensive changes throughout kernel portion of driver to improve + * abort/reset processing and error hanndling + * 4: Other work contributed by various people on the Internet + * 5: Changes to printk information and verbosity selection code + * 6: General reliability related changes, especially in IRQ management + * 7: Modifications to the default probe/attach order for supported cards + * 8: SMP friendliness has been improved + * + * Overall, this driver represents a significant departure from the official + * aic7xxx driver released by Dan Eischen in two ways. First, in the code + * itself. A diff between the two version of the driver is now a several + * thousand line diff. Second, in approach to solving the same problem. The + * problem is importing the FreeBSD aic7xxx driver code to linux can be a + * difficult and time consuming process, that also can be error prone. Dan + * Eischen's official driver uses the approach that the linux and FreeBSD + * drivers should be as identical as possible. To that end, his next version + * of this driver will be using a mid-layer code library that he is developing + * to moderate communications between the linux mid-level SCSI code and the + * low level FreeBSD driver. He intends to be able to essentially drop the + * FreeBSD driver into the linux kernel with only a few minor tweaks to some + * include files and the like and get things working, making for fast easy + * imports of the FreeBSD code into linux. + * + * I disagree with Dan's approach. Not that I don't think his way of doing + * things would be nice, easy to maintain, and create a more uniform driver + * between FreeBSD and Linux. I have no objection to those issues. My + * disagreement is on the needed functionality. There simply are certain + * things that are done differently in FreeBSD than linux that will cause + * problems for this driver regardless of any middle ware Dan implements. + * The biggest example of this at the moment is interrupt semantics. Linux + * doesn't provide the same protection techniques as FreeBSD does, nor can + * they be easily implemented in any middle ware code since they would truly + * belong in the kernel proper and would effect all drivers. For the time + * being, I see issues such as these as major stumbling blocks to the + * reliability of code based upon such middle ware. Therefore, I choose to + * use a different approach to importing the FreeBSD code that doesn't + * involve any middle ware type code. My approach is to import the sequencer + * code from FreeBSD wholesale. Then, to only make changes in the kernel + * portion of the driver as they are needed for the new sequencer semantics. + * In this way, the portion of the driver that speaks to the rest of the + * linux kernel is fairly static and can be changed/modified to solve + * any problems one might encounter without concern for the FreeBSD driver. + * + * Note: If time and experience should prove me wrong that the middle ware + * code Dan writes is reliable in its operation, then I'll retract my above + * statements. But, for those that don't know, I'm from Missouri (in the US) + * and our state motto is "The Show-Me State". Well, before I will put + * faith into it, you'll have to show me that it works :) + * + *_M*************************************************************************/ + +/* + * The next three defines are user configurable. These should be the only + * defines a user might need to get in here and change. There are other + * defines buried deeper in the code, but those really shouldn't need touched + * under normal conditions. + */ + +/* + * AIC7XXX_STRICT_PCI_SETUP + * Should we assume the PCI config options on our controllers are set with + * sane and proper values, or should we be anal about our PCI config + * registers and force them to what we want? The main advantage to + * defining this option is on non-Intel hardware where the BIOS may not + * have been run to set things up, or if you have one of the BIOSless + * Adaptec controllers, such as a 2910, that don't get set up by the + * BIOS. However, keep in mind that we really do set the most important + * items in the driver regardless of this setting, this only controls some + * of the more esoteric PCI options on these cards. In that sense, I + * would default to leaving this off. However, if people wish to try + * things both ways, that would also help me to know if there are some + * machines where it works one way but not another. + * + * -- July 7, 17:09 + * OK...I need this on my machine for testing, so the default is to + * leave it defined. + * + * -- July 7, 18:49 + * I needed it for testing, but it didn't make any difference, so back + * off she goes. + * + * -- July 16, 23:04 + * I turned it back on to try and compensate for the 2.1.x PCI code + * which no longer relies solely on the BIOS and now tries to set + * things itself. + */ + +#define AIC7XXX_STRICT_PCI_SETUP + +/* + * AIC7XXX_VERBOSE_DEBUGGING + * This option enables a lot of extra printk();s in the code, surrounded + * by if (aic7xxx_verbose ...) statements. Executing all of those if + * statements and the extra checks can get to where it actually does have + * an impact on CPU usage and such, as well as code size. Disabling this + * define will keep some of those from becoming part of the code. + * + * NOTE: Currently, this option has no real effect, I will be adding the + * various #ifdef's in the code later when I've decided a section is + * complete and no longer needs debugging. OK...a lot of things are now + * surrounded by this define, so turning this off does have an impact. + */ + +/* + * #define AIC7XXX_VERBOSE_DEBUGGING + */ + +#if defined(MODULE) || defined(PCMCIA) +#include +#endif + +#if defined(PCMCIA) +# undef MODULE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sd.h" +#include "scsi.h" +#include "hosts.h" +#include "aic7xxx_old/aic7xxx.h" + +#include "aic7xxx_old/sequencer.h" +#include "aic7xxx_old/scsi_message.h" +#include "aic7xxx_old/aic7xxx_reg.h" +#include + +#include +#include /* for kmalloc() */ + +#include /* for CONFIG_PCI */ + +/* + * To generate the correct addresses for the controller to issue + * on the bus. Originally added for DEC Alpha support. + */ +#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a)) + +#define AIC7XXX_C_VERSION "5.2.1" + +#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define ALL_TARGETS -1 +#define ALL_CHANNELS -1 +#define ALL_LUNS -1 +#define MAX_TARGETS 16 +#define MAX_LUNS 8 +#ifndef TRUE +# define TRUE 1 +#endif +#ifndef FALSE +# define FALSE 0 +#endif + +#if defined(__powerpc__) || defined(__i386__) +# define MMAPIO +#endif + +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) +# define cpuid smp_processor_id() +# define DRIVER_LOCK_INIT \ + spin_lock_init(&p->spin_lock); +# define DRIVER_LOCK \ + if(!p->cpu_lock_count[cpuid]) { \ + spin_lock_irqsave(&p->spin_lock, cpu_flags); \ + p->cpu_lock_count[cpuid]++; \ + } else { \ + p->cpu_lock_count[cpuid]++; \ + } +# define DRIVER_UNLOCK \ + if(--p->cpu_lock_count[cpuid] == 0) \ + spin_unlock_irqrestore(&p->spin_lock, cpu_flags); +# else +# define DRIVER_LOCK_INIT +# define DRIVER_LOCK +# define DRIVER_UNLOCK +# endif + +/* + * You can try raising me if tagged queueing is enabled, or lowering + * me if you only have 4 SCBs. + */ +#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE +#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE +#else +#define AIC7XXX_CMDS_PER_DEVICE 8 +#endif + +/* + * Control collection of SCSI transfer statistics for the /proc filesystem. + * + * NOTE: Do NOT enable this when running on kernels version 1.2.x and below. + * NOTE: This does affect performance since it has to maintain statistics. + */ +#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS +#define AIC7XXX_PROC_STATS +#endif + +/* + * *** Determining commands per LUN *** + * + * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its + * own algorithm to determine the commands/LUN. If SCB paging is + * enabled, which is always now, the default is 8 commands per lun + * that indicates it supports tagged queueing. All non-tagged devices + * use an internal queue depth of 3, with no more than one of those + * three commands active at one time. + */ + +typedef struct +{ + unsigned char tag_commands[16]; /* Allow for wide/twin adapters. */ +} adapter_tag_info_t; + +/* + * Make a define that will tell the driver not to use tagged queueing + * by default. + */ +#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT +#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ + 0, 0, 0, 0, 0, 0, 0, 0} +#else +#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\ + 255, 255, 255, 255, 255, 255, 255, 255} +#endif + +/* + * Modify this as you see fit for your system. By setting tag_commands + * to 0, the driver will use it's own algorithm for determining the + * number of commands to use (see above). When 255, the driver will + * not enable tagged queueing for that particular device. When positive + * (> 0) and (< 255) the values in the array are used for the queue_depth. + * Note that the maximum value for an entry is 254, but you're insane if + * you try to use that many commands on one device. + * + * In this example, the first line will disable tagged queueing for all + * the devices on the first probed aic7xxx adapter. + * + * The second line enables tagged queueing with 4 commands/LUN for IDs + * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the + * driver to use its own algorithm for ID 1. + * + * The third line is the same as the first line. + * + * The fourth line disables tagged queueing for devices 0 and 3. It + * enables tagged queueing for the other IDs, with 16 commands/LUN + * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for + * IDs 2, 5-7, and 9-15. + */ + +/* + * NOTE: The below structure is for reference only, the actual structure + * to modify in order to change things is found after this fake one. + * +adapter_tag_info_t aic7xxx_tag_info[] = +{ + {DEFAULT_TAG_COMMANDS}, + {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}}, + {DEFAULT_TAG_COMMANDS}, + {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} +}; +*/ + +static adapter_tag_info_t aic7xxx_tag_info[] = +{ + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS}, + {DEFAULT_TAG_COMMANDS} +}; + + +/* + * Define an array of board names that can be indexed by aha_type. + * Don't forget to change this when changing the types! + */ +static const char *board_names[] = { + "AIC-7xxx Unknown", /* AIC_NONE */ + "Adaptec AIC-7810 Hardware RAID Controller", /* AIC_7810 */ + "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */ + "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */ + "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */ + "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */ + "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */ + "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */ + "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */ + "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */ + "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */ + "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */ + "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */ + "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */ + "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */ + "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */ + "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */ + "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */ + "Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */ + "Adaptec AHA-2940UW Pro Ultra SCSI host adapter", /* AIC_7887 */ + "Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */ + "Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */ + "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */ + "Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */ + "Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */ + "Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */ + "Adaptec AHA-395X Ultra2 SCSI host adapter", /* AIC_7897 */ + "Adaptec PCMCIA SCSI controller", /* card bus stuff */ + "Adaptec AIC-7892 Ultra 160/m SCSI host adapter", /* AIC_7892 */ + "Adaptec AIC-7899 Ultra 160/m SCSI host adapter", /* AIC_7899 */ +}; + +/* + * There should be a specific return value for this in scsi.h, but + * it seems that most drivers ignore it. + */ +#define DID_UNDERFLOW DID_ERROR + +/* + * What we want to do is have the higher level scsi driver requeue + * the command to us. There is no specific driver status for this + * condition, but the higher level scsi driver will requeue the + * command on a DID_BUS_BUSY error. + * + * Upon further inspection and testing, it seems that DID_BUS_BUSY + * will *always* retry the command. We can get into an infinite loop + * if this happens when we really want some sort of counter that + * will automatically abort/reset the command after so many retries. + * Using DID_ERROR will do just that. (Made by a suggestion by + * Doug Ledford 8/1/96) + */ +#define DID_RETRY_COMMAND DID_ERROR + +#define HSCSIID 0x07 +#define SCSI_RESET 0x040 + +/* + * EISA/VL-bus stuff + */ +#define MINSLOT 1 +#define MAXSLOT 15 +#define SLOTBASE(x) ((x) << 12) +#define BASE_TO_SLOT(x) ((x) >> 12) + +/* + * Standard EISA Host ID regs (Offset from slot base) + */ +#define AHC_HID0 0x80 /* 0,1: msb of ID2, 2-7: ID1 */ +#define AHC_HID1 0x81 /* 0-4: ID3, 5-7: LSB ID2 */ +#define AHC_HID2 0x82 /* product */ +#define AHC_HID3 0x83 /* firmware revision */ + +/* + * AIC-7770 I/O range to reserve for a card + */ +#define MINREG 0xC00 +#define MAXREG 0xCFF + +#define INTDEF 0x5C /* Interrupt Definition Register */ + +/* + * AIC-78X0 PCI registers + */ +#define CLASS_PROGIF_REVID 0x08 +#define DEVREVID 0x000000FFul +#define PROGINFC 0x0000FF00ul +#define SUBCLASS 0x00FF0000ul +#define BASECLASS 0xFF000000ul + +#define CSIZE_LATTIME 0x0C +#define CACHESIZE 0x0000003Ful /* only 5 bits */ +#define LATTIME 0x0000FF00ul + +#define DEVCONFIG 0x40 +#define SCBSIZE32 0x00010000ul /* aic789X only */ +#define MPORTMODE 0x00000400ul /* aic7870 only */ +#define RAMPSM 0x00000200ul /* aic7870 only */ +#define RAMPSM_ULTRA2 0x00000004 +#define VOLSENSE 0x00000100ul +#define SCBRAMSEL 0x00000080ul +#define SCBRAMSEL_ULTRA2 0x00000008 +#define MRDCEN 0x00000040ul +#define EXTSCBTIME 0x00000020ul /* aic7870 only */ +#define EXTSCBPEN 0x00000010ul /* aic7870 only */ +#define BERREN 0x00000008ul +#define DACEN 0x00000004ul +#define STPWLEVEL 0x00000002ul +#define DIFACTNEGEN 0x00000001ul /* aic7870 only */ + +#define SCAMCTL 0x1a /* Ultra2 only */ +#define CCSCBBADDR 0xf0 /* aic7895/6/7 */ + +/* + * Define the different types of SEEPROMs on aic7xxx adapters + * and make it also represent the address size used in accessing + * its registers. The 93C46 chips have 1024 bits organized into + * 64 16-bit words, while the 93C56 chips have 2048 bits organized + * into 128 16-bit words. The C46 chips use 6 bits to address + * each word, while the C56 and C66 (4096 bits) use 8 bits to + * address each word. + */ +typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type; + +/* + * + * Define the format of the SEEPROM registers (16 bits). + * + */ +struct seeprom_config { + +/* + * SCSI ID Configuration Flags + */ +#define CFXFER 0x0007 /* synchronous transfer rate */ +#define CFSYNCH 0x0008 /* enable synchronous transfer */ +#define CFDISC 0x0010 /* enable disconnection */ +#define CFWIDEB 0x0020 /* wide bus device (wide card) */ +#define CFSYNCHISULTRA 0x0040 /* CFSYNC is an ultra offset */ +#define CFNEWULTRAFORMAT 0x0080 /* Use the Ultra2 SEEPROM format */ +#define CFSTART 0x0100 /* send start unit SCSI command */ +#define CFINCBIOS 0x0200 /* include in BIOS scan */ +#define CFRNFOUND 0x0400 /* report even if not found */ +#define CFMULTILUN 0x0800 /* probe mult luns in BIOS scan */ +#define CFWBCACHEYES 0x4000 /* Enable W-Behind Cache on drive */ +#define CFWBCACHENC 0xc000 /* Don't change W-Behind Cache */ +/* UNUSED 0x3000 */ + unsigned short device_flags[16]; /* words 0-15 */ + +/* + * BIOS Control Bits + */ +#define CFSUPREM 0x0001 /* support all removable drives */ +#define CFSUPREMB 0x0002 /* support removable drives for boot only */ +#define CFBIOSEN 0x0004 /* BIOS enabled */ +/* UNUSED 0x0008 */ +#define CFSM2DRV 0x0010 /* support more than two drives */ +#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ +/* UNUSED 0x0040 */ +#define CFEXTEND 0x0080 /* extended translation enabled */ +/* UNUSED 0xFF00 */ + unsigned short bios_control; /* word 16 */ + +/* + * Host Adapter Control Bits + */ +#define CFAUTOTERM 0x0001 /* Perform Auto termination */ +#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */ +#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */ +#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */ +#define CFSTERM 0x0004 /* SCSI low byte termination */ +#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */ +#define CFSPARITY 0x0010 /* SCSI parity */ +#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */ +#define CFRESETB 0x0040 /* reset SCSI bus at boot */ +#define CFBPRIMARY 0x0100 /* Channel B primary on 7895 chipsets */ +#define CFSEAUTOTERM 0x0400 /* aic7890 Perform SE Auto Term */ +#define CFLVDSTERM 0x0800 /* aic7890 LVD Termination */ +/* UNUSED 0xF280 */ + unsigned short adapter_control; /* word 17 */ + +/* + * Bus Release, Host Adapter ID + */ +#define CFSCSIID 0x000F /* host adapter SCSI ID */ +/* UNUSED 0x00F0 */ +#define CFBRTIME 0xFF00 /* bus release time */ + unsigned short brtime_id; /* word 18 */ + +/* + * Maximum targets + */ +#define CFMAXTARG 0x00FF /* maximum targets */ +/* UNUSED 0xFF00 */ + unsigned short max_targets; /* word 19 */ + + unsigned short res_1[11]; /* words 20-30 */ + unsigned short checksum; /* word 31 */ +}; + +#define SELBUS_MASK 0x0a +#define SELNARROW 0x00 +#define SELBUSB 0x08 +#define SINGLE_BUS 0x00 + +#define SCB_TARGET(scb) \ + (((scb)->hscb->target_channel_lun & TID) >> 4) +#define SCB_LUN(scb) \ + ((scb)->hscb->target_channel_lun & LID) +#define SCB_IS_SCSIBUS_B(scb) \ + (((scb)->hscb->target_channel_lun & SELBUSB) != 0) + +/* + * If an error occurs during a data transfer phase, run the command + * to completion - it's easier that way - making a note of the error + * condition in this location. This then will modify a DID_OK status + * into an appropriate error for the higher-level SCSI code. + */ +#define aic7xxx_error(cmd) ((cmd)->SCp.Status) + +/* + * Keep track of the targets returned status. + */ +#define aic7xxx_status(cmd) ((cmd)->SCp.sent_command) + +/* + * The position of the SCSI commands scb within the scb array. + */ +#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in) + +/* + * The stored DMA mapping for single-buffer data transfers. + */ +#define aic7xxx_mapping(cmd) ((cmd)->SCp.phase) + +/* + * So we can keep track of our host structs + */ +static struct aic7xxx_host *first_aic7xxx = NULL; + +/* + * As of Linux 2.1, the mid-level SCSI code uses virtual addresses + * in the scatter-gather lists. We need to convert the virtual + * addresses to physical addresses. + */ +struct hw_scatterlist { + unsigned int address; + unsigned int length; +}; + +/* + * Maximum number of SG segments these cards can support. + */ +#define AIC7XXX_MAX_SG 128 + +/* + * The maximum number of SCBs we could have for ANY type + * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE + * SEQUENCER CODE IF THIS IS MODIFIED! + */ +#define AIC7XXX_MAXSCB 255 + + +struct aic7xxx_hwscb { +/* ------------ Begin hardware supported fields ---------------- */ +/* 0*/ unsigned char control; +/* 1*/ unsigned char target_channel_lun; /* 4/1/3 bits */ +/* 2*/ unsigned char target_status; +/* 3*/ unsigned char SG_segment_count; +/* 4*/ unsigned int SG_list_pointer; +/* 8*/ unsigned char residual_SG_segment_count; +/* 9*/ unsigned char residual_data_count[3]; +/*12*/ unsigned int data_pointer; +/*16*/ unsigned int data_count; +/*20*/ unsigned int SCSI_cmd_pointer; +/*24*/ unsigned char SCSI_cmd_length; +/*25*/ unsigned char tag; /* Index into our kernel SCB array. + * Also used as the tag for tagged I/O + */ +#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download + * via PIO to initialize a transaction. + */ +/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection + * or disconnected down in the sequencer. + */ +/*27*/ unsigned char prev; +/*28*/ unsigned int pad; /* + * Unused by the kernel, but we require + * the padding so that the array of + * hardware SCBs is alligned on 32 byte + * boundaries so the sequencer can index + */ +}; + +typedef enum { + SCB_FREE = 0x0000, + SCB_WAITINGQ = 0x0002, + SCB_ACTIVE = 0x0004, + SCB_SENSE = 0x0008, + SCB_ABORT = 0x0010, + SCB_DEVICE_RESET = 0x0020, + SCB_RESET = 0x0040, + SCB_RECOVERY_SCB = 0x0080, + SCB_MSGOUT_PPR = 0x0100, + SCB_MSGOUT_SENT = 0x0200, + SCB_MSGOUT_SDTR = 0x0400, + SCB_MSGOUT_WDTR = 0x0800, + SCB_MSGOUT_BITS = SCB_MSGOUT_PPR | + SCB_MSGOUT_SENT | + SCB_MSGOUT_SDTR | + SCB_MSGOUT_WDTR, + SCB_QUEUED_ABORT = 0x1000, + SCB_QUEUED_FOR_DONE = 0x2000, + SCB_WAS_BUSY = 0x4000 +} scb_flag_type; + +typedef enum { + AHC_FNONE = 0x00000000, + AHC_PAGESCBS = 0x00000001, + AHC_CHANNEL_B_PRIMARY = 0x00000002, + AHC_USEDEFAULTS = 0x00000004, + AHC_INDIRECT_PAGING = 0x00000008, + AHC_CHNLB = 0x00000020, + AHC_CHNLC = 0x00000040, + AHC_EXTEND_TRANS_A = 0x00000100, + AHC_EXTEND_TRANS_B = 0x00000200, + AHC_TERM_ENB_A = 0x00000400, + AHC_TERM_ENB_SE_LOW = 0x00000400, + AHC_TERM_ENB_B = 0x00000800, + AHC_TERM_ENB_SE_HIGH = 0x00000800, + AHC_HANDLING_REQINITS = 0x00001000, + AHC_TARGETMODE = 0x00002000, + AHC_NEWEEPROM_FMT = 0x00004000, + /* + * Here ends the FreeBSD defined flags and here begins the linux defined + * flags. NOTE: I did not preserve the old flag name during this change + * specifically to force me to evaluate what flags were being used properly + * and what flags weren't. This way, I could clean up the flag usage on + * a use by use basis. Doug Ledford + */ + AHC_MOTHERBOARD = 0x00020000, + AHC_NO_STPWEN = 0x00040000, + AHC_RESET_DELAY = 0x00080000, + AHC_A_SCANNED = 0x00100000, + AHC_B_SCANNED = 0x00200000, + AHC_MULTI_CHANNEL = 0x00400000, + AHC_BIOS_ENABLED = 0x00800000, + AHC_SEEPROM_FOUND = 0x01000000, + AHC_TERM_ENB_LVD = 0x02000000, + AHC_ABORT_PENDING = 0x04000000, + AHC_RESET_PENDING = 0x08000000, +#define AHC_IN_ISR_BIT 28 + AHC_IN_ISR = 0x10000000, + AHC_IN_ABORT = 0x20000000, + AHC_IN_RESET = 0x40000000, + AHC_EXTERNAL_SRAM = 0x80000000 +} ahc_flag_type; + +typedef enum { + AHC_NONE = 0x0000, + AHC_CHIPID_MASK = 0x00ff, + AHC_AIC7770 = 0x0001, + AHC_AIC7850 = 0x0002, + AHC_AIC7860 = 0x0003, + AHC_AIC7870 = 0x0004, + AHC_AIC7880 = 0x0005, + AHC_AIC7890 = 0x0006, + AHC_AIC7895 = 0x0007, + AHC_AIC7896 = 0x0008, + AHC_AIC7892 = 0x0009, + AHC_AIC7899 = 0x000a, + AHC_VL = 0x0100, + AHC_EISA = 0x0200, + AHC_PCI = 0x0400, +} ahc_chip; + +typedef enum { + AHC_FENONE = 0x0000, + AHC_ULTRA = 0x0001, + AHC_ULTRA2 = 0x0002, + AHC_WIDE = 0x0004, + AHC_TWIN = 0x0008, + AHC_MORE_SRAM = 0x0010, + AHC_CMD_CHAN = 0x0020, + AHC_QUEUE_REGS = 0x0040, + AHC_SG_PRELOAD = 0x0080, + AHC_SPIOCAP = 0x0100, + AHC_ULTRA3 = 0x0200, + AHC_NEW_AUTOTERM = 0x0400, + AHC_AIC7770_FE = AHC_FENONE, + AHC_AIC7850_FE = AHC_SPIOCAP, + AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP, + AHC_AIC7870_FE = AHC_FENONE, + AHC_AIC7880_FE = AHC_ULTRA, + AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2| + AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM, + AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA, + AHC_AIC7896_FE = AHC_AIC7890_FE, + AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA3, + AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3, +} ahc_feature; + +#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset) + +struct aic7xxx_scb_dma { + unsigned long dma_offset; /* Correction you have to add + * to virtual address to get + * dma handle in this region */ + dma_addr_t dma_address; /* DMA handle of the start, + * for unmap */ + unsigned int dma_len; /* DMA length */ +}; + +struct aic7xxx_scb { + struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ + Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */ + struct aic7xxx_scb *q_next; /* next scb in queue */ + volatile scb_flag_type flags; /* current state of scb */ + struct hw_scatterlist *sg_list; /* SG list in adapter format */ + unsigned char tag_action; + unsigned char sg_count; + unsigned char *sense_cmd; /* + * Allocate 6 characters for + * sense command. + */ + unsigned char *cmnd; + unsigned int sg_length; /* We init this during buildscb so we + * don't have to calculate anything + * during underflow/overflow/stat code + */ + void *kmalloc_ptr; + struct aic7xxx_scb_dma *scb_dma; +}; + +/* + * Define a linked list of SCBs. + */ +typedef struct { + struct aic7xxx_scb *head; + struct aic7xxx_scb *tail; +} scb_queue_type; + +static struct { + unsigned char errno; + const char *errmesg; +} hard_error[] = { + { ILLHADDR, "Illegal Host Access" }, + { ILLSADDR, "Illegal Sequencer Address referenced" }, + { ILLOPCODE, "Illegal Opcode in sequencer program" }, + { SQPARERR, "Sequencer Ram Parity Error" }, + { DPARERR, "Data-Path Ram Parity Error" }, + { MPARERR, "Scratch Ram/SCB Array Ram Parity Error" }, + { PCIERRSTAT,"PCI Error detected" }, + { CIOPARERR, "CIOBUS Parity Error" } +}; + +static unsigned char +generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 }; + +typedef struct { + scb_queue_type free_scbs; /* + * SCBs assigned to free slot on + * card (no paging required) + */ + struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; + struct aic7xxx_hwscb *hscbs; + unsigned char numscbs; /* current number of scbs */ + unsigned char maxhscbs; /* hardware scbs */ + unsigned char maxscbs; /* max scbs including pageable scbs */ + dma_addr_t hscbs_dma; /* DMA handle to hscbs */ + unsigned int hscbs_dma_len; /* length of the above DMA area */ + void *hscb_kmalloc_ptr; +} scb_data_type; + +struct target_cmd { + unsigned char mesg_bytes[4]; + unsigned char command[28]; +}; + +#define AHC_TRANS_CUR 0x0001 +#define AHC_TRANS_ACTIVE 0x0002 +#define AHC_TRANS_GOAL 0x0004 +#define AHC_TRANS_USER 0x0008 +#define AHC_TRANS_QUITE 0x0010 +typedef struct { + unsigned char cur_width; + unsigned char goal_width; + unsigned char cur_period; + unsigned char goal_period; + unsigned char cur_offset; + unsigned char goal_offset; + unsigned char cur_options; + unsigned char goal_options; + unsigned char user_width; + unsigned char user_period; + unsigned char user_offset; + unsigned char user_options; +} transinfo_type; + +/* + * Define a structure used for each host adapter. Note, in order to avoid + * problems with architectures I can't test on (because I don't have one, + * such as the Alpha based systems) which happen to give faults for + * non-aligned memory accesses, care was taken to align this structure + * in a way that gauranteed all accesses larger than 8 bits were aligned + * on the appropriate boundary. It's also organized to try and be more + * cache line efficient. Be careful when changing this lest you might hurt + * overall performance and bring down the wrath of the masses. + */ +struct aic7xxx_host { + /* + * This is the first 64 bytes in the host struct + */ + + /* + * We are grouping things here....first, items that get either read or + * written with nearly every interrupt + */ + volatile long flags; + ahc_feature features; /* chip features */ + unsigned long base; /* card base address */ + volatile unsigned char *maddr; /* memory mapped address */ + unsigned long isr_count; /* Interrupt count */ + unsigned long spurious_int; + scb_data_type *scb_data; + volatile unsigned short needdv; + volatile unsigned short needppr; + volatile unsigned short needsdtr; + volatile unsigned short needwdtr; + volatile unsigned short dtr_pending; + struct aic7xxx_cmd_queue { + Scsi_Cmnd *head; + Scsi_Cmnd *tail; + } completeq; + + /* + * Things read/written on nearly every entry into aic7xxx_queue() + */ + volatile scb_queue_type waiting_scbs; + unsigned short discenable; /* Targets allowed to disconnect */ + unsigned short tagenable; /* Targets using tagged I/O */ + unsigned short orderedtag; /* Ordered Q tags allowed */ + unsigned char unpause; /* unpause value for HCNTRL */ + unsigned char pause; /* pause value for HCNTRL */ + volatile unsigned char qoutfifonext; + volatile unsigned char activescbs; /* active scbs */ + volatile unsigned char max_activescbs; + volatile unsigned char qinfifonext; + volatile unsigned char *untagged_scbs; + volatile unsigned char *qoutfifo; + volatile unsigned char *qinfifo; + +#define DEVICE_PRESENT 0x01 +#define BUS_DEVICE_RESET_PENDING 0x02 +#define DEVICE_RESET_DELAY 0x04 +#define DEVICE_PRINT_DTR 0x08 +#define DEVICE_PARITY_ERROR 0x10 +#define DEVICE_WAS_BUSY 0x20 +#define DEVICE_SCSI_3 0x40 +#define DEVICE_SCANNED 0x80 + volatile unsigned char dev_flags[MAX_TARGETS]; + volatile unsigned char dev_active_cmds[MAX_TARGETS]; + volatile unsigned char dev_temp_queue_depth[MAX_TARGETS]; + unsigned char dev_commands_sent[MAX_TARGETS]; + + unsigned int dev_timer_active; /* Which devs have a timer set */ + struct timer_list dev_timer; + unsigned long dev_expires[MAX_TARGETS]; + + spinlock_t spin_lock; + volatile unsigned char cpu_lock_count[NR_CPUS]; + + Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS]; + + unsigned int dev_checksum[MAX_TARGETS]; + + unsigned char dev_last_queue_full[MAX_TARGETS]; + unsigned char dev_last_queue_full_count[MAX_TARGETS]; + unsigned char dev_max_queue_depth[MAX_TARGETS]; + + volatile scb_queue_type delayed_scbs[MAX_TARGETS]; + + + unsigned char msg_buf[13]; /* The message for the target */ + unsigned char msg_type; +#define MSG_TYPE_NONE 0x00 +#define MSG_TYPE_INITIATOR_MSGOUT 0x01 +#define MSG_TYPE_INITIATOR_MSGIN 0x02 + unsigned char msg_len; /* Length of message */ + unsigned char msg_index; /* Index into msg_buf array */ + transinfo_type transinfo[MAX_TARGETS]; + + + /* + * We put the less frequently used host structure items after the more + * frequently used items to try and ease the burden on the cache subsystem. + * These entries are not *commonly* accessed, whereas the preceding entries + * are accessed very often. + */ + + unsigned int irq; /* IRQ for this adapter */ + int instance; /* aic7xxx instance number */ + int scsi_id; /* host adapter SCSI ID */ + int scsi_id_b; /* channel B for twin adapters */ + unsigned int bios_address; + int board_name_index; + unsigned short needppr_copy; /* default config */ + unsigned short needsdtr_copy; /* default config */ + unsigned short needwdtr_copy; /* default config */ + unsigned short ultraenb; /* Ultra mode target list */ + unsigned short bios_control; /* bios control - SEEPROM */ + unsigned short adapter_control; /* adapter control - SEEPROM */ + struct pci_dev *pdev; + unsigned char pci_bus; + unsigned char pci_device_fn; + struct seeprom_config sc; + unsigned short sc_type; + unsigned short sc_size; + struct aic7xxx_host *next; /* allow for multiple IRQs */ + struct Scsi_Host *host; /* pointer to scsi host */ + int host_no; /* SCSI host number */ + unsigned long mbase; /* I/O memory address */ + ahc_chip chip; /* chip type */ + dma_addr_t fifo_dma; /* DMA handle for fifo arrays */ + + /* + * Statistics Kept: + * + * Total Xfers (count for each command that has a data xfer), + * broken down further by reads && writes. + * + * Binned sizes, writes && reads: + * < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K + * + * Total amounts read/written above 512 bytes (amts under ignored) + * + * NOTE: Enabling this feature is likely to cause a noticeable performance + * decrease as the accesses into the stats structures blows apart multiple + * cache lines and is CPU time consuming. + * + * NOTE: Since it doesn't really buy us much, but consumes *tons* of RAM + * and blows apart all sorts of cache lines, I modified this so that we + * no longer look at the LUN. All LUNs now go into the same bin on each + * device for stats purposes. + */ + struct aic7xxx_xferstats { + long w_total; /* total writes */ + long r_total; /* total reads */ +#ifdef AIC7XXX_PROC_STATS + long w_bins[8]; /* binned write */ + long r_bins[8]; /* binned reads */ +#endif /* AIC7XXX_PROC_STATS */ + } stats[MAX_TARGETS]; /* [(channel << 3)|target] */ + +#if 0 + struct target_cmd *targetcmds; + unsigned int num_targetcmds; +#endif + +}; + +/* + * Valid SCSIRATE values. (p. 3-17) + * Provides a mapping of transfer periods in ns/4 to the proper value to + * stick in the SCSIRATE reg to use that transfer rate. + */ +#define AHC_SYNCRATE_ULTRA3 0 +#define AHC_SYNCRATE_ULTRA2 1 +#define AHC_SYNCRATE_ULTRA 3 +#define AHC_SYNCRATE_FAST 6 +#define AHC_SYNCRATE_CRC 0x40 +#define AHC_SYNCRATE_SE 0x10 +static struct aic7xxx_syncrate { + /* Rates in Ultra mode have bit 8 of sxfr set */ +#define ULTRA_SXFR 0x100 + int sxfr_ultra2; + int sxfr; + unsigned char period; + const char *rate[2]; +} aic7xxx_syncrates[] = { + { 0x42, 0x000, 9, {"80.0", "160.0"} }, + { 0x13, 0x000, 10, {"40.0", "80.0"} }, + { 0x14, 0x000, 11, {"33.0", "66.6"} }, + { 0x15, 0x100, 12, {"20.0", "40.0"} }, + { 0x16, 0x110, 15, {"16.0", "32.0"} }, + { 0x17, 0x120, 18, {"13.4", "26.8"} }, + { 0x18, 0x000, 25, {"10.0", "20.0"} }, + { 0x19, 0x010, 31, {"8.0", "16.0"} }, + { 0x1a, 0x020, 37, {"6.67", "13.3"} }, + { 0x1b, 0x030, 43, {"5.7", "11.4"} }, + { 0x10, 0x040, 50, {"5.0", "10.0"} }, + { 0x00, 0x050, 56, {"4.4", "8.8" } }, + { 0x00, 0x060, 62, {"4.0", "8.0" } }, + { 0x00, 0x070, 68, {"3.6", "7.2" } }, + { 0x00, 0x000, 0, {NULL, NULL} }, +}; + +#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1), \ + (((scb->hscb)->target_channel_lun >> 4) & 0xf), \ + ((scb->hscb)->target_channel_lun & 0x07) + +#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01), \ + ((cmd->target) & 0x0f), \ + ((cmd->lun) & 0x07) + +#define TARGET_INDEX(cmd) ((cmd)->target | ((cmd)->channel << 3)) + +/* + * A nice little define to make doing our printks a little easier + */ + +#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) " +#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) " + +/* + * XXX - these options apply unilaterally to _all_ 274x/284x/294x + * cards in the system. This should be fixed. Exceptions to this + * rule are noted in the comments. + */ + + +/* + * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This + * has no effect on any later resets that might occur due to things like + * SCSI bus timeouts. + */ +static unsigned int aic7xxx_no_reset = 0; +/* + * Certain PCI motherboards will scan PCI devices from highest to lowest, + * others scan from lowest to highest, and they tend to do all kinds of + * strange things when they come into contact with PCI bridge chips. The + * net result of all this is that the PCI card that is actually used to boot + * the machine is very hard to detect. Most motherboards go from lowest + * PCI slot number to highest, and the first SCSI controller found is the + * one you boot from. The only exceptions to this are when a controller + * has its BIOS disabled. So, we by default sort all of our SCSI controllers + * from lowest PCI slot number to highest PCI slot number. We also force + * all controllers with their BIOS disabled to the end of the list. This + * works on *almost* all computers. Where it doesn't work, we have this + * option. Setting this option to non-0 will reverse the order of the sort + * to highest first, then lowest, but will still leave cards with their BIOS + * disabled at the very end. That should fix everyone up unless there are + * really strange cirumstances. + */ +static int aic7xxx_reverse_scan = 0; +/* + * Should we force EXTENDED translation on a controller. + * 0 == Use whatever is in the SEEPROM or default to off + * 1 == Use whatever is in the SEEPROM or default to on + */ +static unsigned int aic7xxx_extended = 0; +/* + * The IRQ trigger method used on EISA controllers. Does not effect PCI cards. + * -1 = Use detected settings. + * 0 = Force Edge triggered mode. + * 1 = Force Level triggered mode. + */ +static int aic7xxx_irq_trigger = -1; +/* + * This variable is used to override the termination settings on a controller. + * This should not be used under normal conditions. However, in the case + * that a controller does not have a readable SEEPROM (so that we can't + * read the SEEPROM settings directly) and that a controller has a buggered + * version of the cable detection logic, this can be used to force the + * correct termination. It is preferable to use the manual termination + * settings in the BIOS if possible, but some motherboard controllers store + * those settings in a format we can't read. In other cases, auto term + * should also work, but the chipset was put together with no auto term + * logic (common on motherboard controllers). In those cases, we have + * 32 bits here to work with. That's good for 8 controllers/channels. The + * bits are organized as 4 bits per channel, with scsi0 getting the lowest + * 4 bits in the int. A 1 in a bit position indicates the termination setting + * that corresponds to that bit should be enabled, a 0 is disabled. + * It looks something like this: + * + * 0x0f = 1111-Single Ended Low Byte Termination on/off + * ||\-Single Ended High Byte Termination on/off + * |\-LVD Low Byte Termination on/off + * \-LVD High Byte Termination on/off + * + * For non-Ultra2 controllers, the upper 2 bits are not important. So, to + * enable both high byte and low byte termination on scsi0, I would need to + * make sure that the override_term variable was set to 0x03 (bits 0011). + * To make sure that all termination is enabled on an Ultra2 controller at + * scsi2 and only high byte termination on scsi1 and high and low byte + * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011) + * + * For the most part, users should never have to use this, that's why I + * left it fairly cryptic instead of easy to understand. If you need it, + * most likely someone will be telling you what your's needs to be set to. + */ +static int aic7xxx_override_term = -1; +/* + * Certain motherboard chipset controllers tend to screw + * up the polarity of the term enable output pin. Use this variable + * to force the correct polarity for your system. This is a bitfield variable + * similar to the previous one, but this one has one bit per channel instead + * of four. + * 0 = Force the setting to active low. + * 1 = Force setting to active high. + * Most Adaptec cards are active high, several motherboards are active low. + * To force a 2940 card at SCSI 0 to active high and a motherboard 7895 + * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3 + * to active high, you would need to set stpwlev=0x9 (bits 1001). + * + * People shouldn't need to use this, but if you are experiencing lots of + * SCSI timeout problems, this may help. There is one sure way to test what + * this option needs to be. Using a boot floppy to boot the system, configure + * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and + * if needed then also pass a value to override_term to make sure that the + * driver is enabling SCSI termination, then set this variable to either 0 + * or 1. When the driver boots, make sure there are *NO* SCSI cables + * connected to your controller. If it finds and inits the controller + * without problem, then the setting you passed to stpwlev was correct. If + * the driver goes into a reset loop and hangs the system, then you need the + * other setting for this variable. If neither setting lets the machine + * boot then you have definite termination problems that may not be fixable. + */ +static int aic7xxx_stpwlev = -1; +/* + * Set this to non-0 in order to force the driver to panic the kernel + * and print out debugging info on a SCSI abort or reset cycle. + */ +static int aic7xxx_panic_on_abort = 0; +/* + * PCI bus parity checking of the Adaptec controllers. This is somewhat + * dubious at best. To my knowledge, this option has never actually + * solved a PCI parity problem, but on certain machines with broken PCI + * chipset configurations, it can generate tons of false error messages. + * It's included in the driver for completeness. + * 0 = Shut off PCI parity check + * -1 = Normal polarity pci parity checking + * 1 = reverse polarity pci parity checking + * + * NOTE: you can't actually pass -1 on the lilo prompt. So, to set this + * variable to -1 you would actually want to simply pass the variable + * name without a number. That will invert the 0 which will result in + * -1. + */ +static int aic7xxx_pci_parity = 0; +/* + * Set this to any non-0 value to cause us to dump the contents of all + * the card's registers in a hex dump format tailored to each model of + * controller. + * + * NOTE: THE CONTROLLER IS LEFT IN AN UNUSEABLE STATE BY THIS OPTION. + * YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES + * ONLY + */ +static int aic7xxx_dump_card = 0; +/* + * Set this to a non-0 value to make us dump out the 32 bit instruction + * registers on the card after completing the sequencer download. This + * allows the actual sequencer download to be verified. It is possible + * to use this option and still boot up and run your system. This is + * only intended for debugging purposes. + */ +static int aic7xxx_dump_sequencer = 0; +/* + * Certain newer motherboards have put new PCI based devices into the + * IO spaces that used to typically be occupied by VLB or EISA cards. + * This overlap can cause these newer motherboards to lock up when scanned + * for older EISA and VLB devices. Setting this option to non-0 will + * cause the driver to skip scanning for any VLB or EISA controllers and + * only support the PCI controllers. NOTE: this means that if the kernel + * os compiled with PCI support disabled, then setting this to non-0 + * would result in never finding any devices :) + */ +static int aic7xxx_no_probe = 0; +/* + * On some machines, enabling the external SCB RAM isn't reliable yet. I + * haven't had time to make test patches for things like changing the + * timing mode on that external RAM either. Some of those changes may + * fix the problem. Until then though, we default to external SCB RAM + * off and give a command line option to enable it. + */ +static int aic7xxx_scbram = 0; +/* + * So that we can set how long each device is given as a selection timeout. + * The table of values goes like this: + * 0 - 256ms + * 1 - 128ms + * 2 - 64ms + * 3 - 32ms + * We default to 64ms because it's fast. Some old SCSI-I devices need a + * longer time. The final value has to be left shifted by 3, hence 0x10 + * is the final value. + */ +static int aic7xxx_seltime = 0x10; +/* + * So that insmod can find the variable and make it point to something + */ +#ifdef MODULE +static char * aic7xxx = NULL; +MODULE_PARM(aic7xxx, "s"); + +/* + * Just in case someone uses commas to separate items on the insmod + * command line, we define a dummy buffer here to avoid having insmod + * write wild stuff into our code segment + */ +static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n"; + +#endif + +#define VERBOSE_NORMAL 0x0000 +#define VERBOSE_NEGOTIATION 0x0001 +#define VERBOSE_SEQINT 0x0002 +#define VERBOSE_SCSIINT 0x0004 +#define VERBOSE_PROBE 0x0008 +#define VERBOSE_PROBE2 0x0010 +#define VERBOSE_NEGOTIATION2 0x0020 +#define VERBOSE_MINOR_ERROR 0x0040 +#define VERBOSE_TRACING 0x0080 +#define VERBOSE_ABORT 0x0f00 +#define VERBOSE_ABORT_MID 0x0100 +#define VERBOSE_ABORT_FIND 0x0200 +#define VERBOSE_ABORT_PROCESS 0x0400 +#define VERBOSE_ABORT_RETURN 0x0800 +#define VERBOSE_RESET 0xf000 +#define VERBOSE_RESET_MID 0x1000 +#define VERBOSE_RESET_FIND 0x2000 +#define VERBOSE_RESET_PROCESS 0x4000 +#define VERBOSE_RESET_RETURN 0x8000 +static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION | + VERBOSE_PROBE; /* verbose messages */ + + +/**************************************************************************** + * + * We're going to start putting in function declarations so that order of + * functions is no longer important. As needed, they are added here. + * + ***************************************************************************/ + +static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd); +static void aic7xxx_print_card(struct aic7xxx_host *p); +static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p); +static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded); +#ifdef AIC7XXX_VERBOSE_DEBUGGING +static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer); +#endif + +/**************************************************************************** + * + * These functions are now used. They happen to be wrapped in useless + * inb/outb port read/writes around the real reads and writes because it + * seems that certain very fast CPUs have a problem dealing with us when + * going at full speed. + * + ***************************************************************************/ + +static inline unsigned char +aic_inb(struct aic7xxx_host *p, long port) +{ +#ifdef MMAPIO + unsigned char x; + if(p->maddr) + { + x = readb(p->maddr + port); + } + else + { + x = inb(p->base + port); + } + return(x); +#else + return(inb(p->base + port)); +#endif +} + +static inline void +aic_outb(struct aic7xxx_host *p, unsigned char val, long port) +{ +#ifdef MMAPIO + if(p->maddr) + { + writeb(val, p->maddr + port); + mb(); /* locked operation in order to force CPU ordering */ + readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */ + } + else + { + outb(val, p->base + port); + mb(); /* locked operation in order to force CPU ordering */ + } +#else + outb(val, p->base + port); + mb(); /* locked operation in order to force CPU ordering */ +#endif +} + +/*+F************************************************************************* + * Function: + * aic7xxx_setup + * + * Description: + * Handle Linux boot parameters. This routine allows for assigning a value + * to a parameter with a ':' between the parameter and the value. + * ie. aic7xxx=unpause:0x0A,extended + *-F*************************************************************************/ +static int +aic7xxx_setup(char *s) +{ + int i, n; + char *p; + char *end; + + static struct { + const char *name; + unsigned int *flag; + } options[] = { + { "extended", &aic7xxx_extended }, + { "no_reset", &aic7xxx_no_reset }, + { "irq_trigger", &aic7xxx_irq_trigger }, + { "verbose", &aic7xxx_verbose }, + { "reverse_scan",&aic7xxx_reverse_scan }, + { "override_term", &aic7xxx_override_term }, + { "stpwlev", &aic7xxx_stpwlev }, + { "no_probe", &aic7xxx_no_probe }, + { "panic_on_abort", &aic7xxx_panic_on_abort }, + { "pci_parity", &aic7xxx_pci_parity }, + { "dump_card", &aic7xxx_dump_card }, + { "dump_sequencer", &aic7xxx_dump_sequencer }, + { "scbram", &aic7xxx_scbram }, + { "seltime", &aic7xxx_seltime }, + { "tag_info", NULL } + }; + + end = strchr(s, '\0'); + + for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) + { + for (i = 0; i < NUMBER(options); i++) + { + n = strlen(options[i].name); + if (!strncmp(options[i].name, p, n)) + { + if (!strncmp(p, "tag_info", n)) + { + if (p[n] == ':') + { + char *base; + char *tok, *tok_end, *tok_end2; + char tok_list[] = { '.', ',', '{', '}', '\0' }; + int i, instance = -1, device = -1; + unsigned char done = FALSE; + + base = p; + tok = base + n + 1; /* Forward us just past the ':' */ + tok_end = strchr(tok, '\0'); + if (tok_end < end) + *tok_end = ','; + while(!done) + { + switch(*tok) + { + case '{': + if (instance == -1) + instance = 0; + else if (device == -1) + device = 0; + tok++; + break; + case '}': + if (device != -1) + device = -1; + else if (instance != -1) + instance = -1; + tok++; + break; + case ',': + case '.': + if (instance == -1) + done = TRUE; + else if (device >= 0) + device++; + else if (instance >= 0) + instance++; + if ( (device >= MAX_TARGETS) || + (instance >= NUMBER(aic7xxx_tag_info)) ) + done = TRUE; + tok++; + if (!done) + { + base = tok; + } + break; + case '\0': + done = TRUE; + break; + default: + done = TRUE; + tok_end = strchr(tok, '\0'); + for(i=0; tok_list[i]; i++) + { + tok_end2 = strchr(tok, tok_list[i]); + if ( (tok_end2) && (tok_end2 < tok_end) ) + { + tok_end = tok_end2; + done = FALSE; + } + } + if ( (instance >= 0) && (device >= 0) && + (instance < NUMBER(aic7xxx_tag_info)) && + (device < MAX_TARGETS) ) + aic7xxx_tag_info[instance].tag_commands[device] = + simple_strtoul(tok, NULL, 0) & 0xff; + tok = tok_end; + break; + } + } + while((p != base) && (p != NULL)) + p = strtok(NULL, ",."); + } + } + else if (p[n] == ':') + { + *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); + if(!strncmp(p, "seltime", n)) + { + *(options[i].flag) = (*(options[i].flag) % 4) << 3; + } + } + else if (!strncmp(p, "verbose", n)) + { + *(options[i].flag) = 0xff29; + } + else + { + *(options[i].flag) = ~(*(options[i].flag)); + if(!strncmp(p, "seltime", n)) + { + *(options[i].flag) = (*(options[i].flag) % 4) << 3; + } + } + } + } + } + return 1; +} + +__setup("aic7xxx=", aic7xxx_setup); + +/*+F************************************************************************* + * Function: + * pause_sequencer + * + * Description: + * Pause the sequencer and wait for it to actually stop - this + * is important since the sequencer can disable pausing for critical + * sections. + *-F*************************************************************************/ +static void +pause_sequencer(struct aic7xxx_host *p) +{ + aic_outb(p, p->pause, HCNTRL); + while ((aic_inb(p, HCNTRL) & PAUSE) == 0) + { + ; + } + if(p->features & AHC_ULTRA2) + { + aic_inb(p, CCSCBCTL); + } +} + +/*+F************************************************************************* + * Function: + * unpause_sequencer + * + * Description: + * Unpause the sequencer. Unremarkable, yet done often enough to + * warrant an easy way to do it. + *-F*************************************************************************/ +static void +unpause_sequencer(struct aic7xxx_host *p, int unpause_always) +{ + if (unpause_always || + ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) && + !(p->flags & AHC_HANDLING_REQINITS) ) ) + { + aic_outb(p, p->unpause, HCNTRL); + } +} + +/*+F************************************************************************* + * Function: + * restart_sequencer + * + * Description: + * Restart the sequencer program from address zero. This assumes + * that the sequencer is already paused. + *-F*************************************************************************/ +static void +restart_sequencer(struct aic7xxx_host *p) +{ + aic_outb(p, 0, SEQADDR0); + aic_outb(p, 0, SEQADDR1); + aic_outb(p, FASTMODE, SEQCTL); +} + +/* + * We include the aic7xxx_seq.c file here so that the other defines have + * already been made, and so that it comes before the code that actually + * downloads the instructions (since we don't typically use function + * prototype, our code has to be ordered that way, it's a left-over from + * the original driver days.....I should fix it some time DL). + */ +#include "aic7xxx_old/aic7xxx_seq.c" + +/*+F************************************************************************* + * Function: + * aic7xxx_check_patch + * + * Description: + * See if the next patch to download should be downloaded. + *-F*************************************************************************/ +static int +aic7xxx_check_patch(struct aic7xxx_host *p, + struct sequencer_patch **start_patch, int start_instr, int *skip_addr) +{ + struct sequencer_patch *cur_patch; + struct sequencer_patch *last_patch; + int num_patches; + + num_patches = sizeof(sequencer_patches)/sizeof(struct sequencer_patch); + last_patch = &sequencer_patches[num_patches]; + cur_patch = *start_patch; + + while ((cur_patch < last_patch) && (start_instr == cur_patch->begin)) + { + if (cur_patch->patch_func(p) == 0) + { + /* + * Start rejecting code. + */ + *skip_addr = start_instr + cur_patch->skip_instr; + cur_patch += cur_patch->skip_patch; + } + else + { + /* + * Found an OK patch. Advance the patch pointer to the next patch + * and wait for our instruction pointer to get here. + */ + cur_patch++; + } + } + + *start_patch = cur_patch; + if (start_instr < *skip_addr) + /* + * Still skipping + */ + return (0); + return(1); +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_download_instr + * + * Description: + * Find the next patch to download. + *-F*************************************************************************/ +static void +aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr, + unsigned char *dconsts) +{ + union ins_formats instr; + struct ins_format1 *fmt1_ins; + struct ins_format3 *fmt3_ins; + unsigned char opcode; + + instr = *(union ins_formats*) &seqprog[instrptr * 4]; + + instr.integer = le32_to_cpu(instr.integer); + + fmt1_ins = &instr.format1; + fmt3_ins = NULL; + + /* Pull the opcode */ + opcode = instr.format1.opcode; + switch (opcode) + { + case AIC_OP_JMP: + case AIC_OP_JC: + case AIC_OP_JNC: + case AIC_OP_CALL: + case AIC_OP_JNE: + case AIC_OP_JNZ: + case AIC_OP_JE: + case AIC_OP_JZ: + { + struct sequencer_patch *cur_patch; + int address_offset; + unsigned int address; + int skip_addr; + int i; + + fmt3_ins = &instr.format3; + address_offset = 0; + address = fmt3_ins->address; + cur_patch = sequencer_patches; + skip_addr = 0; + + for (i = 0; i < address;) + { + aic7xxx_check_patch(p, &cur_patch, i, &skip_addr); + if (skip_addr > i) + { + int end_addr; + + end_addr = MIN(address, skip_addr); + address_offset += end_addr - i; + i = skip_addr; + } + else + { + i++; + } + } + address -= address_offset; + fmt3_ins->address = address; + /* Fall Through to the next code section */ + } + case AIC_OP_OR: + case AIC_OP_AND: + case AIC_OP_XOR: + case AIC_OP_ADD: + case AIC_OP_ADC: + case AIC_OP_BMOV: + if (fmt1_ins->parity != 0) + { + fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; + } + fmt1_ins->parity = 0; + /* Fall Through to the next code section */ + case AIC_OP_ROL: + if ((p->features & AHC_ULTRA2) != 0) + { + int i, count; + + /* Calculate odd parity for the instruction */ + for ( i=0, count=0; i < 31; i++) + { + unsigned int mask; + + mask = 0x01 << i; + if ((instr.integer & mask) != 0) + count++; + } + if (!(count & 0x01)) + instr.format1.parity = 1; + } + else + { + if (fmt3_ins != NULL) + { + instr.integer = fmt3_ins->immediate | + (fmt3_ins->source << 8) | + (fmt3_ins->address << 16) | + (fmt3_ins->opcode << 25); + } + else + { + instr.integer = fmt1_ins->immediate | + (fmt1_ins->source << 8) | + (fmt1_ins->destination << 16) | + (fmt1_ins->ret << 24) | + (fmt1_ins->opcode << 25); + } + } + aic_outb(p, (instr.integer & 0xff), SEQRAM); + aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM); + aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM); + aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM); + udelay(10); + break; + + default: + panic("aic7xxx: Unknown opcode encountered in sequencer program."); + break; + } +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_loadseq + * + * Description: + * Load the sequencer code into the controller memory. + *-F*************************************************************************/ +static void +aic7xxx_loadseq(struct aic7xxx_host *p) +{ + struct sequencer_patch *cur_patch; + int i; + int downloaded; + int skip_addr; + unsigned char download_consts[4] = {0, 0, 0, 0}; + + if (aic7xxx_verbose & VERBOSE_PROBE) + { + printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no); + } +#if 0 + download_consts[TMODE_NUMCMDS] = p->num_targetcmds; +#endif + download_consts[TMODE_NUMCMDS] = 0; + cur_patch = &sequencer_patches[0]; + downloaded = 0; + skip_addr = 0; + + aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL); + aic_outb(p, 0, SEQADDR0); + aic_outb(p, 0, SEQADDR1); + + for (i = 0; i < sizeof(seqprog) / 4; i++) + { + if (aic7xxx_check_patch(p, &cur_patch, i, &skip_addr) == 0) + { + /* Skip this instruction for this configuration. */ + continue; + } + aic7xxx_download_instr(p, i, &download_consts[0]); + downloaded++; + } + + aic_outb(p, 0, SEQADDR0); + aic_outb(p, 0, SEQADDR1); + aic_outb(p, FASTMODE | FAILDIS, SEQCTL); + unpause_sequencer(p, TRUE); + mdelay(1); + pause_sequencer(p); + aic_outb(p, FASTMODE, SEQCTL); + if (aic7xxx_verbose & VERBOSE_PROBE) + { + printk(" %d instructions downloaded\n", downloaded); + } + if (aic7xxx_dump_sequencer) + aic7xxx_print_sequencer(p, downloaded); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_print_sequencer + * + * Description: + * Print the contents of the sequencer memory to the screen. + *-F*************************************************************************/ +static void +aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded) +{ + int i, k, temp; + + aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL); + aic_outb(p, 0, SEQADDR0); + aic_outb(p, 0, SEQADDR1); + + k = 0; + for (i=0; i < downloaded; i++) + { + if ( k == 0 ) + printk("%03x: ", i); + temp = aic_inb(p, SEQRAM); + temp |= (aic_inb(p, SEQRAM) << 8); + temp |= (aic_inb(p, SEQRAM) << 16); + temp |= (aic_inb(p, SEQRAM) << 24); + printk("%08x", temp); + if ( ++k == 8 ) + { + printk("\n"); + k = 0; + } + else + printk(" "); + } + aic_outb(p, 0, SEQADDR0); + aic_outb(p, 0, SEQADDR1); + aic_outb(p, FASTMODE | FAILDIS, SEQCTL); + unpause_sequencer(p, TRUE); + mdelay(1); + pause_sequencer(p); + aic_outb(p, FASTMODE, SEQCTL); + printk("\n"); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_info + * + * Description: + * Return a string describing the driver. + *-F*************************************************************************/ +const char * +aic7xxx_info(struct Scsi_Host *dooh) +{ + static char buffer[256]; + char *bp; + struct aic7xxx_host *p; + + bp = &buffer[0]; + p = (struct aic7xxx_host *)dooh->hostdata; + memset(bp, 0, sizeof(buffer)); + strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) "); + strcat(bp, AIC7XXX_C_VERSION); + strcat(bp, "/"); + strcat(bp, AIC7XXX_H_VERSION); + strcat(bp, "\n"); + strcat(bp, " <"); + strcat(bp, board_names[p->board_name_index]); + strcat(bp, ">"); + + return(bp); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_find_syncrate + * + * Description: + * Look up the valid period to SCSIRATE conversion in our table + *-F*************************************************************************/ +static struct aic7xxx_syncrate * +aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period, + unsigned int maxsync, unsigned char *options) +{ + struct aic7xxx_syncrate *syncrate; + int done = FALSE; + + switch(*options) + { + case MSG_EXT_PPR_OPTION_DT_CRC: + case MSG_EXT_PPR_OPTION_DT_UNITS: + if(!(p->features & AHC_ULTRA3)) + { + *options = 0; + maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); + } + break; + case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: + case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK: + if(!(p->features & AHC_ULTRA3)) + { + *options = 0; + maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); + } + else + { + /* + * we don't support the Quick Arbitration variants of dual edge + * clocking. As it turns out, we want to send back the + * same basic option, but without the QA attribute. + * We know that we are responding because we would never set + * these options ourself, we would only respond to them. + */ + switch(*options) + { + case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: + *options = MSG_EXT_PPR_OPTION_DT_CRC; + break; + case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK: + *options = MSG_EXT_PPR_OPTION_DT_UNITS; + break; + } + } + break; + default: + *options = 0; + maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); + break; + } + syncrate = &aic7xxx_syncrates[maxsync]; + while ( (syncrate->rate[0] != NULL) && + (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) ) + { + if (*period <= syncrate->period) + { + switch(*options) + { + case MSG_EXT_PPR_OPTION_DT_CRC: + case MSG_EXT_PPR_OPTION_DT_UNITS: + if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC)) + { + done = TRUE; + /* + * oops, we went too low for the CRC/DualEdge signalling, so + * clear the options byte + */ + *options = 0; + /* + * We'll be sending a reply to this packet to set the options + * properly, so unilaterally set the period as well. + */ + *period = syncrate->period; + } + else + { + done = TRUE; + if(syncrate == &aic7xxx_syncrates[maxsync]) + { + *period = syncrate->period; + } + } + break; + default: + if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC)) + { + done = TRUE; + if(syncrate == &aic7xxx_syncrates[maxsync]) + { + *period = syncrate->period; + } + } + break; + } + if(done) + { + break; + } + } + syncrate++; + } + if ( (*period == 0) || (syncrate->rate[0] == NULL) || + ((p->features & AHC_ULTRA2) && (syncrate->sxfr_ultra2 == 0)) ) + { + /* + * Use async transfers for this target + */ + *options = 0; + *period = 255; + syncrate = NULL; + } + return (syncrate); +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_find_period + * + * Description: + * Look up the valid SCSIRATE to period conversion in our table + *-F*************************************************************************/ +static unsigned int +aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate, + unsigned int maxsync) +{ + struct aic7xxx_syncrate *syncrate; + + if (p->features & AHC_ULTRA2) + { + scsirate &= SXFR_ULTRA2; + } + else + { + scsirate &= SXFR; + } + + syncrate = &aic7xxx_syncrates[maxsync]; + while (syncrate->rate[0] != NULL) + { + if (p->features & AHC_ULTRA2) + { + if (syncrate->sxfr_ultra2 == 0) + break; + else if (scsirate == syncrate->sxfr_ultra2) + return (syncrate->period); + else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC)) + return (syncrate->period); + } + else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR)) + { + return (syncrate->period); + } + syncrate++; + } + return (0); /* async */ +} + +/*+F************************************************************************* + * Function: + * aic7xxx_validate_offset + * + * Description: + * Set a valid offset value for a particular card in use and transfer + * settings in use. + *-F*************************************************************************/ +static void +aic7xxx_validate_offset(struct aic7xxx_host *p, + struct aic7xxx_syncrate *syncrate, unsigned int *offset, int wide) +{ + unsigned int maxoffset; + + /* Limit offset to what the card (and device) can do */ + if (syncrate == NULL) + { + maxoffset = 0; + } + else if (p->features & AHC_ULTRA2) + { + maxoffset = MAX_OFFSET_ULTRA2; + } + else + { + if (wide) + maxoffset = MAX_OFFSET_16BIT; + else + maxoffset = MAX_OFFSET_8BIT; + } + *offset = MIN(*offset, maxoffset); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_set_syncrate + * + * Description: + * Set the actual syncrate down in the card and in our host structs + *-F*************************************************************************/ +static void +aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate, + int target, int channel, unsigned int period, unsigned int offset, + unsigned char options, unsigned int type) +{ + unsigned char tindex; + unsigned short target_mask; + unsigned char lun, old_options; + unsigned int old_period, old_offset; + + tindex = target | (channel << 3); + target_mask = 0x01 << tindex; + lun = aic_inb(p, SCB_TCL) & 0x07; + + if (syncrate == NULL) + { + period = 0; + offset = 0; + } + + old_period = p->transinfo[tindex].cur_period; + old_offset = p->transinfo[tindex].cur_offset; + old_options = p->transinfo[tindex].cur_options; + + + if (type & AHC_TRANS_CUR) + { + unsigned int scsirate; + + scsirate = aic_inb(p, TARG_SCSIRATE + tindex); + if (p->features & AHC_ULTRA2) + { + scsirate &= ~SXFR_ULTRA2; + if (syncrate != NULL) + { + switch(options) + { + case MSG_EXT_PPR_OPTION_DT_UNITS: + /* + * mask off the CRC bit in the xfer settings + */ + scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC); + break; + default: + scsirate |= syncrate->sxfr_ultra2; + break; + } + } + if (type & AHC_TRANS_ACTIVE) + { + aic_outb(p, offset, SCSIOFFSET); + } + aic_outb(p, offset, TARG_OFFSET + tindex); + } + else /* Not an Ultra2 controller */ + { + scsirate &= ~(SXFR|SOFS); + p->ultraenb &= ~target_mask; + if (syncrate != NULL) + { + if (syncrate->sxfr & ULTRA_SXFR) + { + p->ultraenb |= target_mask; + } + scsirate |= (syncrate->sxfr & SXFR); + scsirate |= (offset & SOFS); + } + if (type & AHC_TRANS_ACTIVE) + { + unsigned char sxfrctl0; + + sxfrctl0 = aic_inb(p, SXFRCTL0); + sxfrctl0 &= ~FAST20; + if (p->ultraenb & target_mask) + sxfrctl0 |= FAST20; + aic_outb(p, sxfrctl0, SXFRCTL0); + } + aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB); + aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1 ); + } + if (type & AHC_TRANS_ACTIVE) + { + aic_outb(p, scsirate, SCSIRATE); + } + aic_outb(p, scsirate, TARG_SCSIRATE + tindex); + p->transinfo[tindex].cur_period = period; + p->transinfo[tindex].cur_offset = offset; + p->transinfo[tindex].cur_options = options; + if ( !(type & AHC_TRANS_QUITE) && + (aic7xxx_verbose & VERBOSE_NEGOTIATION) && + (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) + { + if (offset) + { + int rate_mod = (scsirate & WIDEXFER) ? 1 : 0; + + printk(INFO_LEAD "Synchronous at %s Mbyte/sec, " + "offset %d.\n", p->host_no, channel, target, lun, + syncrate->rate[rate_mod], offset); + } + else + { + printk(INFO_LEAD "Using asynchronous transfers.\n", + p->host_no, channel, target, lun); + } + p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR; + } + } + + if (type & AHC_TRANS_GOAL) + { + p->transinfo[tindex].goal_period = period; + p->transinfo[tindex].goal_offset = offset; + p->transinfo[tindex].goal_options = options; + } + + if (type & AHC_TRANS_USER) + { + p->transinfo[tindex].user_period = period; + p->transinfo[tindex].user_offset = offset; + p->transinfo[tindex].user_options = options; + } +} + +/*+F************************************************************************* + * Function: + * aic7xxx_set_width + * + * Description: + * Set the actual width down in the card and in our host structs + *-F*************************************************************************/ +static void +aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun, + unsigned int width, unsigned int type) +{ + unsigned char tindex; + unsigned short target_mask; + unsigned int old_width; + + tindex = target | (channel << 3); + target_mask = 1 << tindex; + + old_width = p->transinfo[tindex].cur_width; + + if (type & AHC_TRANS_CUR) + { + unsigned char scsirate; + + scsirate = aic_inb(p, TARG_SCSIRATE + tindex); + + scsirate &= ~WIDEXFER; + if (width == MSG_EXT_WDTR_BUS_16_BIT) + scsirate |= WIDEXFER; + + aic_outb(p, scsirate, TARG_SCSIRATE + tindex); + + if (type & AHC_TRANS_ACTIVE) + aic_outb(p, scsirate, SCSIRATE); + + p->transinfo[tindex].cur_width = width; + + if ( !(type & AHC_TRANS_QUITE) && + (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) + { + printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target, + lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" ); + } + } + + if (type & AHC_TRANS_GOAL) + p->transinfo[tindex].goal_width = width; + if (type & AHC_TRANS_USER) + p->transinfo[tindex].user_width = width; + + if (p->transinfo[tindex].goal_offset) + { + if (p->features & AHC_ULTRA2) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + } + else if (width == MSG_EXT_WDTR_BUS_16_BIT) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + } + else + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + } + } +} + +/*+F************************************************************************* + * Function: + * scbq_init + * + * Description: + * SCB queue initialization. + * + *-F*************************************************************************/ +static void +scbq_init(volatile scb_queue_type *queue) +{ + queue->head = NULL; + queue->tail = NULL; +} + +/*+F************************************************************************* + * Function: + * scbq_insert_head + * + * Description: + * Add an SCB to the head of the list. + * + *-F*************************************************************************/ +static inline void +scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags; +#endif + + DRIVER_LOCK + scb->q_next = queue->head; + queue->head = scb; + if (queue->tail == NULL) /* If list was empty, update tail. */ + queue->tail = queue->head; + DRIVER_UNLOCK +} + +/*+F************************************************************************* + * Function: + * scbq_remove_head + * + * Description: + * Remove an SCB from the head of the list. + * + *-F*************************************************************************/ +static inline struct aic7xxx_scb * +scbq_remove_head(volatile scb_queue_type *queue) +{ + struct aic7xxx_scb * scbp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags; +#endif + + DRIVER_LOCK + scbp = queue->head; + if (queue->head != NULL) + queue->head = queue->head->q_next; + if (queue->head == NULL) /* If list is now empty, update tail. */ + queue->tail = NULL; + DRIVER_UNLOCK + return(scbp); +} + +/*+F************************************************************************* + * Function: + * scbq_remove + * + * Description: + * Removes an SCB from the list. + * + *-F*************************************************************************/ +static inline void +scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags; +#endif + + DRIVER_LOCK + if (queue->head == scb) + { + /* At beginning of queue, remove from head. */ + scbq_remove_head(queue); + } + else + { + struct aic7xxx_scb *curscb = queue->head; + + /* + * Search until the next scb is the one we're looking for, or + * we run out of queue. + */ + while ((curscb != NULL) && (curscb->q_next != scb)) + { + curscb = curscb->q_next; + } + if (curscb != NULL) + { + /* Found it. */ + curscb->q_next = scb->q_next; + if (scb->q_next == NULL) + { + /* Update the tail when removing the tail. */ + queue->tail = curscb; + } + } + } + DRIVER_UNLOCK +} + +/*+F************************************************************************* + * Function: + * scbq_insert_tail + * + * Description: + * Add an SCB at the tail of the list. + * + *-F*************************************************************************/ +static inline void +scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags; +#endif + + DRIVER_LOCK + scb->q_next = NULL; + if (queue->tail != NULL) /* Add the scb at the end of the list. */ + queue->tail->q_next = scb; + queue->tail = scb; /* Update the tail. */ + if (queue->head == NULL) /* If list was empty, update head. */ + queue->head = queue->tail; + DRIVER_UNLOCK +} + +/*+F************************************************************************* + * Function: + * aic7xxx_match_scb + * + * Description: + * Checks to see if an scb matches the target/channel as specified. + * If target is ALL_TARGETS (-1), then we're looking for any device + * on the specified channel; this happens when a channel is going + * to be reset and all devices on that channel must be aborted. + *-F*************************************************************************/ +static int +aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, + int target, int channel, int lun, unsigned char tag) +{ + int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F; + int chan = (scb->hscb->target_channel_lun >> 3) & 0x01; + int slun = scb->hscb->target_channel_lun & 0x07; + int match; + + match = ((chan == channel) || (channel == ALL_CHANNELS)); + if (match != 0) + match = ((targ == target) || (target == ALL_TARGETS)); + if (match != 0) + match = ((lun == slun) || (lun == ALL_LUNS)); + if (match != 0) + match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); + + return (match); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_add_curscb_to_free_list + * + * Description: + * Adds the current scb (in SCBPTR) to the list of free SCBs. + *-F*************************************************************************/ +static void +aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p) +{ + /* + * Invalidate the tag so that aic7xxx_find_scb doesn't think + * it's active + */ + aic_outb(p, SCB_LIST_NULL, SCB_TAG); + aic_outb(p, 0, SCB_CONTROL); + + aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT); + aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_rem_scb_from_disc_list + * + * Description: + * Removes the current SCB from the disconnected list and adds it + * to the free list. + *-F*************************************************************************/ +static unsigned char +aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr, + unsigned char prev) +{ + unsigned char next; + + aic_outb(p, scbptr, SCBPTR); + next = aic_inb(p, SCB_NEXT); + aic7xxx_add_curscb_to_free_list(p); + + if (prev != SCB_LIST_NULL) + { + aic_outb(p, prev, SCBPTR); + aic_outb(p, next, SCB_NEXT); + } + else + { + aic_outb(p, next, DISCONNECTED_SCBH); + } + + return next; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_busy_target + * + * Description: + * Set the specified target busy. + *-F*************************************************************************/ +static inline void +aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_index_busy_target + * + * Description: + * Returns the index of the busy target, and optionally sets the + * target inactive. + *-F*************************************************************************/ +static inline unsigned char +aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl, + int unbusy) +{ + unsigned char busy_scbid; + + busy_scbid = p->untagged_scbs[tcl]; + if (unbusy) + { + p->untagged_scbs[tcl] = SCB_LIST_NULL; + } + return (busy_scbid); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_find_scb + * + * Description: + * Look through the SCB array of the card and attempt to find the + * hardware SCB that corresponds to the passed in SCB. Return + * SCB_LIST_NULL if unsuccessful. This routine assumes that the + * card is already paused. + *-F*************************************************************************/ +static unsigned char +aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + unsigned char saved_scbptr; + unsigned char curindex; + + saved_scbptr = aic_inb(p, SCBPTR); + curindex = 0; + for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++) + { + aic_outb(p, curindex, SCBPTR); + if (aic_inb(p, SCB_TAG) == scb->hscb->tag) + { + break; + } + } + aic_outb(p, saved_scbptr, SCBPTR); + if (curindex >= p->scb_data->maxhscbs) + { + curindex = SCB_LIST_NULL; + } + + return (curindex); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_allocate_scb + * + * Description: + * Get an SCB from the free list or by allocating a new one. + *-F*************************************************************************/ +static int +aic7xxx_allocate_scb(struct aic7xxx_host *p) +{ + struct aic7xxx_scb *scbp = NULL; + int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6; + int i; + int step = PAGE_SIZE / 1024; + unsigned long scb_count = 0; + struct hw_scatterlist *hsgp; + struct aic7xxx_scb *scb_ap; + struct aic7xxx_scb_dma *scb_dma; + unsigned char *bufs; + + if (p->scb_data->numscbs < p->scb_data->maxscbs) + { + /* + * Calculate the optimal number of SCBs to allocate. + * + * NOTE: This formula works because the sizeof(sg_array) is always + * 1024. Therefore, scb_size * i would always be > PAGE_SIZE * + * (i/step). The (i-1) allows the left hand side of the equation + * to grow into the right hand side to a point of near perfect + * efficiency since scb_size * (i -1) is growing slightly faster + * than the right hand side. If the number of SG array elements + * is changed, this function may not be near so efficient any more. + * + * Since the DMA'able buffers are now allocated in a seperate + * chunk this algorithm has been modified to match. The '12' + * and '6' factors in scb_size are for the DMA'able command byte + * and sensebuffers respectively. -DaveM + */ + for ( i=step;; i *= 2 ) + { + if ( (scb_size * (i-1)) >= ( (PAGE_SIZE * (i/step)) - 64 ) ) + { + i /= 2; + break; + } + } + scb_count = MIN( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs); + scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count + + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC); + if (scb_ap == NULL) + return(0); + scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count]; + hsgp = (struct hw_scatterlist *) + pci_alloc_consistent(p->pdev, scb_size * scb_count, + &scb_dma->dma_address); + if (hsgp == NULL) + { + kfree(scb_ap); + return(0); + } + bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG]; +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose > 0xffff) + { + if (p->scb_data->numscbs == 0) + printk(INFO_LEAD "Allocating initial %ld SCB structures.\n", + p->host_no, -1, -1, -1, scb_count); + else + printk(INFO_LEAD "Allocating %ld additional SCB structures.\n", + p->host_no, -1, -1, -1, scb_count); + } +#endif + memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count); + scb_dma->dma_offset = (unsigned long)scb_dma->dma_address + - (unsigned long)hsgp; + scb_dma->dma_len = scb_size * scb_count; + for (i=0; i < scb_count; i++) + { + scbp = &scb_ap[i]; + scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs]; + scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG]; + scbp->sense_cmd = bufs; + scbp->cmnd = bufs + 6; + bufs += 12 + 6; + scbp->scb_dma = scb_dma; + memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb)); + scbp->hscb->tag = p->scb_data->numscbs; + /* + * Place in the scb array; never is removed + */ + p->scb_data->scb_array[p->scb_data->numscbs++] = scbp; + scbq_insert_tail(&p->scb_data->free_scbs, scbp); + } + scbp->kmalloc_ptr = scb_ap; + } + return(scb_count); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_queue_cmd_complete + * + * Description: + * Due to race conditions present in the SCSI subsystem, it is easier + * to queue completed commands, then call scsi_done() on them when + * we're finished. This function queues the completed commands. + *-F*************************************************************************/ +static void +aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd) +{ + cmd->host_scribble = (char *)p->completeq.head; + p->completeq.head = cmd; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_done_cmds_complete + * + * Description: + * Process the completed command queue. + *-F*************************************************************************/ +static void +aic7xxx_done_cmds_complete(struct aic7xxx_host *p) +{ + Scsi_Cmnd *cmd; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned int cpu_flags = 0; +#endif + + DRIVER_LOCK + while (p->completeq.head != NULL) + { + cmd = p->completeq.head; + p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; + cmd->host_scribble = NULL; + cmd->scsi_done(cmd); + } + DRIVER_UNLOCK +} + +/*+F************************************************************************* + * Function: + * aic7xxx_free_scb + * + * Description: + * Free the scb and insert into the free scb list. + *-F*************************************************************************/ +static void +aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + + scb->flags = SCB_FREE; + scb->cmd = NULL; + scb->sg_count = 0; + scb->sg_length = 0; + scb->tag_action = 0; + scb->hscb->control = 0; + scb->hscb->target_status = 0; + scb->hscb->target_channel_lun = SCB_LIST_NULL; + + scbq_insert_head(&p->scb_data->free_scbs, scb); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_done + * + * Description: + * Calls the higher level scsi done function and frees the scb. + *-F*************************************************************************/ +static void +aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + Scsi_Cmnd *cmd = scb->cmd; + int tindex = TARGET_INDEX(cmd); + struct aic7xxx_scb *scbp; + unsigned char queue_depth; + + if (cmd->use_sg > 1) + { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } + else if (cmd->request_bufflen) + pci_unmap_single(p->pdev, aic7xxx_mapping(cmd), + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + if (scb->flags & SCB_SENSE) + { + pci_unmap_single(p->pdev, + le32_to_cpu(scb->sg_list[0].address), + sizeof(cmd->sense_buffer), + PCI_DMA_FROMDEVICE); + } + if (scb->flags & SCB_RECOVERY_SCB) + { + p->flags &= ~AHC_ABORT_PENDING; + } + if (scb->flags & SCB_RESET) + { + cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); + } + else if (scb->flags & SCB_ABORT) + { + cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff); + } + else if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) + { + if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) ) + { + char *buffer; + + p->dev_flags[tindex] |= DEVICE_PRESENT; + if(cmd->use_sg) + { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + buffer = (char *)sg[0].address; + } + else + { + buffer = (char *)cmd->request_buffer; + } +#define WIDE_INQUIRY_BITS 0x60 +#define SYNC_INQUIRY_BITS 0x10 +#define SCSI_VERSION_BITS 0x07 +#define SCSI_DT_BIT 0x04 + if ( (buffer[7] & WIDE_INQUIRY_BITS) && + (p->features & AHC_WIDE) ) + { + p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width = p->transinfo[tindex].user_width; + } + else + { + p->needwdtr &= ~(1<needwdtr_copy &= ~(1<target, cmd->channel, cmd->lun, + MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | + AHC_TRANS_GOAL | + AHC_TRANS_CUR) ); + unpause_sequencer(p, FALSE); + } + if ( (buffer[7] & SYNC_INQUIRY_BITS) && + p->transinfo[tindex].user_offset ) + { + p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options; + if (p->features & AHC_ULTRA2) + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT) + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + else + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) || + (buffer[56] & SCSI_DT_BIT) || + (p->dev_flags[tindex] & DEVICE_SCSI_3) ) && + (p->transinfo[tindex].user_period <= 9) && + (p->transinfo[tindex].user_options) ) + { + p->needppr |= (1<needppr_copy |= (1<needsdtr &= ~(1<needsdtr_copy &= ~(1<needwdtr &= ~(1<needwdtr_copy &= ~(1<dev_flags[tindex] |= DEVICE_SCSI_3; + } + else + { + p->needsdtr |= (1<needsdtr_copy |= (1<transinfo[tindex].goal_period = + MAX(10, p->transinfo[tindex].goal_period); + p->transinfo[tindex].goal_options = 0; + } + } + else + { + p->needsdtr &= ~(1<needsdtr_copy &= ~(1<transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_options = 0; + } + /* + * This is needed to work around a sequencer bug for now. Regardless + * of the controller in use, if we have a Quantum drive, we need to + * limit the speed to 80MByte/sec. As soon as I get a fixed version + * of the sequencer, this code will get yanked. + */ + if(!strncmp(buffer + 8, "QUANTUM", 7) && + p->transinfo[tindex].goal_options ) + { + p->transinfo[tindex].goal_period = + MAX(p->transinfo[tindex].goal_period, 10); + p->transinfo[tindex].goal_options = 0; + p->needppr &= ~(1<needppr_copy &= ~(1<needsdtr |= (1<needsdtr_copy |= (1<needwdtr |= (1<needwdtr_copy |= (1<dev_dtr_cmnd[tindex] == cmd) { + unsigned int checksum = 0; + int *ibuffer; + int i=0; + + ibuffer = (int *)buffer; + for( i = 0; i < (cmd->request_bufflen >> 2); i++) + { + checksum += ibuffer[i]; + } + p->dev_checksum[tindex] = checksum; + p->dev_flags[tindex] |= DEVICE_SCANNED; + p->dev_flags[tindex] |= DEVICE_PRINT_DTR; + } +#undef WIDE_INQUIRY_BITS +#undef SYNC_INQUIRY_BITS +#undef SCSI_VERSION_BITS +#undef SCSI_DT_BIT + } + } + else if ((scb->flags & SCB_MSGOUT_BITS) != 0) + { + unsigned short mask; + int message_error = FALSE; + + mask = 0x01 << tindex; + + /* + * Check to see if we get an invalid message or a message error + * after failing to negotiate a wide or sync transfer message. + */ + if ((scb->flags & SCB_SENSE) && + ((scb->cmd->sense_buffer[12] == 0x43) || /* INVALID_MESSAGE */ + (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR */ + { + message_error = TRUE; + } + + if (scb->flags & SCB_MSGOUT_WDTR) + { + p->dtr_pending &= ~mask; + if (message_error) + { + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) + { + printk(INFO_LEAD "Device failed to complete Wide Negotiation " + "processing and\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "returned a sense error code for invalid message, " + "disabling future\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no, + CTL_OF_SCB(scb)); + } + p->needwdtr &= ~mask; + p->needwdtr_copy &= ~mask; + } + } + if (scb->flags & SCB_MSGOUT_SDTR) + { + p->dtr_pending &= ~mask; + if (message_error) + { + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) + { + printk(INFO_LEAD "Device failed to complete Sync Negotiation " + "processing and\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "returned a sense error code for invalid message, " + "disabling future\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no, + CTL_OF_SCB(scb)); + p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR; + } + p->needsdtr &= ~mask; + p->needsdtr_copy &= ~mask; + } + } + if (scb->flags & SCB_MSGOUT_PPR) + { + p->dtr_pending &= ~mask; + if(message_error) + { + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + (p->dev_flags[tindex] & DEVICE_PRINT_DTR) ) + { + printk(INFO_LEAD "Device failed to complete Parallel Protocol " + "Request processing and\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "returned a sense error code for invalid message, " + "disabling future\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "Parallel Protocol Request negotiation to this " + "device.\n", p->host_no, CTL_OF_SCB(scb)); + } + /* + * Disable PPR negotiation and revert back to WDTR and SDTR setup + */ + p->needppr &= ~mask; + p->needppr_copy &= ~mask; + p->needsdtr |= mask; + p->needsdtr_copy |= mask; + p->needwdtr |= mask; + p->needwdtr_copy |= mask; + } + } + } + queue_depth = p->dev_temp_queue_depth[tindex]; + if (queue_depth >= p->dev_active_cmds[tindex]) + { + scbp = scbq_remove_head(&p->delayed_scbs[tindex]); + if (scbp) + { + if (queue_depth == 1) + { + /* + * Give extra preference to untagged devices, such as CD-R devices + * This makes it more likely that a drive *won't* stuff up while + * waiting on data at a critical time, such as CD-R writing and + * audio CD ripping operations. Should also benefit tape drives. + */ + scbq_insert_head(&p->waiting_scbs, scbp); + } + else + { + scbq_insert_tail(&p->waiting_scbs, scbp); + } +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose > 0xffff) + printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n", + p->host_no, CTL_OF_SCB(scbp)); +#endif + if (queue_depth > p->dev_active_cmds[tindex]) + { + scbp = scbq_remove_head(&p->delayed_scbs[tindex]); + if (scbp) + scbq_insert_tail(&p->waiting_scbs, scbp); + } + } + } + if ( !(scb->tag_action) && (p->tagenable & (1<dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex]; + } + p->dev_active_cmds[tindex]--; + p->activescbs--; + + { + int actual; + + /* + * XXX: we should actually know how much actually transferred + * XXX: for each command, but apparently that's too difficult. + * + * We set a lower limit of 512 bytes on the transfer length. We + * ignore anything less than this because we don't have a real + * reason to count it. Read/Writes to tapes are usually about 20K + * and disks are a minimum of 512 bytes unless you want to count + * non-read/write commands (such as TEST_UNIT_READY) which we don't + */ + actual = scb->sg_length; + if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK)) + { + struct aic7xxx_xferstats *sp; +#ifdef AIC7XXX_PROC_STATS + long *ptr; + int x; +#endif /* AIC7XXX_PROC_STATS */ + + sp = &p->stats[TARGET_INDEX(cmd)]; + + /* + * For block devices, cmd->request.cmd is always == either READ or + * WRITE. For character devices, this isn't always set properly, so + * we check data_cmnd[0]. This catches the conditions for st.c, but + * I'm still not sure if request.cmd is valid for sg devices. + */ + if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) || + (cmd->data_cmnd[0] == WRITE_FILEMARKS) ) + { + sp->w_total++; +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if ( (sp->w_total > 16) && (aic7xxx_verbose > 0xffff) ) + aic7xxx_verbose &= 0xffff; +#endif +#ifdef AIC7XXX_PROC_STATS + ptr = sp->w_bins; +#endif /* AIC7XXX_PROC_STATS */ + } + else + { + sp->r_total++; +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if ( (sp->r_total > 16) && (aic7xxx_verbose > 0xffff) ) + aic7xxx_verbose &= 0xffff; +#endif +#ifdef AIC7XXX_PROC_STATS + ptr = sp->r_bins; +#endif /* AIC7XXX_PROC_STATS */ + } +#ifdef AIC7XXX_PROC_STATS + x = -11; + while(actual) + { + actual >>= 1; + x++; + } + if (x < 0) + { + ptr[0]++; + } + else if (x > 7) + { + ptr[7]++; + } + else + { + ptr[x]++; + } +#endif /* AIC7XXX_PROC_STATS */ + } + } + aic7xxx_free_scb(p, scb); + aic7xxx_queue_cmd_complete(p, cmd); + +} + +/*+F************************************************************************* + * Function: + * aic7xxx_run_done_queue + * + * Description: + * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the + * aborted list, and adds each scb to the free list. If complete + * is TRUE, we also process the commands complete list. + *-F*************************************************************************/ +static void +aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete) +{ + struct aic7xxx_scb *scb; + int i, found = 0; + + for (i = 0; i < p->scb_data->numscbs; i++) + { + scb = p->scb_data->scb_array[i]; + if (scb->flags & SCB_QUEUED_FOR_DONE) + { + if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) + printk(INFO_LEAD "Aborting scb %d\n", + p->host_no, CTL_OF_SCB(scb), scb->hscb->tag); + found++; + aic7xxx_done(p, scb); + } + } + if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN)) + { + printk(INFO_LEAD "%d commands found and queued for " + "completion.\n", p->host_no, -1, -1, -1, found); + } + if (complete) + { + aic7xxx_done_cmds_complete(p); + } +} + +/*+F************************************************************************* + * Function: + * aic7xxx_abort_waiting_scb + * + * Description: + * Manipulate the waiting for selection list and return the + * scb that follows the one that we remove. + *-F*************************************************************************/ +static unsigned char +aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, + unsigned char scbpos, unsigned char prev) +{ + unsigned char curscb, next; + + /* + * Select the SCB we want to abort and pull the next pointer out of it. + */ + curscb = aic_inb(p, SCBPTR); + aic_outb(p, scbpos, SCBPTR); + next = aic_inb(p, SCB_NEXT); + + aic7xxx_add_curscb_to_free_list(p); + + /* + * Update the waiting list + */ + if (prev == SCB_LIST_NULL) + { + /* + * First in the list + */ + aic_outb(p, next, WAITING_SCBH); + } + else + { + /* + * Select the scb that pointed to us and update its next pointer. + */ + aic_outb(p, prev, SCBPTR); + aic_outb(p, next, SCB_NEXT); + } + /* + * Point us back at the original scb position and inform the SCSI + * system that the command has been aborted. + */ + aic_outb(p, curscb, SCBPTR); + return (next); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_search_qinfifo + * + * Description: + * Search the queue-in FIFO for matching SCBs and conditionally + * requeue. Returns the number of matching SCBs. + *-F*************************************************************************/ +static int +aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel, + int lun, unsigned char tag, int flags, int requeue, + volatile scb_queue_type *queue) +{ + int found; + unsigned char qinpos, qintail; + struct aic7xxx_scb *scbp; + + found = 0; + qinpos = aic_inb(p, QINPOS); + qintail = p->qinfifonext; + + p->qinfifonext = qinpos; + + while (qinpos != qintail) + { + scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]]; + if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) + { + /* + * We found an scb that needs to be removed. + */ + if (requeue && (queue != NULL)) + { + if (scbp->flags & SCB_WAITINGQ) + { + scbq_remove(queue, scbp); + scbq_remove(&p->waiting_scbs, scbp); + scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp); + p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; + p->activescbs++; + } + scbq_insert_tail(queue, scbp); + p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--; + p->activescbs--; + scbp->flags |= SCB_WAITINGQ; + if ( !(scbp->tag_action & TAG_ENB) ) + { + aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, + TRUE); + } + } + else if (requeue) + { + p->qinfifo[p->qinfifonext++] = scbp->hscb->tag; + } + else + { + /* + * Preserve any SCB_RECOVERY_SCB flags on this scb then set the + * flags we were called with, presumeably so aic7xxx_run_done_queue + * can find this scb + */ + scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB); + if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, + FALSE) == scbp->hscb->tag) + { + aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, + TRUE); + } + } + found++; + } + else + { + p->qinfifo[p->qinfifonext++] = scbp->hscb->tag; + } + } + /* + * Now that we've done the work, clear out any left over commands in the + * qinfifo and update the KERNEL_QINPOS down on the card. + * + * NOTE: This routine expect the sequencer to already be paused when + * it is run....make sure it's that way! + */ + qinpos = p->qinfifonext; + while(qinpos != qintail) + { + p->qinfifo[qinpos++] = SCB_LIST_NULL; + } + if (p->features & AHC_QUEUE_REGS) + aic_outb(p, p->qinfifonext, HNSCB_QOFF); + else + aic_outb(p, p->qinfifonext, KERNEL_QINPOS); + + return (found); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_scb_on_qoutfifo + * + * Description: + * Is the scb that was passed to us currently on the qoutfifo? + *-F*************************************************************************/ +static int +aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + int i=0; + + while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL) + { + if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag) + return TRUE; + else + i++; + } + return FALSE; +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_reset_device + * + * Description: + * The device at the given target/channel has been reset. Abort + * all active and queued scbs for that target/channel. This function + * need not worry about linked next pointers because if was a MSG_ABORT_TAG + * then we had a tagged command (no linked next), if it was MSG_ABORT or + * MSG_BUS_DEV_RESET then the device won't know about any commands any more + * and no busy commands will exist, and if it was a bus reset, then nothing + * knows about any linked next commands any more. In all cases, we don't + * need to worry about the linked next or busy scb, we just need to clear + * them. + *-F*************************************************************************/ +static void +aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, + int lun, unsigned char tag) +{ + struct aic7xxx_scb *scbp; + unsigned char active_scb, tcl; + int i = 0, j, init_lists = FALSE; + + /* + * Restore this when we're done + */ + active_scb = aic_inb(p, SCBPTR); + + if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) + printk(INFO_LEAD "Reset device, active_scb %d\n", + p->host_no, channel, target, lun, active_scb); + /* + * Deal with the busy target and linked next issues. + */ + { + int min_target, max_target; + struct aic7xxx_scb *scbp, *prev_scbp; + + /* Make all targets 'relative' to bus A. */ + if (target == ALL_TARGETS) + { + switch (channel) + { + case 0: + min_target = 0; + max_target = (p->features & AHC_WIDE) ? 15 : 7; + break; + case 1: + min_target = 8; + max_target = 15; + break; + case ALL_CHANNELS: + default: + min_target = 0; + max_target = (p->features & (AHC_TWIN|AHC_WIDE)) ? 15 : 7; + break; + } + } + else + { + min_target = target | (channel << 3); + max_target = min_target; + } + + + for (i = min_target; i <= max_target; i++) + { + if ( i == p->scsi_id ) + { + continue; + } + if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) + printk(INFO_LEAD "Cleaning up status information " + "and delayed_scbs.\n", p->host_no, channel, i, lun); + p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR); + if ( tag == SCB_LIST_NULL ) + { + p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY; + p->dev_expires[i] = jiffies + (4 * HZ); + p->dev_timer_active |= (0x01 << i); + p->dev_last_queue_full_count[i] = 0; + p->dev_last_queue_full[i] = 0; + p->dev_temp_queue_depth[i] = + p->dev_max_queue_depth[i]; + } + for(j=0; jdelayed_scbs[i].head; + while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) ) + { + prev_scbp = scbp; + scbp = scbp->q_next; + if ( prev_scbp == scbp ) + { + if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) + printk(WARN_LEAD "Yikes!! scb->q_next == scb " + "in the delayed_scbs queue!\n", p->host_no, channel, i, lun); + scbp = NULL; + prev_scbp->q_next = NULL; + p->delayed_scbs[i].tail = prev_scbp; + } + if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) + { + scbq_remove(&p->delayed_scbs[i], prev_scbp); + if (prev_scbp->flags & SCB_WAITINGQ) + { + p->dev_active_cmds[i]++; + p->activescbs++; + } + prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); + prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; + } + } + if ( j > (p->scb_data->maxscbs + 1) ) + { + if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) + printk(WARN_LEAD "Yikes!! There's a loop in the " + "delayed_scbs queue!\n", p->host_no, channel, i, lun); + scbq_init(&p->delayed_scbs[i]); + } + if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) || + time_after_eq(p->dev_timer.expires, p->dev_expires[i]) ) + { + mod_timer(&p->dev_timer, p->dev_expires[i]); + p->dev_timer_active |= (0x01 << MAX_TARGETS); + } + } + } + + if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) + printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun ); + aic7xxx_search_qinfifo(p, target, channel, lun, tag, + SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL); + +/* + * Search the waiting_scbs queue for matches, this catches any SCB_QUEUED + * ABORT/RESET commands. + */ + if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) + printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel, + target, lun ); + { + struct aic7xxx_scb *scbp, *prev_scbp; + + j = 0; + prev_scbp = NULL; + scbp = p->waiting_scbs.head; + while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) ) + { + prev_scbp = scbp; + scbp = scbp->q_next; + if ( prev_scbp == scbp ) + { + if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) + printk(WARN_LEAD "Yikes!! scb->q_next == scb " + "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp)); + scbp = NULL; + prev_scbp->q_next = NULL; + p->waiting_scbs.tail = prev_scbp; + } + if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) + { + scbq_remove(&p->waiting_scbs, prev_scbp); + if (prev_scbp->flags & SCB_WAITINGQ) + { + p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++; + p->activescbs++; + } + prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); + prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; + } + } + if ( j > (p->scb_data->maxscbs + 1) ) + { + if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET)) + printk(WARN_LEAD "Yikes!! There's a loop in the " + "waiting_scbs queue!\n", p->host_no, channel, target, lun); + scbq_init(&p->waiting_scbs); + } + } + + + /* + * Search waiting for selection list. + */ + if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) + printk(INFO_LEAD "Cleaning waiting for selection " + "list.\n", p->host_no, channel, target, lun); + { + unsigned char next, prev, scb_index; + + next = aic_inb(p, WAITING_SCBH); /* Start at head of list. */ + prev = SCB_LIST_NULL; + j = 0; + while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) ) + { + aic_outb(p, next, SCBPTR); + scb_index = aic_inb(p, SCB_TAG); + if (scb_index >= p->scb_data->numscbs) + { + /* + * No aic7xxx_verbose check here.....we want to see this since it + * means either the kernel driver or the sequencer screwed things up + */ + printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, " + "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, + p->scb_data->numscbs); + next = aic_inb(p, SCB_NEXT); + aic7xxx_add_curscb_to_free_list(p); + } + else + { + scbp = p->scb_data->scb_array[scb_index]; + if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) + { + next = aic7xxx_abort_waiting_scb(p, scbp, next, prev); + if (scbp->flags & SCB_WAITINGQ) + { + p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; + p->activescbs++; + } + scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); + scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; + if (prev == SCB_LIST_NULL) + { + /* + * This is either the first scb on the waiting list, or we + * have already yanked the first and haven't left any behind. + * Either way, we need to turn off the selection hardware if + * it isn't already off. + */ + aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); + aic_outb(p, CLRSELTIMEO, CLRSINT1); + } + } + else + { + prev = next; + next = aic_inb(p, SCB_NEXT); + } + } + } + if ( j > (p->scb_data->maxscbs + 1) ) + { + printk(WARN_LEAD "Yikes!! There is a loop in the waiting for " + "selection list!\n", p->host_no, channel, target, lun); + init_lists = TRUE; + } + } + + /* + * Go through disconnected list and remove any entries we have queued + * for completion, zeroing their control byte too. + */ + if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) + printk(INFO_LEAD "Cleaning disconnected scbs " + "list.\n", p->host_no, channel, target, lun); + if (p->flags & AHC_PAGESCBS) + { + unsigned char next, prev, scb_index; + + next = aic_inb(p, DISCONNECTED_SCBH); + prev = SCB_LIST_NULL; + j = 0; + while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) ) + { + aic_outb(p, next, SCBPTR); + scb_index = aic_inb(p, SCB_TAG); + if (scb_index > p->scb_data->numscbs) + { + printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, " + "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, + p->scb_data->numscbs); + next = aic7xxx_rem_scb_from_disc_list(p, next, prev); + } + else + { + scbp = p->scb_data->scb_array[scb_index]; + if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) + { + next = aic7xxx_rem_scb_from_disc_list(p, next, prev); + if (scbp->flags & SCB_WAITINGQ) + { + p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; + p->activescbs++; + } + scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); + scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; + scbp->hscb->control = 0; + } + else + { + prev = next; + next = aic_inb(p, SCB_NEXT); + } + } + } + if ( j > (p->scb_data->maxscbs + 1) ) + { + printk(WARN_LEAD "Yikes!! There is a loop in the disconnected list!\n", + p->host_no, channel, target, lun); + init_lists = TRUE; + } + } + + /* + * Walk the free list making sure no entries on the free list have + * a valid SCB_TAG value or SCB_CONTROL byte. + */ + if (p->flags & AHC_PAGESCBS) + { + unsigned char next; + + j = 0; + next = aic_inb(p, FREE_SCBH); + if ( (next >= p->scb_data->maxhscbs) && (next != SCB_LIST_NULL) ) + { + printk(WARN_LEAD "Bogus FREE_SCBH!.\n", p->host_no, channel, + target, lun); + init_lists = TRUE; + next = SCB_LIST_NULL; + } + while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) ) + { + aic_outb(p, next, SCBPTR); + if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs) + { + printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel, + target, lun); + init_lists = TRUE; + next = SCB_LIST_NULL; + } + else + { + aic_outb(p, SCB_LIST_NULL, SCB_TAG); + aic_outb(p, 0, SCB_CONTROL); + next = aic_inb(p, SCB_NEXT); + } + } + if ( j > (p->scb_data->maxscbs + 1) ) + { + printk(WARN_LEAD "Yikes!! There is a loop in the free list!\n", + p->host_no, channel, target, lun); + init_lists = TRUE; + } + } + + /* + * Go through the hardware SCB array looking for commands that + * were active but not on any list. + */ + if (init_lists) + { + aic_outb(p, SCB_LIST_NULL, FREE_SCBH); + aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); + aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH); + } + for (i = p->scb_data->maxhscbs - 1; i >= 0; i--) + { + unsigned char scbid; + + aic_outb(p, i, SCBPTR); + if (init_lists) + { + aic_outb(p, SCB_LIST_NULL, SCB_TAG); + aic_outb(p, SCB_LIST_NULL, SCB_NEXT); + aic_outb(p, 0, SCB_CONTROL); + aic7xxx_add_curscb_to_free_list(p); + } + else + { + scbid = aic_inb(p, SCB_TAG); + if (scbid < p->scb_data->numscbs) + { + scbp = p->scb_data->scb_array[scbid]; + if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) + { + aic_outb(p, 0, SCB_CONTROL); + aic_outb(p, SCB_LIST_NULL, SCB_TAG); + aic7xxx_add_curscb_to_free_list(p); + } + } + } + } + + /* + * Go through the entire SCB array now and look for commands for + * for this target that are stillactive. These are other (most likely + * tagged) commands that were disconnected when the reset occurred. + * Any commands we find here we know this about, it wasn't on any queue, + * it wasn't in the qinfifo, it wasn't in the disconnected or waiting + * lists, so it really must have been a paged out SCB. In that case, + * we shouldn't need to bother with updating any counters, just mark + * the correct flags and go on. + */ + for (i = 0; i < p->scb_data->numscbs; i++) + { + scbp = p->scb_data->scb_array[i]; + if ((scbp->flags & SCB_ACTIVE) && + aic7xxx_match_scb(p, scbp, target, channel, lun, tag) && + !aic7xxx_scb_on_qoutfifo(p, scbp)) + { + if (scbp->flags & SCB_WAITINGQ) + { + scbq_remove(&p->waiting_scbs, scbp); + scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp); + p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++; + p->activescbs++; + } + scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; + scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); + } + } + + aic_outb(p, active_scb, SCBPTR); +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_clear_intstat + * + * Description: + * Clears the interrupt status. + *-F*************************************************************************/ +static void +aic7xxx_clear_intstat(struct aic7xxx_host *p) +{ + /* Clear any interrupt conditions this may have caused. */ + aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0); + aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR | + CLRPHASECHG | CLRREQINIT, CLRSINT1); + aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT | CLRPARERR, CLRINT); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_reset_current_bus + * + * Description: + * Reset the current SCSI bus. + *-F*************************************************************************/ +static void +aic7xxx_reset_current_bus(struct aic7xxx_host *p) +{ + + /* Disable reset interrupts. */ + aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1); + + /* Turn off the bus' current operations, after all, we shouldn't have any + * valid commands left to cause a RSELI and SELO once we've tossed the + * bus away with this reset, so we might as well shut down the sequencer + * until the bus is restarted as oppossed to saving the current settings + * and restoring them (which makes no sense to me). */ + + /* Turn on the bus reset. */ + aic_outb(p, aic_inb(p, SCSISEQ) | SCSIRSTO, SCSISEQ); + while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0) + mdelay(5); + + /* + * Some of the new Ultra2 chipsets need a longer delay after a chip + * reset than just the init setup creates, so we have to delay here + * before we go into a reset in order to make the chips happy. + */ + if (p->features & AHC_ULTRA2) + mdelay(250); + else + mdelay(50); + + /* Turn off the bus reset. */ + aic_outb(p, 0, SCSISEQ); + mdelay(10); + + aic7xxx_clear_intstat(p); + /* Re-enable reset interrupts. */ + aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1); + +} + +/*+F************************************************************************* + * Function: + * aic7xxx_reset_channel + * + * Description: + * Reset the channel. + *-F*************************************************************************/ +static void +aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset) +{ + unsigned long offset_min, offset_max; + unsigned char sblkctl; + int cur_channel; + + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Reset channel called, %s initiate reset.\n", + p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" ); + + + if (channel == 1) + { + p->needsdtr |= (p->needsdtr_copy & 0xFF00); + p->dtr_pending &= 0x00FF; + offset_min = 8; + offset_max = 16; + } + else + { + if (p->features & AHC_TWIN) + { + /* Channel A */ + p->needsdtr |= (p->needsdtr_copy & 0x00FF); + p->dtr_pending &= 0xFF00; + offset_min = 0; + offset_max = 8; + } + else + { + p->needppr = p->needppr_copy; + p->needsdtr = p->needsdtr_copy; + p->needwdtr = p->needwdtr_copy; + p->dtr_pending = 0x0; + offset_min = 0; + if (p->features & AHC_WIDE) + { + offset_max = 16; + } + else + { + offset_max = 8; + } + } + } + + while (offset_min < offset_max) + { + /* + * Revert to async/narrow transfers until we renegotiate. + */ + aic_outb(p, 0, TARG_SCSIRATE + offset_min); + if (p->features & AHC_ULTRA2) + { + aic_outb(p, 0, TARG_OFFSET + offset_min); + } + offset_min++; + } + + /* + * Reset the bus and unpause/restart the controller + */ + sblkctl = aic_inb(p, SBLKCTL); + if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) + cur_channel = (sblkctl & SELBUSB) >> 3; + else + cur_channel = 0; + if ( (cur_channel != channel) && (p->features & AHC_TWIN) ) + { + /* + * Case 1: Command for another bus is active + */ + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no, + channel, -1, -1); + /* + * Stealthily reset the other bus without upsetting the current bus. + */ + aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL); + aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1); + if (initiate_reset) + { + aic7xxx_reset_current_bus(p); + } + aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ); + aic7xxx_clear_intstat(p); + aic_outb(p, sblkctl, SBLKCTL); + } + else + { + /* + * Case 2: A command from this bus is active or we're idle. + */ + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no, + channel, -1, -1); + aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), + SIMODE1); + p->flags &= ~AHC_HANDLING_REQINITS; + p->msg_type = MSG_TYPE_NONE; + p->msg_len = 0; + if (initiate_reset) + { + aic7xxx_reset_current_bus(p); + } + aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ); + aic7xxx_clear_intstat(p); + } + if (aic7xxx_verbose & VERBOSE_RESET_RETURN) + printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1); + /* + * Clean up all the state information for the pending transactions + * on this bus. + */ + aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL); + + if ( !(p->features & AHC_TWIN) ) + { + restart_sequencer(p); + } + + return; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_run_waiting_queues + * + * Description: + * Scan the awaiting_scbs queue downloading and starting as many + * scbs as we can. + *-F*************************************************************************/ +static void +aic7xxx_run_waiting_queues(struct aic7xxx_host *p) +{ + struct aic7xxx_scb *scb; + int tindex; + int sent; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + + + if (p->waiting_scbs.head == NULL) + return; + + sent = 0; + + /* + * First handle SCBs that are waiting but have been assigned a slot. + */ + DRIVER_LOCK + while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL) + { + tindex = TARGET_INDEX(scb->cmd); + if ( !scb->tag_action && (p->tagenable & (1<dev_temp_queue_depth[tindex] = 1; + } + if ( (p->dev_active_cmds[tindex] >= + p->dev_temp_queue_depth[tindex]) || + (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) || + (p->flags & AHC_RESET_DELAY) ) + { + scbq_insert_tail(&p->delayed_scbs[tindex], scb); + } + else + { + scb->flags &= ~SCB_WAITINGQ; + p->dev_active_cmds[tindex]++; + p->activescbs++; + if ( !(scb->tag_action) ) + { + aic7xxx_busy_target(p, scb); + } + p->qinfifo[p->qinfifonext++] = scb->hscb->tag; + sent++; + } + } + if (sent) + { + if (p->features & AHC_QUEUE_REGS) + aic_outb(p, p->qinfifonext, HNSCB_QOFF); + else + { + pause_sequencer(p); + aic_outb(p, p->qinfifonext, KERNEL_QINPOS); + unpause_sequencer(p, FALSE); + } + if (p->activescbs > p->max_activescbs) + p->max_activescbs = p->activescbs; + } + DRIVER_UNLOCK +} + +#ifdef CONFIG_PCI + +#define DPE 0x80 +#define SSE 0x40 +#define RMA 0x20 +#define RTA 0x10 +#define STA 0x08 +#define DPR 0x01 + +/*+F************************************************************************* + * Function: + * aic7xxx_pci_intr + * + * Description: + * Check the scsi card for PCI errors and clear the interrupt + * + * NOTE: If you don't have this function and a 2940 card encounters + * a PCI error condition, the machine will end up locked as the + * interrupt handler gets slammed with non-stop PCI error interrupts + *-F*************************************************************************/ +static void +aic7xxx_pci_intr(struct aic7xxx_host *p) +{ + unsigned char status1; + + pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1); + + if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) + printk(WARN_LEAD "Data Parity Error during PCI address or PCI write" + "phase.\n", p->host_no, -1, -1, -1); + if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) + printk(WARN_LEAD "Signal System Error Detected\n", p->host_no, + -1, -1, -1); + if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) + printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no, + -1, -1, -1); + if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) + printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no, + -1, -1, -1); + if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) + printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no, + -1, -1, -1); + if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) + printk(WARN_LEAD "Data Parity Error has been reported via PCI pin " + "PERR#\n", p->host_no, -1, -1, -1); + + pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1); + if (status1 & (DPR|RMA|RTA)) + aic_outb(p, CLRPARERR, CLRINT); + + if ( (aic7xxx_panic_on_abort) && (p->spurious_int > 500) ) + aic7xxx_panic_abort(p, NULL); + +} +#endif /* CONFIG_PCI */ + +/*+F************************************************************************* + * Function: + * aic7xxx_timer + * + * Description: + * Take expired extries off of delayed queues and place on waiting queue + * then run waiting queue to start commands. + ***************************************************************************/ +static void +aic7xxx_timer(struct aic7xxx_host *p) +{ + int i, j; + unsigned long cpu_flags = 0; + struct aic7xxx_scb *scb; + + spin_lock_irqsave(&io_request_lock, cpu_flags); + p->dev_timer_active &= ~(0x01 << MAX_TARGETS); + if ( (p->dev_timer_active & (0x01 << p->scsi_id)) && + time_after_eq(jiffies, p->dev_expires[p->scsi_id]) ) + { + p->flags &= ~AHC_RESET_DELAY; + p->dev_timer_active &= ~(0x01 << p->scsi_id); + } + for(i=0; iscsi_id) && + (p->dev_timer_active & (0x01 << i)) && + time_after_eq(jiffies, p->dev_expires[i]) ) + { + p->dev_timer_active &= ~(0x01 << i); + p->dev_flags[i] &= ~(DEVICE_RESET_DELAY|DEVICE_WAS_BUSY); + p->dev_temp_queue_depth[i] = p->dev_max_queue_depth[i]; + j = 0; + while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) && + (j++ < p->scb_data->numscbs) ) + { + scbq_insert_tail(&p->waiting_scbs, scb); + } + if (j == p->scb_data->numscbs) + { + printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n", + p->host_no, 0, i, -1); + scbq_init(&p->delayed_scbs[i]); + scbq_init(&p->waiting_scbs); + /* + * Well, things are screwed now, wait for a reset to clean the junk + * out. + */ + } + } + else if ( p->dev_timer_active & (0x01 << i) ) + { + if ( p->dev_timer_active & (0x01 << MAX_TARGETS) ) + { + if ( time_after_eq(p->dev_timer.expires, p->dev_expires[i]) ) + { + p->dev_timer.expires = p->dev_expires[i]; + } + } + else + { + p->dev_timer.expires = p->dev_expires[i]; + p->dev_timer_active |= (0x01 << MAX_TARGETS); + } + } + } + if ( p->dev_timer_active & (0x01 << MAX_TARGETS) ) + { + add_timer(&p->dev_timer); + } + + aic7xxx_run_waiting_queues(p); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_construct_ppr + * + * Description: + * Build up a Parallel Protocol Request message for use with SCSI-3 + * devices. + *-F*************************************************************************/ +static void +aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + int tindex = TARGET_INDEX(scb->cmd); + + p->msg_buf[p->msg_index++] = MSG_EXTENDED; + p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN; + p->msg_buf[p->msg_index++] = MSG_EXT_PPR; + p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period; + p->msg_buf[p->msg_index++] = 0; + p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset; + p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width; + p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options; + p->msg_len += 8; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_construct_sdtr + * + * Description: + * Constucts a synchronous data transfer message in the message + * buffer on the sequencer. + *-F*************************************************************************/ +static void +aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period, + unsigned char offset) +{ + p->msg_buf[p->msg_index++] = MSG_EXTENDED; + p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN; + p->msg_buf[p->msg_index++] = MSG_EXT_SDTR; + p->msg_buf[p->msg_index++] = period; + p->msg_buf[p->msg_index++] = offset; + p->msg_len += 5; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_construct_wdtr + * + * Description: + * Constucts a wide data transfer message in the message buffer + * on the sequencer. + *-F*************************************************************************/ +static void +aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width) +{ + p->msg_buf[p->msg_index++] = MSG_EXTENDED; + p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN; + p->msg_buf[p->msg_index++] = MSG_EXT_WDTR; + p->msg_buf[p->msg_index++] = bus_width; + p->msg_len += 4; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_calc_residual + * + * Description: + * Calculate the residual data not yet transferred. + *-F*************************************************************************/ +static void +aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + struct aic7xxx_hwscb *hscb; + Scsi_Cmnd *cmd; + int actual, i; + + cmd = scb->cmd; + hscb = scb->hscb; + + /* + * Don't destroy valid residual information with + * residual coming from a check sense operation. + */ + if (((scb->hscb->control & DISCONNECTED) == 0) && + (scb->flags & SCB_SENSE) == 0) + { + /* + * We had an underflow. At this time, there's only + * one other driver that bothers to check for this, + * and cmd->underflow seems to be set rather half- + * heartedly in the higher-level SCSI code. + */ + actual = scb->sg_length; + for (i=1; i < hscb->residual_SG_segment_count; i++) + { + actual -= scb->sg_list[scb->sg_count - i].length; + } + actual -= (hscb->residual_data_count[2] << 16) | + (hscb->residual_data_count[1] << 8) | + hscb->residual_data_count[0]; + + if (actual < cmd->underflow) + { + if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) + printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG " + "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow, + (cmd->request.cmd == WRITE) ? "wrote" : "read", actual, + hscb->residual_SG_segment_count); + aic7xxx_error(cmd) = DID_RETRY_COMMAND; + aic7xxx_status(cmd) = hscb->target_status; + } + } + + /* + * Clean out the residual information in the SCB for the + * next consumer. + */ + hscb->residual_data_count[2] = 0; + hscb->residual_data_count[1] = 0; + hscb->residual_data_count[0] = 0; + hscb->residual_SG_segment_count = 0; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_handle_device_reset + * + * Description: + * Interrupt handler for sequencer interrupts (SEQINT). + *-F*************************************************************************/ +static void +aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel) +{ + unsigned short targ_mask; + unsigned char tindex = target; + + tindex |= ((channel & 0x01) << 3); + + targ_mask = (0x01 << tindex); + /* + * Go back to async/narrow transfers and renegotiate. + */ + p->needppr |= (p->needppr_copy & targ_mask); + p->needsdtr |= (p->needsdtr_copy & targ_mask); + p->needwdtr |= (p->needwdtr_copy & targ_mask); + p->dtr_pending &= ~targ_mask; + aic_outb(p, 0, TARG_SCSIRATE + tindex); + if (p->features & AHC_ULTRA2) + aic_outb(p, 0, TARG_OFFSET + tindex); + aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL); + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel, + target, -1); + aic7xxx_run_done_queue(p, /*complete*/ TRUE); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_handle_seqint + * + * Description: + * Interrupt handler for sequencer interrupts (SEQINT). + *-F*************************************************************************/ +static void +aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) +{ + struct aic7xxx_scb *scb; + unsigned short target_mask; + unsigned char target, lun, tindex; + unsigned char queue_flag = FALSE; + char channel; + + target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f); + if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) + channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; + else + channel = 0; + tindex = target + (channel << 3); + lun = aic_inb(p, SAVED_TCL) & 0x07; + target_mask = (0x01 << tindex); + + /* + * Go ahead and clear the SEQINT now, that avoids any interrupt race + * conditions later on in case we enable some other interrupt. + */ + aic_outb(p, CLRSEQINT, CLRINT); + switch (intstat & SEQINT_MASK) + { + case NO_MATCH: + { + aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), + SCSISEQ); + printk(WARN_LEAD "No active SCB for reconnecting target - Issuing " + "BUS DEVICE RESET.\n", p->host_no, channel, target, lun); + printk(WARN_LEAD " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n", + p->host_no, channel, target, lun, + aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1), + (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); + if (aic7xxx_panic_on_abort) + aic7xxx_panic_abort(p, NULL); + } + break; + + case SEND_REJECT: + { + if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) + printk(INFO_LEAD "Rejecting unknown message (0x%x) received from " + "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun, + aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS)); + } + break; + + case NO_IDENT: + { + /* + * The reconnecting target either did not send an identify + * message, or did, but we didn't find an SCB to match and + * before it could respond to our ATN/abort, it hit a dataphase. + * The only safe thing to do is to blow it away with a bus + * reset. + */ + if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID)) + printk(INFO_LEAD "Target did not send an IDENTIFY message; " + "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target, + lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL)); + + aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE); + aic7xxx_run_done_queue(p, TRUE); + + } + break; + + case BAD_PHASE: + if (aic_inb(p, LASTPHASE) == P_BUSFREE) + { + if (aic7xxx_verbose & VERBOSE_SEQINT) + printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel, + target, lun); + restart_sequencer(p); + } + else + { + if (aic7xxx_verbose & VERBOSE_SEQINT) + printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no, + channel, target, lun); + } + break; + + case EXTENDED_MSG: + { + p->msg_type = MSG_TYPE_INITIATOR_MSGIN; + p->msg_len = 0; + p->msg_index = 0; + +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose > 0xffff) + printk(INFO_LEAD "Enabling REQINITs for MSG_IN\n", p->host_no, + channel, target, lun); +#endif + + /* + * To actually receive the message, simply turn on + * REQINIT interrupts and let our interrupt handler + * do the rest (REQINIT should already be true). + */ + p->flags |= AHC_HANDLING_REQINITS; + aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1); + + /* + * We don't want the sequencer unpaused yet so we return early + */ + return; + } + + case REJECT_MSG: + { + /* + * What we care about here is if we had an outstanding SDTR + * or WDTR message for this target. If we did, this is a + * signal that the target is refusing negotiation. + */ + unsigned char scb_index; + unsigned char last_msg; + + scb_index = aic_inb(p, SCB_TAG); + scb = p->scb_data->scb_array[scb_index]; + last_msg = aic_inb(p, LAST_MSG); + + if ( (last_msg == MSG_IDENTIFYFLAG) && + (scb->tag_action) && + !(scb->flags & SCB_MSGOUT_BITS) ) + { + if (scb->tag_action == MSG_ORDERED_Q_TAG) + { + /* + * OK...the device seems able to accept tagged commands, but + * not ordered tag commands, only simple tag commands. So, we + * disable ordered tag commands and go on with life just like + * normal. + */ + p->orderedtag &= ~target_mask; + scb->tag_action = MSG_SIMPLE_Q_TAG; + scb->hscb->control &= ~SCB_TAG_TYPE; + scb->hscb->control |= MSG_SIMPLE_Q_TAG; + aic_outb(p, scb->hscb->control, SCB_CONTROL); + /* + * OK..we set the tag type to simple tag command, now we re-assert + * ATNO and hope this will take us into the identify phase again + * so we can resend the tag type and info to the device. + */ + aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); + } + else if (scb->tag_action == MSG_SIMPLE_Q_TAG) + { + unsigned char i, reset = 0; + struct aic7xxx_scb *scbp; + int old_verbose; + /* + * Hmmmm....the device is flaking out on tagged commands. The + * bad thing is that we already have tagged commands enabled in + * the device struct in the mid level code. We also have a queue + * set according to the tagged queue depth. Gonna have to live + * with it by controlling our queue depth internally and making + * sure we don't set the tagged command flag any more. + */ + p->tagenable &= ~target_mask; + p->orderedtag &= ~target_mask; + p->dev_max_queue_depth[tindex] = + p->dev_temp_queue_depth[tindex] = 1; + /* + * We set this command up as a bus device reset. However, we have + * to clear the tag type as it's causing us problems. We shouldnt + * have to worry about any other commands being active, since if + * the device is refusing tagged commands, this should be the + * first tagged command sent to the device, however, we do have + * to worry about any other tagged commands that may already be + * in the qinfifo. The easiest way to do this, is to issue a BDR, + * send all the commands back to the mid level code, then let them + * come back and get rebuilt as untagged commands. + */ + scb->tag_action = 0; + scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE); + aic_outb(p, scb->hscb->control, SCB_CONTROL); + + old_verbose = aic7xxx_verbose; + aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT); + for (i=0; i!=p->scb_data->numscbs; i++) + { + scbp = p->scb_data->scb_array[i]; + if ((scbp->flags & SCB_ACTIVE) && (scbp != scb)) + { + if (aic7xxx_match_scb(p, scbp, target, channel, lun, i)) + { + aic7xxx_reset_device(p, target, channel, lun, i); + reset++; + } + aic7xxx_run_done_queue(p, TRUE); + } + } + aic7xxx_verbose = old_verbose; + /* + * Wait until after the for loop to set the busy index since + * aic7xxx_reset_device will clear the busy index during its + * operation. + */ + aic7xxx_busy_target(p, scb); + printk(INFO_LEAD "Device is refusing tagged commands, using " + "untagged I/O.\n", p->host_no, channel, target, lun); + aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); + } + } + else if (scb->flags & SCB_MSGOUT_PPR) + { + /* + * As per the draft specs, any device capable of supporting any of + * the option values other than 0 are not allowed to reject the + * PPR message. Instead, they must negotiate out what they do + * support instead of rejecting our offering or else they cause + * a parity error during msg_out phase to signal that they don't + * like our settings. + */ + p->needppr &= ~target_mask; + p->needppr_copy &= ~target_mask; + aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, + (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE)); + aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); + p->transinfo[tindex].goal_options = 0; + p->dtr_pending &= ~target_mask; + scb->flags &= ~SCB_MSGOUT_BITS; + if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Device is rejecting PPR messages, falling " + "back.\n", p->host_no, channel, target, lun); + } + if ( p->transinfo[tindex].goal_width ) + { + p->needwdtr |= target_mask; + p->needwdtr_copy |= target_mask; + p->dtr_pending |= target_mask; + scb->flags |= SCB_MSGOUT_WDTR; + } + if ( p->transinfo[tindex].goal_offset ) + { + p->needsdtr |= target_mask; + p->needsdtr_copy |= target_mask; + if( !(p->dtr_pending & target_mask) ) + { + p->dtr_pending |= target_mask; + scb->flags |= SCB_MSGOUT_SDTR; + } + } + if ( p->dtr_pending & target_mask ) + { + aic_outb(p, HOST_MSG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); + } + } + else if (scb->flags & SCB_MSGOUT_WDTR) + { + /* + * note 8bit xfers and clear flag + */ + p->needwdtr &= ~target_mask; + p->needwdtr_copy &= ~target_mask; + p->dtr_pending &= ~target_mask; + scb->flags &= ~SCB_MSGOUT_BITS; + aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, + (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR)); + aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); + if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Device is rejecting WDTR messages, using " + "narrow transfers.\n", p->host_no, channel, target, lun); + } + p->needsdtr |= (p->needsdtr_copy & target_mask); + } + else if (scb->flags & SCB_MSGOUT_SDTR) + { + /* + * note asynch xfers and clear flag + */ + p->needsdtr &= ~target_mask; + p->needsdtr_copy &= ~target_mask; + p->dtr_pending &= ~target_mask; + scb->flags &= ~SCB_MSGOUT_SDTR; + aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, + (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL)); + if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Device is rejecting SDTR messages, using " + "async transfers.\n", p->host_no, channel, target, lun); + } + } + else if (aic7xxx_verbose & VERBOSE_SEQINT) + { + /* + * Otherwise, we ignore it. + */ + printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause. " + "Ignoring.\n", p->host_no, channel, target, lun); + } + } + break; + + case BAD_STATUS: + { + unsigned char scb_index; + struct aic7xxx_hwscb *hscb; + Scsi_Cmnd *cmd; + + /* The sequencer will notify us when a command has an error that + * would be of interest to the kernel. This allows us to leave + * the sequencer running in the common case of command completes + * without error. The sequencer will have DMA'd the SCB back + * up to us, so we can reference the drivers SCB array. + * + * Set the default return value to 0 indicating not to send + * sense. The sense code will change this if needed and this + * reduces code duplication. + */ + aic_outb(p, 0, RETURN_1); + scb_index = aic_inb(p, SCB_TAG); + if (scb_index > p->scb_data->numscbs) + { + printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n", + p->host_no, channel, target, lun, intstat, scb_index); + break; + } + scb = p->scb_data->scb_array[scb_index]; + hscb = scb->hscb; + + if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) + { + printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x," + " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat, + scb_index, scb->flags, (unsigned long) scb->cmd); + } + else + { + cmd = scb->cmd; + hscb->target_status = aic_inb(p, SCB_TARGET_STATUS); + aic7xxx_status(cmd) = hscb->target_status; + + cmd->result = hscb->target_status; + + switch (status_byte(hscb->target_status)) + { + case GOOD: + if (aic7xxx_verbose & VERBOSE_SEQINT) + printk(INFO_LEAD "Interrupted for status of GOOD???\n", + p->host_no, CTL_OF_SCB(scb)); + break; + + case COMMAND_TERMINATED: + case CHECK_CONDITION: + if ( !(scb->flags & SCB_SENSE) ) + { + /* + * Send a sense command to the requesting target. + * XXX - revisit this and get rid of the memcopys. + */ + memcpy(scb->sense_cmd, &generic_sense[0], + sizeof(generic_sense)); + + scb->sense_cmd[1] = (cmd->lun << 5); + scb->sense_cmd[4] = sizeof(cmd->sense_buffer); + + scb->sg_list[0].length = + cpu_to_le32(sizeof(cmd->sense_buffer)); + scb->sg_list[0].address = + cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer, + sizeof(cmd->sense_buffer), + PCI_DMA_FROMDEVICE)); + + /* + * XXX - We should allow disconnection, but can't as it + * might allow overlapped tagged commands. + */ + /* hscb->control &= DISCENB; */ + hscb->control = 0; + hscb->target_status = 0; + hscb->SG_list_pointer = + cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list)); + hscb->SCSI_cmd_pointer = + cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd)); + hscb->data_count = scb->sg_list[0].length; + hscb->data_pointer = scb->sg_list[0].address; + hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]); + hscb->residual_SG_segment_count = 0; + hscb->residual_data_count[0] = 0; + hscb->residual_data_count[1] = 0; + hscb->residual_data_count[2] = 0; + + scb->sg_count = hscb->SG_segment_count = 1; + scb->sg_length = sizeof(cmd->sense_buffer); + scb->tag_action = 0; + scb->flags |= SCB_SENSE; + /* + * Ensure the target is busy since this will be an + * an untagged request. + */ +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + if (scb->flags & SCB_MSGOUT_BITS) + printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no, + CTL_OF_SCB(scb), (scb->flags & SCB_MSGOUT_SDTR) ? + "SDTR" : "WDTR"); + else + printk(INFO_LEAD "Requesting SENSE, no MSG\n", p->host_no, + CTL_OF_SCB(scb)); + } +#endif + aic7xxx_busy_target(p, scb); + aic_outb(p, SEND_SENSE, RETURN_1); + aic7xxx_error(cmd) = DID_OK; + break; + } /* first time sense, no errors */ + aic7xxx_error(cmd) = DID_ERROR; + scb->flags &= ~SCB_SENSE; + break; + + case QUEUE_FULL: + queue_flag = TRUE; /* Mark that this is a QUEUE_FULL and */ + case BUSY: /* drop through to here */ + { + struct aic7xxx_scb *next_scbp, *prev_scbp; + unsigned char active_hscb, next_hscb, prev_hscb, scb_index; + /* + * We have to look three places for queued commands: + * 1: QINFIFO + * 2: p->waiting_scbs queue + * 3: WAITING_SCBS list on card (for commands that are started + * but haven't yet made it to the device) + */ + aic7xxx_search_qinfifo(p, target, channel, lun, + SCB_LIST_NULL, 0, TRUE, + &p->delayed_scbs[tindex]); + next_scbp = p->waiting_scbs.head; + while ( next_scbp != NULL ) + { + prev_scbp = next_scbp; + next_scbp = next_scbp->q_next; + if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun, + SCB_LIST_NULL) ) + { + scbq_remove(&p->waiting_scbs, prev_scbp); + scbq_insert_tail(&p->delayed_scbs[tindex], + prev_scbp); + } + } + next_scbp = NULL; + active_hscb = aic_inb(p, SCBPTR); + prev_hscb = next_hscb = scb_index = SCB_LIST_NULL; + next_hscb = aic_inb(p, WAITING_SCBH); + while (next_hscb != SCB_LIST_NULL) + { + aic_outb(p, next_hscb, SCBPTR); + scb_index = aic_inb(p, SCB_TAG); + if (scb_index < p->scb_data->numscbs) + { + next_scbp = p->scb_data->scb_array[scb_index]; + if (aic7xxx_match_scb(p, next_scbp, target, channel, lun, + SCB_LIST_NULL) ) + { + if (next_scbp->flags & SCB_WAITINGQ) + { + p->dev_active_cmds[tindex]++; + p->activescbs--; + scbq_remove(&p->delayed_scbs[tindex], next_scbp); + scbq_remove(&p->waiting_scbs, next_scbp); + } + scbq_insert_head(&p->delayed_scbs[tindex], + next_scbp); + next_scbp->flags |= SCB_WAITINGQ; + p->dev_active_cmds[tindex]--; + p->activescbs--; + next_hscb = aic_inb(p, SCB_NEXT); + aic_outb(p, 0, SCB_CONTROL); + aic_outb(p, SCB_LIST_NULL, SCB_TAG); + aic7xxx_add_curscb_to_free_list(p); + if (prev_hscb == SCB_LIST_NULL) + { + /* We were first on the list, + * so we kill the selection + * hardware. Let the sequencer + * re-init the hardware itself + */ + aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); + aic_outb(p, CLRSELTIMEO, CLRSINT1); + aic_outb(p, next_hscb, WAITING_SCBH); + } + else + { + aic_outb(p, prev_hscb, SCBPTR); + aic_outb(p, next_hscb, SCB_NEXT); + } + } + else + { + prev_hscb = next_hscb; + next_hscb = aic_inb(p, SCB_NEXT); + } + } /* scb_index >= p->scb_data->numscbs */ + } + aic_outb(p, active_hscb, SCBPTR); + if (scb->flags & SCB_WAITINGQ) + { + scbq_remove(&p->delayed_scbs[tindex], scb); + scbq_remove(&p->waiting_scbs, scb); + p->dev_active_cmds[tindex]++; + p->activescbs++; + } + scbq_insert_head(&p->delayed_scbs[tindex], scb); + p->dev_active_cmds[tindex]--; + p->activescbs--; + scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY; + + if ( !(p->dev_timer_active & (0x01 << tindex)) ) + { + p->dev_timer_active |= (0x01 << tindex); + if ( p->dev_active_cmds[tindex] ) + { + p->dev_expires[tindex] = jiffies + HZ; + } + else + { + p->dev_expires[tindex] = jiffies + (HZ / 10); + } + if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ) + { + p->dev_timer.expires = p->dev_expires[tindex]; + p->dev_timer_active |= (0x01 << MAX_TARGETS); + add_timer(&p->dev_timer); + } + else if ( time_after_eq(p->dev_timer.expires, + p->dev_expires[tindex]) ) + mod_timer(&p->dev_timer, p->dev_expires[tindex]); + } +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) || + (aic7xxx_verbose > 0xffff) ) + { + if (queue_flag) + printk(INFO_LEAD "Queue full received; queue depth %d, " + "active %d\n", p->host_no, CTL_OF_SCB(scb), + p->dev_max_queue_depth[tindex], + p->dev_active_cmds[tindex]); + else + printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb)); + + } +#endif + if (queue_flag) + { + if ( p->dev_last_queue_full[tindex] != + p->dev_active_cmds[tindex] ) + { + p->dev_last_queue_full[tindex] = + p->dev_active_cmds[tindex]; + p->dev_last_queue_full_count[tindex] = 0; + } + else + { + p->dev_last_queue_full_count[tindex]++; + } + if ( (p->dev_last_queue_full_count[tindex] > 14) && + (p->dev_active_cmds[tindex] > 4) ) + { + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no, + CTL_OF_SCB(scb), p->dev_active_cmds[tindex]); + p->dev_max_queue_depth[tindex] = + p->dev_active_cmds[tindex]; + p->dev_last_queue_full[tindex] = 0; + p->dev_last_queue_full_count[tindex] = 0; + p->dev_temp_queue_depth[tindex] = + p->dev_active_cmds[tindex]; + } + else if (p->dev_active_cmds[tindex] == 0) + { + if (aic7xxx_verbose & VERBOSE_NEGOTIATION) + { + printk(INFO_LEAD "QUEUE_FULL status received with 0 " + "commands active.\n", p->host_no, CTL_OF_SCB(scb)); + printk(INFO_LEAD "Tagged Command Queueing disabled\n", + p->host_no, CTL_OF_SCB(scb)); + } + p->dev_max_queue_depth[tindex] = 1; + p->dev_temp_queue_depth[tindex] = 1; + scb->tag_action = 0; + scb->hscb->control &= ~(MSG_ORDERED_Q_TAG|MSG_SIMPLE_Q_TAG); + } + else + { + p->dev_flags[tindex] |= DEVICE_WAS_BUSY; + p->dev_temp_queue_depth[tindex] = + p->dev_active_cmds[tindex]; + } + } + break; + } + + default: + if (aic7xxx_verbose & VERBOSE_SEQINT) + printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no, + CTL_OF_SCB(scb), scb->hscb->target_status); + if (!aic7xxx_error(cmd)) + { + aic7xxx_error(cmd) = DID_RETRY_COMMAND; + } + break; + } /* end switch */ + } /* end else of */ + } + break; + + case AWAITING_MSG: + { + unsigned char scb_index, msg_out; + + scb_index = aic_inb(p, SCB_TAG); + msg_out = aic_inb(p, MSG_OUT); + scb = p->scb_data->scb_array[scb_index]; + p->msg_index = p->msg_len = 0; + /* + * This SCB had a MK_MESSAGE set in its control byte informing + * the sequencer that we wanted to send a special message to + * this target. + */ + + if ( !(scb->flags & SCB_DEVICE_RESET) && + (msg_out == MSG_IDENTIFYFLAG) && + (scb->hscb->control & TAG_ENB) ) + { + p->msg_buf[p->msg_index++] = scb->tag_action; + p->msg_buf[p->msg_index++] = scb->hscb->tag; + p->msg_len += 2; + } + + if (scb->flags & SCB_DEVICE_RESET) + { + p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET; + p->msg_len++; + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Bus device reset mailed.\n", + p->host_no, CTL_OF_SCB(scb)); + } + else if (scb->flags & SCB_ABORT) + { + if (scb->tag_action) + { + p->msg_buf[p->msg_index++] = MSG_ABORT_TAG; + } + else + { + p->msg_buf[p->msg_index++] = MSG_ABORT; + } + p->msg_len++; + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "Abort message mailed.\n", p->host_no, + CTL_OF_SCB(scb)); + } + else if (scb->flags & SCB_MSGOUT_PPR) + { + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n", + p->host_no, CTL_OF_SCB(scb), + p->transinfo[tindex].goal_period, + p->transinfo[tindex].goal_offset, + p->transinfo[tindex].goal_width, + p->transinfo[tindex].goal_options); + } + aic7xxx_construct_ppr(p, scb); + } + else if (scb->flags & SCB_MSGOUT_WDTR) + { + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Sending WDTR message.\n", p->host_no, + CTL_OF_SCB(scb)); + } + aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width); + } + else if (scb->flags & SCB_MSGOUT_SDTR) + { + unsigned int max_sync, period; + unsigned char options = 0; + /* + * Now that the device is selected, use the bits in SBLKCTL and + * SSTAT2 to determine the max sync rate for this device. + */ + if (p->features & AHC_ULTRA2) + { + if ( (aic_inb(p, SBLKCTL) & ENAB40) && + !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) + { + max_sync = AHC_SYNCRATE_ULTRA2; + } + else + { + max_sync = AHC_SYNCRATE_ULTRA; + } + } + else if (p->features & AHC_ULTRA) + { + max_sync = AHC_SYNCRATE_ULTRA; + } + else + { + max_sync = AHC_SYNCRATE_FAST; + } + period = p->transinfo[tindex].goal_period; + aic7xxx_find_syncrate(p, &period, max_sync, &options); + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no, + CTL_OF_SCB(scb), period, + p->transinfo[tindex].goal_offset); + } + aic7xxx_construct_sdtr(p, period, + p->transinfo[tindex].goal_offset); + } + else + { + sti(); + panic("aic7xxx: AWAITING_MSG for an SCB that does " + "not have a waiting message.\n"); + } + /* + * We've set everything up to send our message, now to actually do + * so we need to enable reqinit interrupts and let the interrupt + * handler do the rest. We don't want to unpause the sequencer yet + * though so we'll return early. We also have to make sure that + * we clear the SEQINT *BEFORE* we set the REQINIT handler active + * or else it's possible on VLB cards to loose the first REQINIT + * interrupt. Edge triggered EISA cards could also loose this + * interrupt, although PCI and level triggered cards should not + * have this problem since they continually interrupt the kernel + * until we take care of the situation. + */ + scb->flags |= SCB_MSGOUT_SENT; + p->msg_index = 0; + p->msg_type = MSG_TYPE_INITIATOR_MSGOUT; + p->flags |= AHC_HANDLING_REQINITS; + aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1); + return; + } + break; + + case DATA_OVERRUN: + { + unsigned char scb_index = aic_inb(p, SCB_TAG); + unsigned char lastphase = aic_inb(p, LASTPHASE); + unsigned int i; + + scb = (p->scb_data->scb_array[scb_index]); + /* + * XXX - What do we really want to do on an overrun? The + * mid-level SCSI code should handle this, but for now, + * we'll just indicate that the command should retried. + * If we retrieved sense info on this target, then the + * base SENSE info should have been saved prior to the + * overrun error. In that case, we return DID_OK and let + * the mid level code pick up on the sense info. Otherwise + * we return DID_ERROR so the command will get retried. + */ + if ( !(scb->flags & SCB_SENSE) ) + { + printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n", + p->host_no, CTL_OF_SCB(scb), + (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag); + printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n", + (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't", + scb->sg_length, scb->sg_count); + for (i = 0; i < scb->sg_count; i++) + { + printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", + i, + le32_to_cpu(scb->sg_list[i].address), + le32_to_cpu(scb->sg_list[i].length) ); + } + aic7xxx_error(scb->cmd) = DID_ERROR; + } + else + printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n", + p->host_no, CTL_OF_SCB(scb)); + } + break; + + case WIDE_RESIDUE: + { + unsigned char resid_sgcnt, index; + unsigned char scb_index = aic_inb(p, SCB_TAG); + unsigned int cur_addr, resid_dcnt; + unsigned int native_addr, native_length; + int i; + + if(scb_index > p->scb_data->numscbs) + { + printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n", + p->host_no, -1, -1, -1); + /* + * XXX: Add error handling here + */ + break; + } + scb = p->scb_data->scb_array[scb_index]; + if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) + { + printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x " + "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb), + scb->flags, (unsigned long)scb->cmd); + break; + } + + /* + * We have a valid scb to use on this WIDE_RESIDUE message, so + * we need to walk the sg list looking for this particular sg + * segment, then see if we happen to be at the very beginning of + * the segment. If we are, then we have to back things up to + * the previous segment. If not, then we simply need to remove + * one byte from this segments address and add one to the byte + * count. + */ + cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) | + (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24); + resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT); + resid_dcnt = aic_inb(p, SCB_RESID_DCNT) | + (aic_inb(p, SCB_RESID_DCNT + 1) << 8) | + (aic_inb(p, SCB_RESID_DCNT + 2) << 16); + index = scb->sg_count - (resid_sgcnt + 1); + native_addr = le32_to_cpu(scb->sg_list[index].address); + native_length = le32_to_cpu(scb->sg_list[index].length); + /* + * Make sure this is a valid sg_seg for the given pointer + */ + if(cur_addr < native_addr || + cur_addr > (native_addr + native_length + 1)) + { + printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n", + p->host_no, CTL_OF_SCB(scb), cur_addr); + if(index > 0) + printk(WARN_LEAD " sg_address[-1]:0x%x sg_length[-1]:%d\n", + p->host_no, CTL_OF_SCB(scb), + le32_to_cpu(scb->sg_list[index - 1].address), + le32_to_cpu(scb->sg_list[index - 1].length)); + printk(WARN_LEAD " sg_address:0x%x sg_length:%d\n", + p->host_no, CTL_OF_SCB(scb), + native_addr, native_length); + if(resid_sgcnt > 1) + printk(WARN_LEAD " sg_address[1]:0x%x sg_length[1]:%d\n", + p->host_no, CTL_OF_SCB(scb), + le32_to_cpu(scb->sg_list[index + 1].address), + le32_to_cpu(scb->sg_list[index + 1].length)); + printk(WARN_LEAD " cur_address:0x%x resid_dcnt:0x%06x\n", + p->host_no, CTL_OF_SCB(scb), + cur_addr, resid_dcnt); + break; + } + + if( (resid_sgcnt == 0) && + ((resid_dcnt == 0) || (resid_dcnt == 0xffffff))) + { + /* + * We are at the end of the transfer and this is about a byte + * we ignored already (because the sequencer knew this was + * the last segment and set the adapter to ignore any wide + * residue bytes that might come through, which is only done + * on the last scatter gather segment of transfers). + */ + break; + } + else if(cur_addr == native_addr) + { + /* + * If our current address matches the sg_seg->address then we + * have to back up the sg array to the previous segment and set + * it up to have only one byte of transfer left to go. + */ + if(index == 0) + { + printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been " + "transferred.\n", p->host_no, CTL_OF_SCB(scb)); + break; + } + resid_sgcnt++; + index--; + cur_addr = le32_to_cpu(scb->sg_list[index].address) + + le32_to_cpu(scb->sg_list[index].length) - 1; + native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8) + | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24); + native_addr -= SG_SIZEOF; + aic_outb(p, resid_sgcnt, SG_COUNT); + aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); + aic_outb(p, native_addr & 0xff, SG_NEXT); + aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1); + aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2); + aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3); + aic_outb(p, 1, SCB_RESID_DCNT); + aic_outb(p, 0, SCB_RESID_DCNT + 1); + aic_outb(p, 0, SCB_RESID_DCNT + 2); + aic_outb(p, 1, HCNT); + aic_outb(p, 0, HCNT + 1); + aic_outb(p, 0, HCNT + 2); + aic_outb(p, cur_addr & 0xff, HADDR); + aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); + aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); + aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + } + else + { + /* + * Back the data pointer up by one and add one to the remaining + * byte count. Then store that in the HCNT and HADDR registers. + */ + cur_addr--; + resid_dcnt++; + aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); + aic_outb(p, resid_dcnt & 0xff, HCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); + aic_outb(p, cur_addr & 0xff, HADDR); + aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); + aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); + aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); + } + /* + * The sequencer actually wants to find the new address and byte + * count in the SHCNT and SHADDR register sets. These registers + * are a shadow of the regular HCNT and HADDR registers. On the + * Ultra2 controllers, these registers are read only and the way + * we have to set their values is to put the values we want into + * the HCNT and HADDR registers and then output PRELOADEN into + * the DFCNTRL register which causes the card to latch the current + * values in the HADDR and HCNT registers and drop it through to + * the shadow registers. On older cards we copy them directly + * across by hand. + */ + if(p->features & AHC_ULTRA2) + { + aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); + i=0; + udelay(1); + while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000)) + { + udelay(1); + } + aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL); + i=0; + udelay(1); + while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000)) + { + udelay(1); + } + } + else + { + aic_outb(p, resid_dcnt & 0xff, STCNT); + aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); + aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); + aic_outb(p, cur_addr & 0xff, SHADDR); + aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); + aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); + aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3); + } + } + break; + + +#if AIC7XXX_NOT_YET + case TRACEPOINT: + { + printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, + channel, target, lun); + } + break; + + case TRACEPOINT2: + { + printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, + channel, target, lun); + } + break; + + /* XXX Fill these in later */ + case MSG_BUFFER_BUSY: + printk("aic7xxx: Message buffer busy.\n"); + break; + case MSGIN_PHASEMIS: + printk("aic7xxx: Message-in phasemis.\n"); + break; +#endif + + default: /* unknown */ + printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n", + p->host_no, channel, target, lun, intstat, + aic_inb(p, SCSISIGI)); + break; + } + + /* + * Clear the sequencer interrupt and unpause the sequencer. + */ + unpause_sequencer(p, /* unpause always */ TRUE); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_parse_msg + * + * Description: + * Parses incoming messages into actions on behalf of + * aic7xxx_handle_reqinit + *_F*************************************************************************/ +static int +aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + int reject, reply, done; + unsigned char target_scsirate, tindex; + unsigned short target_mask; + unsigned char target, channel, lun; + + target = scb->cmd->target; + channel = scb->cmd->channel; + lun = scb->cmd->lun; + reply = reject = done = FALSE; + tindex = TARGET_INDEX(scb->cmd); + target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex); + target_mask = (0x01 << tindex); + + /* + * Parse as much of the message as is availible, + * rejecting it if we don't support it. When + * the entire message is availible and has been + * handled, return TRUE indicating that we have + * parsed an entire message. + */ + + if (p->msg_buf[0] != MSG_EXTENDED) + { + reject = TRUE; + } + + /* + * Just accept the length byte outright and perform + * more checking once we know the message type. + */ + + if ( !reject && (p->msg_len > 2) ) + { + switch(p->msg_buf[2]) + { + case MSG_EXT_SDTR: + { + unsigned int period, offset; + unsigned char maxsync, saved_offset, options; + struct aic7xxx_syncrate *syncrate; + + if (p->msg_buf[1] != MSG_EXT_SDTR_LEN) + { + reject = TRUE; + break; + } + + if (p->msg_len < (MSG_EXT_SDTR_LEN + 2)) + { + break; + } + + period = p->msg_buf[3]; + saved_offset = offset = p->msg_buf[4]; + options = 0; + + /* + * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when + * using the SDTR messages. We need the PPR messages to enable the + * higher speeds that include things like Dual Edge clocking. + */ + if (p->features & AHC_ULTRA2) + { + if ( (aic_inb(p, SBLKCTL) & ENAB40) && + !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) + { + maxsync = AHC_SYNCRATE_ULTRA2; + } + else + { + maxsync = AHC_SYNCRATE_ULTRA; + } + } + else if (p->features & AHC_ULTRA) + { + maxsync = AHC_SYNCRATE_ULTRA; + } + else + { + maxsync = AHC_SYNCRATE_FAST; + } + /* + * We might have a device that is starting negotiation with us + * before we can start up negotiation with it....be prepared to + * have a device ask for a higher speed then we want to give it + * in that case + */ + if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != + (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) + { + if (!(p->dev_flags[tindex] & DEVICE_SCANNED) && + !(p->needsdtr_copy & target_mask) && + (p->transinfo[tindex].user_offset) ) + { + /* + * Not only is the device starting this up, but it also hasn't + * been scanned yet, so this would likely be our TUR or our + * INQUIRY command at scan time, so we need to use the + * settings from the SEEPROM if they existed. Of course, even + * if we didn't find a SEEPROM, we stuffed default values into + * the user settings anyway, so use those in all cases. + */ + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + if(p->features & AHC_ULTRA2) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + } + else if (p->transinfo[tindex].cur_width) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + } + else + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + } + p->needsdtr_copy |= target_mask; + } + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Received pre-emptive SDTR message from " + "target.\n", p->host_no, CTL_OF_SCB(scb)); + } + if ( !p->transinfo[tindex].goal_offset ) + period = 255; + if ( p->transinfo[tindex].goal_period > period ) + period = p->transinfo[tindex].goal_period; + } + + syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options); + aic7xxx_validate_offset(p, syncrate, &offset, + target_scsirate & WIDEXFER); + aic7xxx_set_syncrate(p, syncrate, target, channel, period, + offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + + /* + * Did we drop to async? Or are we sending a reply? If we are, + * then we have to make sure that the reply value reflects the proper + * settings so we need to set the goal values according to what + * we need to send. + */ + if ( (offset != saved_offset) || + ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != + (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) ) + { + aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset, + options, AHC_TRANS_GOAL|AHC_TRANS_QUITE); + } + + /* + * Did we start this, if not, or if we went to low and had to + * go async, then send an SDTR back to the target + */ + p->needsdtr &= ~target_mask; + p->dtr_pending &= ~target_mask; + if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != + (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) || + (offset != saved_offset) ) + { + reply = TRUE; + p->dtr_pending |= target_mask; + scb->flags &= ~SCB_MSGOUT_BITS; + scb->flags |= SCB_MSGOUT_SDTR; + aic_outb(p, HOST_MSG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); + } + done = TRUE; + break; + } + case MSG_EXT_WDTR: + { + unsigned char bus_width; + + if (p->msg_buf[1] != MSG_EXT_WDTR_LEN) + { + reject = TRUE; + break; + } + + if (p->msg_len < (MSG_EXT_WDTR_LEN + 2)) + { + break; + } + + bus_width = p->msg_buf[3]; + if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) == + (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) ) + { + switch(bus_width) + { + default: + { + reject = TRUE; + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || + (aic7xxx_verbose > 0xffff)) ) + { + printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", + p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); + } + } /* We fall through on purpose */ + case MSG_EXT_WDTR_BUS_8_BIT: + { + bus_width = MSG_EXT_WDTR_BUS_8_BIT; + p->needwdtr_copy &= ~target_mask; + break; + } + case MSG_EXT_WDTR_BUS_16_BIT: + { + break; + } + } + p->dtr_pending &= ~target_mask; + p->needwdtr &= ~target_mask; + } + else + { + if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) ) + { + /* + * Well, we now know the WDTR and SYNC caps of this device since + * it contacted us first, mark it as such and copy the user stuff + * over to the goal stuff. + */ + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + if(p->transinfo[tindex].user_offset) + { + if(p->features & AHC_ULTRA2) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + } + else if( p->transinfo[tindex].user_width && + (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && + p->features & AHC_WIDE ) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + } + else + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + } + } + p->transinfo[tindex].goal_width = + p->transinfo[tindex].user_width; + p->needwdtr_copy |= target_mask; + p->needsdtr_copy |= target_mask; + } + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Received pre-emptive WDTR message from " + "target.\n", p->host_no, CTL_OF_SCB(scb)); + } + switch(bus_width) + { + default: + { + if ( (p->features & AHC_WIDE) && + (p->transinfo[tindex].goal_width == + MSG_EXT_WDTR_BUS_16_BIT) ) + { + bus_width = MSG_EXT_WDTR_BUS_16_BIT; + break; + } + } /* Fall through if we aren't a wide card */ + case MSG_EXT_WDTR_BUS_8_BIT: + { + p->needwdtr_copy &= ~target_mask; + bus_width = MSG_EXT_WDTR_BUS_8_BIT; + aic7xxx_set_width(p, target, channel, lun, bus_width, + AHC_TRANS_GOAL|AHC_TRANS_QUITE); + break; + } + } + reply = TRUE; + scb->flags &= ~SCB_MSGOUT_BITS; + scb->flags |= SCB_MSGOUT_WDTR; + p->needwdtr &= ~target_mask; + p->dtr_pending |= target_mask; + aic_outb(p, HOST_MSG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); + } + aic7xxx_set_width(p, target, channel, lun, bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + + /* + * By virtue of the SCSI spec, a WDTR message negates any existing + * SDTR negotiations. So, even if needsdtr isn't marked for this + * device, we still have to do a new SDTR message if the device + * supports SDTR at all. Therefore, we check needsdtr_copy instead + * of needstr. + */ + aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); + p->needsdtr |= (p->needsdtr_copy & target_mask); + done = TRUE; + break; + } + case MSG_EXT_PPR: + { + unsigned char bus_width, trans_options, new_trans_options; + unsigned int period, offset; + unsigned char maxsync, saved_offset; + struct aic7xxx_syncrate *syncrate; + + if (p->msg_buf[1] != MSG_EXT_PPR_LEN) + { + reject = TRUE; + break; + } + + if (p->msg_len < (MSG_EXT_PPR_LEN + 2)) + { + break; + } + + period = p->msg_buf[3]; + offset = saved_offset = p->msg_buf[5]; + bus_width = p->msg_buf[6]; + trans_options = new_trans_options = p->msg_buf[7] & 0xf; + + if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n", + p->host_no, CTL_OF_SCB(scb), period, offset, bus_width, + trans_options); + } + + if ( (aic_inb(p, SBLKCTL) & ENAB40) && + !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) + { + if(p->features & AHC_ULTRA3) + { + maxsync = AHC_SYNCRATE_ULTRA3; + } + else + { + maxsync = AHC_SYNCRATE_ULTRA2; + } + } + else + { + maxsync = AHC_SYNCRATE_ULTRA; + } + /* + * We might have a device that is starting negotiation with us + * before we can start up negotiation with it....be prepared to + * have a device ask for a higher speed then we want to give it + * in that case + */ + if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) != + (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) ) + { + reply = TRUE; + scb->flags &= ~SCB_MSGOUT_BITS; + scb->flags |= SCB_MSGOUT_PPR; + p->dev_flags[tindex] |= DEVICE_SCSI_3; + if (!(p->dev_flags[tindex] & DEVICE_SCANNED)) + { + /* + * Not only is the device starting this up, but it also hasn't + * been scanned yet, so this would likely be our TUR or our + * INQUIRY command at scan time, so we need to use the + * settings from the SEEPROM if they existed. Of course, even + * if we didn't find a SEEPROM, we stuffed default values into + * the user settings anyway, so use those in all cases. + */ + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + if(p->transinfo[tindex].user_offset) + { + if(p->features & AHC_ULTRA2) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2; + } + else if( p->transinfo[tindex].user_width && + (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && + p->features & AHC_WIDE ) + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT; + } + else + { + p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT; + } + } + p->transinfo[tindex].goal_width = + p->transinfo[tindex].user_width; + p->transinfo[tindex].goal_options = + p->transinfo[tindex].user_options; + } + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Received pre-emptive PPR message from " + "target.\n", p->host_no, CTL_OF_SCB(scb)); + } + if ( !p->transinfo[tindex].goal_offset ) + period = 255; + if ( p->transinfo[tindex].goal_period > period ) + period = p->transinfo[tindex].goal_period; + if ( p->transinfo[tindex].goal_options == 0 ) + new_trans_options = 0; + switch(bus_width) + { + default: + { + if ( (p->features & AHC_WIDE) && + (p->transinfo[tindex].goal_width == + MSG_EXT_WDTR_BUS_16_BIT) ) + { + bus_width = MSG_EXT_WDTR_BUS_16_BIT; + break; + } + } /* Fall through if we aren't a wide card */ + case MSG_EXT_WDTR_BUS_8_BIT: + { + p->needwdtr_copy &= ~target_mask; + bus_width = MSG_EXT_WDTR_BUS_8_BIT; + aic7xxx_set_width(p, target, channel, lun, bus_width, + AHC_TRANS_GOAL|AHC_TRANS_QUITE); + break; + } + } + if ( (p->transinfo[tindex].goal_period > 9) || + (p->transinfo[tindex].goal_options == 0) ) + { + scb->flags &= ~SCB_MSGOUT_BITS; + reject = TRUE; + reply = FALSE; + p->needppr &= ~(1 << tindex); + p->needppr_copy &= ~(1 << tindex); + if ( p->transinfo[tindex].goal_offset ) + { + p->needsdtr |= (1 << tindex); + p->needsdtr_copy |= (1 << tindex); + } + if ( p->transinfo[tindex].goal_width ) + { + p->needwdtr |= (1 << tindex); + p->needwdtr_copy |= (1 << tindex); + } + } + } + else + { + switch(bus_width) + { + default: + { + reject = TRUE; + if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && + ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) || + (aic7xxx_verbose > 0xffff)) ) + { + printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", + p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); + } + } /* We fall through on purpose */ + case MSG_EXT_WDTR_BUS_8_BIT: + { + /* + * According to the spec, if we aren't wide, we also can't be + * Dual Edge so clear the options byte + */ + new_trans_options = 0; + bus_width = MSG_EXT_WDTR_BUS_8_BIT; + break; + } + case MSG_EXT_WDTR_BUS_16_BIT: + { + break; + } + } + } + + if ( !reject ) + { + aic7xxx_set_width(p, target, channel, lun, bus_width, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + syncrate = aic7xxx_find_syncrate(p, &period, maxsync, + &new_trans_options); + aic7xxx_validate_offset(p, syncrate, &offset, bus_width); + aic7xxx_set_syncrate(p, syncrate, target, channel, period, + offset, new_trans_options, + AHC_TRANS_ACTIVE|AHC_TRANS_CUR); + } + + p->dtr_pending &= ~target_mask; + p->needppr &= ~target_mask; + if(reply) + { + p->dtr_pending |= target_mask; + scb->flags &= ~SCB_MSGOUT_BITS; + scb->flags |= SCB_MSGOUT_PPR; + aic_outb(p, HOST_MSG, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); + } + done = TRUE; + break; + } + default: + { + reject = TRUE; + break; + } + } /* end of switch(p->msg_type) */ + } /* end of if (!reject && (p->msg_len > 2)) */ + + if (!reply && reject) + { + aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); + done = TRUE; + } + return(done); +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_handle_reqinit + * + * Description: + * Interrupt handler for REQINIT interrupts (used to transfer messages to + * and from devices). + *_F*************************************************************************/ +static void +aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + unsigned char lastbyte; + unsigned char phasemis; + int done = FALSE; + + switch(p->msg_type) + { + case MSG_TYPE_INITIATOR_MSGOUT: + { + if (p->msg_len == 0) + panic("aic7xxx: REQINIT with no active message!\n"); + + lastbyte = (p->msg_index == (p->msg_len - 1)); + phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT; + + if (lastbyte || phasemis) + { + /* Time to end the message */ + p->msg_len = 0; + p->msg_type = MSG_TYPE_NONE; + /* + * NOTE-TO-MYSELF: If you clear the REQINIT after you + * disable REQINITs, then cases of REJECT_MSG stop working + * and hang the bus + */ + aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); + aic_outb(p, CLRSCSIINT, CLRINT); + p->flags &= ~AHC_HANDLING_REQINITS; + + if (phasemis == 0) + { + aic_outb(p, p->msg_buf[p->msg_index], SINDEX); + aic_outb(p, 0, RETURN_1); +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose > 0xffff) + printk(INFO_LEAD "Completed sending of REQINIT message.\n", + p->host_no, CTL_OF_SCB(scb)); +#endif + } + else + { + aic_outb(p, MSGOUT_PHASEMIS, RETURN_1); +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose > 0xffff) + printk(INFO_LEAD "PHASEMIS while sending REQINIT message.\n", + p->host_no, CTL_OF_SCB(scb)); +#endif + } + unpause_sequencer(p, TRUE); + } + else + { + /* + * Present the byte on the bus (clearing REQINIT) but don't + * unpause the sequencer. + */ + aic_outb(p, CLRREQINIT, CLRSINT1); + aic_outb(p, CLRSCSIINT, CLRINT); + aic_outb(p, p->msg_buf[p->msg_index++], SCSIDATL); + } + break; + } + case MSG_TYPE_INITIATOR_MSGIN: + { + phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN; + + if (phasemis == 0) + { + p->msg_len++; + /* Pull the byte in without acking it */ + p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL); + done = aic7xxx_parse_msg(p, scb); + /* Ack the byte */ + aic_outb(p, CLRREQINIT, CLRSINT1); + aic_outb(p, CLRSCSIINT, CLRINT); + aic_inb(p, SCSIDATL); + p->msg_index++; + } + if (phasemis || done) + { +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose > 0xffff) + { + if (phasemis) + printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.\n", + p->host_no, CTL_OF_SCB(scb)); + else + printk(INFO_LEAD "Completed receipt of REQINIT message.\n", + p->host_no, CTL_OF_SCB(scb)); + } +#endif + /* Time to end our message session */ + p->msg_len = 0; + p->msg_type = MSG_TYPE_NONE; + aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); + aic_outb(p, CLRSCSIINT, CLRINT); + p->flags &= ~AHC_HANDLING_REQINITS; + unpause_sequencer(p, TRUE); + } + break; + } + default: + { + panic("aic7xxx: Unknown REQINIT message type.\n"); + break; + } + } /* End of switch(p->msg_type) */ +} + +/*+F************************************************************************* + * Function: + * aic7xxx_handle_scsiint + * + * Description: + * Interrupt handler for SCSI interrupts (SCSIINT). + *-F*************************************************************************/ +static void +aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat) +{ + unsigned char scb_index; + unsigned char status; + struct aic7xxx_scb *scb; + + scb_index = aic_inb(p, SCB_TAG); + status = aic_inb(p, SSTAT1); + + if (scb_index < p->scb_data->numscbs) + { + scb = p->scb_data->scb_array[scb_index]; + if ((scb->flags & SCB_ACTIVE) == 0) + { + scb = NULL; + } + } + else + { + scb = NULL; + } + + + if ((status & SCSIRSTI) != 0) + { + int channel; + + if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) + channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; + else + channel = 0; + + if (aic7xxx_verbose & VERBOSE_RESET) + printk(WARN_LEAD "Someone else reset the channel!!\n", + p->host_no, channel, -1, -1); + if (aic7xxx_panic_on_abort) + aic7xxx_panic_abort(p, NULL); + /* + * Go through and abort all commands for the channel, but do not + * reset the channel again. + */ + aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE); + aic7xxx_run_done_queue(p, TRUE); + scb = NULL; + } + else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) ) + { + /* + * First look at what phase we were last in. If it's message-out, + * chances are pretty good that the bus free was in response to + * one of our abort requests. + */ + unsigned char lastphase = aic_inb(p, LASTPHASE); + unsigned char saved_tcl = aic_inb(p, SAVED_TCL); + unsigned char target = (saved_tcl >> 4) & 0x0F; + int channel; + int printerror = TRUE; + + if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) + channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; + else + channel = 0; + + aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), + SCSISEQ); + if (lastphase == P_MESGOUT) + { + unsigned char message; + + message = aic_inb(p, SINDEX); + + if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG)) + { + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no, + CTL_OF_SCB(scb), scb->hscb->tag); + aic7xxx_reset_device(p, target, channel, ALL_LUNS, + (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag ); + aic7xxx_run_done_queue(p, TRUE); + scb = NULL; + printerror = 0; + } + else if (message == MSG_BUS_DEV_RESET) + { + aic7xxx_handle_device_reset(p, target, channel); + scb = NULL; + printerror = 0; + } + } + if ( (scb != NULL) && + (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) ) + { + /* + * This might be a SCSI-3 device that is dropping the bus due to + * errors and signalling that we should reduce the transfer speed. + * All we have to do is complete this command (since it's a negotiation + * command already) and the checksum routine should flag an error and + * reduce the speed setting and renegotiate. We call the reset routing + * just to clean out the hardware from this scb. + */ + printerror = 0; + aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag); + aic7xxx_run_done_queue(p, TRUE); + scb = NULL; + } + if (printerror != 0) + { + if (scb != NULL) + { + unsigned char tag; + + if ((scb->hscb->control & TAG_ENB) != 0) + { + tag = scb->hscb->tag; + } + else + { + tag = SCB_LIST_NULL; + } + aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag); + aic7xxx_run_done_queue(p, TRUE); + } + else + { + aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL); + aic7xxx_run_done_queue(p, TRUE); + } + printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, " + "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase, + (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); + scb = NULL; + } + aic_outb(p, MSG_NOOP, MSG_OUT); + aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), + SIMODE1); + p->flags &= ~AHC_HANDLING_REQINITS; + aic_outb(p, CLRBUSFREE, CLRSINT1); + aic_outb(p, CLRSCSIINT, CLRINT); + restart_sequencer(p); + unpause_sequencer(p, TRUE); + } + else if ((status & SELTO) != 0) + { + unsigned char scbptr; + unsigned char nextscb; + Scsi_Cmnd *cmd; + + scbptr = aic_inb(p, WAITING_SCBH); + if (scbptr > p->scb_data->maxhscbs) + { + /* + * I'm still trying to track down exactly how this happens, but until + * I find it, this code will make sure we aren't passing bogus values + * into the SCBPTR register, even if that register will just wrap + * things around, we still don't like having out of range variables. + * + * NOTE: Don't check the aic7xxx_verbose variable, I want this message + * to always be displayed. + */ + printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.\n", + p->host_no, -1, -1, -1, scbptr); + if (p->scb_data->maxhscbs > 4) + scbptr &= (p->scb_data->maxhscbs - 1); + else + scbptr &= 0x03; + } + aic_outb(p, scbptr, SCBPTR); + scb_index = aic_inb(p, SCB_TAG); + + scb = NULL; + if (scb_index < p->scb_data->numscbs) + { + scb = p->scb_data->scb_array[scb_index]; + if ((scb->flags & SCB_ACTIVE) == 0) + { + scb = NULL; + } + } + if (scb == NULL) + { + printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n", + p->host_no, -1, -1, -1, scb_index); + printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x " + "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + if (aic7xxx_panic_on_abort) + aic7xxx_panic_abort(p, NULL); + } + else + { + cmd = scb->cmd; + cmd->result = (DID_TIME_OUT << 16); + + /* + * Clear out this hardware SCB + */ + aic_outb(p, 0, SCB_CONTROL); + + /* + * Clear out a few values in the card that are in an undetermined + * state. + */ + aic_outb(p, MSG_NOOP, MSG_OUT); + + /* + * Shift the waiting for selection queue forward + */ + nextscb = aic_inb(p, SCB_NEXT); + aic_outb(p, nextscb, WAITING_SCBH); + + /* + * Put this SCB back on the free list. + */ + aic7xxx_add_curscb_to_free_list(p); +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose > 0xffff) + printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb)); +#endif + if (scb->flags & SCB_QUEUED_ABORT) + { + /* + * We know that this particular SCB had to be the queued abort since + * the disconnected SCB would have gotten a reconnect instead. + * What we need to do then is to let the command timeout again so + * we get a reset since this abort just failed. + */ + cmd->result = 0; + scb = NULL; + } + else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) + { + /* + * Turn off the needsdtr, needwdtr, and needppr bits since this device + * doesn't seem to exist. + */ + p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd)); + p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); + p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); + p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); + p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd)); + p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd)); + } + } + /* + * Keep the sequencer from trying to restart any selections + */ + aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); + /* + * Make sure the data bits on the bus are released + * Don't do this on 7770 chipsets, it makes them give us + * a BRKADDRINT and kills the card. + */ + if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) + aic_outb(p, 0, SCSIBUSL); + + /* + * Delay for the selection timeout delay period then stop the selection + */ + udelay(301); + aic_outb(p, CLRSELINGO, CLRSINT0); + /* + * Clear out all the interrupt status bits + */ + aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1); + p->flags &= ~AHC_HANDLING_REQINITS; + aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1); + aic_outb(p, CLRSCSIINT, CLRINT); + /* + * Restarting the sequencer will stop the selection and make sure devices + * are allowed to reselect in. + */ + restart_sequencer(p); + unpause_sequencer(p, TRUE); + } + else if (scb == NULL) + { + printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid " + "during scsiint 0x%x scb(%d)\n" + " SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n", + p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0), + aic_inb(p, SIMODE1), aic_inb(p, SSTAT0), + (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); + /* + * Turn off the interrupt and set status to zero, so that it + * falls through the rest of the SCSIINT code. + */ + aic_outb(p, status, CLRSINT1); + aic_outb(p, CLRSCSIINT, CLRINT); + unpause_sequencer(p, /* unpause always */ TRUE); + scb = NULL; + } + else if (status & SCSIPERR) + { + /* + * Determine the bus phase and queue an appropriate message. + */ + char *phase; + Scsi_Cmnd *cmd; + unsigned char mesg_out = MSG_NOOP; + unsigned char lastphase = aic_inb(p, LASTPHASE); + unsigned char sstat2 = aic_inb(p, SSTAT2); + unsigned char tindex = TARGET_INDEX(scb->cmd); + + cmd = scb->cmd; + switch (lastphase) + { + case P_DATAOUT: + phase = "Data-Out"; + break; + case P_DATAIN: + phase = "Data-In"; + mesg_out = MSG_INITIATOR_DET_ERR; + break; + case P_COMMAND: + phase = "Command"; + break; + case P_MESGOUT: + phase = "Message-Out"; + break; + case P_STATUS: + phase = "Status"; + mesg_out = MSG_INITIATOR_DET_ERR; + break; + case P_MESGIN: + phase = "Message-In"; + mesg_out = MSG_PARITY_ERROR; + break; + default: + phase = "unknown"; + break; + } + + /* + * A parity error has occurred during a data + * transfer phase. Flag it and continue. + */ + if( (p->features & AHC_ULTRA3) && + (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && + (lastphase == P_DATAIN) ) + { + printk(WARN_LEAD "CRC error during %s phase.\n", + p->host_no, CTL_OF_SCB(scb), phase); + if(sstat2 & CRCVALERR) + { + printk(WARN_LEAD " CRC error in intermediate CRC packet.\n", + p->host_no, CTL_OF_SCB(scb)); + } + if(sstat2 & CRCENDERR) + { + printk(WARN_LEAD " CRC error in ending CRC packet.\n", + p->host_no, CTL_OF_SCB(scb)); + } + if(sstat2 & CRCREQERR) + { + printk(WARN_LEAD " Target incorrectly requested a CRC packet.\n", + p->host_no, CTL_OF_SCB(scb)); + } + if(sstat2 & DUAL_EDGE_ERROR) + { + printk(WARN_LEAD " Dual Edge transmission error.\n", + p->host_no, CTL_OF_SCB(scb)); + } + } + else if( (lastphase == P_MESGOUT) && + (cmd == p->dev_dtr_cmnd[tindex]) && + (scb->flags & SCB_MSGOUT_PPR) ) + { + /* + * As per the draft specs, any device capable of supporting any of + * the option values other than 0 are not allowed to reject the + * PPR message. Instead, they must negotiate out what they do + * support instead of rejecting our offering or else they cause + * a parity error during msg_out phase to signal that they don't + * like our settings. + */ + p->needppr &= ~(1 << tindex); + p->needppr_copy &= ~(1 << tindex); + aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun, + MSG_EXT_WDTR_BUS_8_BIT, + (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE)); + aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0, + 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE); + p->transinfo[tindex].goal_options = 0; + p->dtr_pending &= ~(1 << tindex); + scb->flags &= ~SCB_MSGOUT_BITS; + if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "parity error during PPR message, reverting " + "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb)); + } + if ( p->transinfo[tindex].goal_width ) + { + p->needwdtr |= (1 << tindex); + p->needwdtr_copy |= (1 << tindex); + } + if ( p->transinfo[tindex].goal_offset ) + { + if( p->transinfo[tindex].goal_period <= 9 ) + { + p->transinfo[tindex].goal_period = 10; + } + p->needsdtr |= (1 << tindex); + p->needsdtr_copy |= (1 << tindex); + } + scb = NULL; + } + else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR) + { + struct aic7xxx_syncrate *syncrate; + unsigned int period = p->transinfo[tindex].cur_period; + unsigned char options = p->transinfo[tindex].cur_options; + /* + * oops, we had a failure, lower the transfer rate and try again. It's + * worth noting here that it might be wise to also check for typical + * wide setting on narrow cable type problems and try disabling wide + * instead of slowing down if those exist. That's hard to do with simple + * checksums though. + */ + printk(WARN_LEAD "Parity error during %s phase.\n", + p->host_no, CTL_OF_SCB(scb), phase); + if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) + { + syncrate++; + if( (syncrate->rate[0] != NULL) && + (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) + { + p->transinfo[tindex].goal_period = syncrate->period; + if( p->transinfo[tindex].goal_period > 9 ) + { + p->transinfo[tindex].goal_options = 0; + p->needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_width) + { + p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width) + { + p->transinfo[tindex].goal_width = 0; + p->needwdtr &= ~(1<needwdtr_copy &= ~(1<transinfo[tindex].goal_offset = + p->transinfo[tindex].user_offset; + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = + p->transinfo[tindex].user_options; + if( p->transinfo[tindex].goal_period <= 9 ) + { + p->needppr |= (1<needsdtr &= ~(1<needppr_copy |= (1<needsdtr_copy &= ~(1<needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_options = 0; + p->transinfo[tindex].goal_width = 0; + p->needppr &= ~(1<needsdtr &= ~(1<needwdtr &= ~(1<needppr_copy &= ~(1<needsdtr_copy &= ~(1<needwdtr_copy &= ~(1<dev_flags[tindex] &= ~DEVICE_PARITY_ERROR; + } + else + { + p->dev_flags[tindex] |= DEVICE_PARITY_ERROR; + } + + /* + * We've set the hardware to assert ATN if we get a parity + * error on "in" phases, so all we need to do is stuff the + * message buffer with the appropriate message. "In" phases + * have set mesg_out to something other than MSG_NOP. + */ + if (mesg_out != MSG_NOOP) + { + aic_outb(p, mesg_out, MSG_OUT); + aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); + scb = NULL; + } + aic_outb(p, CLRSCSIPERR, CLRSINT1); + aic_outb(p, CLRSCSIINT, CLRINT); + unpause_sequencer(p, /* unpause_always */ TRUE); + } + else if ( (status & REQINIT) && + (p->flags & AHC_HANDLING_REQINITS) ) + { +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (aic7xxx_verbose > 0xffff) + printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.\n", p->host_no, + CTL_OF_SCB(scb), aic_inb(p, SSTAT1)); +#endif + aic7xxx_handle_reqinit(p, scb); + return; + } + else + { + /* + * We don't know what's going on. Turn off the + * interrupt source and try to continue. + */ + if (aic7xxx_verbose & VERBOSE_SCSIINT) + printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n", + p->host_no, -1, -1, -1, status); + aic_outb(p, status, CLRSINT1); + aic_outb(p, CLRSCSIINT, CLRINT); + unpause_sequencer(p, /* unpause always */ TRUE); + scb = NULL; + } + if (scb != NULL) + { + aic7xxx_done(p, scb); + } +} + +#ifdef AIC7XXX_VERBOSE_DEBUGGING +static void +aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer) +{ + unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp; + int i, bogus, lost; + static unsigned char scb_status[AIC7XXX_MAXSCB]; + +#define SCB_NO_LIST 0 +#define SCB_FREE_LIST 1 +#define SCB_WAITING_LIST 2 +#define SCB_DISCONNECTED_LIST 4 +#define SCB_CURRENTLY_ACTIVE 8 + + /* + * Note, these checks will fail on a regular basis once the machine moves + * beyond the bus scan phase. The problem is race conditions concerning + * the scbs and where they are linked in. When you have 30 or so commands + * outstanding on the bus, and run this twice with every interrupt, the + * chances get pretty good that you'll catch the sequencer with an SCB + * only partially linked in. Therefore, once we pass the scan phase + * of the bus, we really should disable this function. + */ + bogus = FALSE; + memset(&scb_status[0], 0, sizeof(scb_status)); + pause_sequencer(p); + saved_scbptr = aic_inb(p, SCBPTR); + if (saved_scbptr >= p->scb_data->maxhscbs) + { + printk("Bogus SCBPTR %d\n", saved_scbptr); + bogus = TRUE; + } + scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE; + free_scbh = aic_inb(p, FREE_SCBH); + if ( (free_scbh != SCB_LIST_NULL) && + (free_scbh >= p->scb_data->maxhscbs) ) + { + printk("Bogus FREE_SCBH %d\n", free_scbh); + bogus = TRUE; + } + else + { + temp = free_scbh; + while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) + { + if(scb_status[temp] & 0x07) + { + printk("HSCB %d on multiple lists, status 0x%02x", temp, + scb_status[temp] | SCB_FREE_LIST); + bogus = TRUE; + } + scb_status[temp] |= SCB_FREE_LIST; + aic_outb(p, temp, SCBPTR); + temp = aic_inb(p, SCB_NEXT); + } + } + + dis_scbh = aic_inb(p, DISCONNECTED_SCBH); + if ( (dis_scbh != SCB_LIST_NULL) && + (dis_scbh >= p->scb_data->maxhscbs) ) + { + printk("Bogus DISCONNECTED_SCBH %d\n", dis_scbh); + bogus = TRUE; + } + else + { + temp = dis_scbh; + while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) + { + if(scb_status[temp] & 0x07) + { + printk("HSCB %d on multiple lists, status 0x%02x", temp, + scb_status[temp] | SCB_DISCONNECTED_LIST); + bogus = TRUE; + } + scb_status[temp] |= SCB_DISCONNECTED_LIST; + aic_outb(p, temp, SCBPTR); + temp = aic_inb(p, SCB_NEXT); + } + } + + wait_scbh = aic_inb(p, WAITING_SCBH); + if ( (wait_scbh != SCB_LIST_NULL) && + (wait_scbh >= p->scb_data->maxhscbs) ) + { + printk("Bogus WAITING_SCBH %d\n", wait_scbh); + bogus = TRUE; + } + else + { + temp = wait_scbh; + while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) + { + if(scb_status[temp] & 0x07) + { + printk("HSCB %d on multiple lists, status 0x%02x", temp, + scb_status[temp] | SCB_WAITING_LIST); + bogus = TRUE; + } + scb_status[temp] |= SCB_WAITING_LIST; + aic_outb(p, temp, SCBPTR); + temp = aic_inb(p, SCB_NEXT); + } + } + + lost=0; + for(i=0; i < p->scb_data->maxhscbs; i++) + { + aic_outb(p, i, SCBPTR); + temp = aic_inb(p, SCB_NEXT); + if ( ((temp != SCB_LIST_NULL) && + (temp >= p->scb_data->maxhscbs)) ) + { + printk("HSCB %d bad, SCB_NEXT invalid(%d).\n", i, temp); + bogus = TRUE; + } + if ( temp == i ) + { + printk("HSCB %d bad, SCB_NEXT points to self.\n", i); + bogus = TRUE; + } + if (scb_status[i] == 0) + lost++; + if (lost > 1) + { + printk("Too many lost scbs.\n"); + bogus=TRUE; + } + } + aic_outb(p, saved_scbptr, SCBPTR); + unpause_sequencer(p, FALSE); + if (bogus) + { + printk("Bogus parameters found in card SCB array structures.\n"); + printk("%s\n", buffer); + aic7xxx_panic_abort(p, NULL); + } + return; +} +#endif + + +/*+F************************************************************************* + * Function: + * aic7xxx_handle_command_completion_intr + * + * Description: + * SCSI command completion interrupt handler. + *-F*************************************************************************/ +static void +aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p) +{ + struct aic7xxx_scb *scb = NULL; + Scsi_Cmnd *cmd; + unsigned char scb_index, tindex; + +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) ) + printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1); +#endif + + /* + * Read the INTSTAT location after clearing the CMDINT bit. This forces + * any posted PCI writes to flush to memory. Gerard Roudier suggested + * this fix to the possible race of clearing the CMDINT bit but not + * having all command bytes flushed onto the qoutfifo. + */ + aic_outb(p, CLRCMDINT, CLRINT); + aic_inb(p, INTSTAT); + /* + * The sequencer will continue running when it + * issues this interrupt. There may be >1 commands + * finished, so loop until we've processed them all. + */ + + while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL) + { + scb_index = p->qoutfifo[p->qoutfifonext]; + p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL; + if ( scb_index >= p->scb_data->numscbs ) + { + printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no, + -1, -1, -1, scb_index); + continue; + } + scb = p->scb_data->scb_array[scb_index]; + if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) + { + printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags " + "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags, + (unsigned long) scb->cmd); + continue; + } + tindex = TARGET_INDEX(scb->cmd); + if (scb->flags & SCB_QUEUED_ABORT) + { + pause_sequencer(p); + if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) && + (aic_inb(p, SCB_TAG) == scb->hscb->tag) ) + { + unpause_sequencer(p, FALSE); + continue; + } + aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel, + scb->cmd->lun, scb->hscb->tag); + scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT | + SCB_QUEUED_ABORT); + unpause_sequencer(p, FALSE); + } + else if (scb->flags & SCB_ABORT) + { + /* + * We started to abort this, but it completed on us, let it + * through as successful + */ + scb->flags &= ~(SCB_ABORT|SCB_RESET); + } + else if (scb->flags & SCB_SENSE) + { + char *buffer = &scb->cmd->sense_buffer[0]; + if (scb->cmd == p->dev_dtr_cmnd[tindex]) + { + struct aic7xxx_scb *old_scb; + /* + * We have valid sense data, send it back immediately. + */ + old_scb = p->scb_data->scb_array[scb->cmd->next->tag]; + *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer; + old_scb->hscb->target_status = scb->hscb->target_status; + old_scb->cmd->result = scb->hscb->target_status; + old_scb->cmd->result |= (DID_ERROR << 16); + aic7xxx_status(old_scb->cmd) = scb->hscb->target_status; + scbq_remove(&p->waiting_scbs, old_scb); + scbq_remove(&p->delayed_scbs[tindex], old_scb); + scb->cmd->next = NULL; + aic7xxx_done(p, scb); + aic7xxx_done(p, old_scb); + continue; + } + else if (buffer[12] == 0x47 || buffer[12] == 0x54) + { + /* + * SCSI errors, run domain validation and re-run negotiation + */ + p->needdv |= (1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<needwdtr |= (p->needwdtr_copy & (1<hscb->target_status)) + { + case QUEUE_FULL: + case BUSY: + scb->hscb->target_status = 0; + scb->cmd->result = 0; + aic7xxx_error(scb->cmd) = DID_OK; + break; + default: + cmd = scb->cmd; + if (scb->hscb->residual_SG_segment_count != 0) + { + aic7xxx_calculate_residual(p, scb); + } + cmd->result |= (aic7xxx_error(cmd) << 16); + aic7xxx_done(p, scb); + break; + } + } +} + +/*+F************************************************************************* + * Function: + * aic7xxx_isr + * + * Description: + * SCSI controller interrupt handler. + *-F*************************************************************************/ +static void +aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct aic7xxx_host *p; + unsigned char intstat; + + p = (struct aic7xxx_host *)dev_id; + + /* + * Just a few sanity checks. Make sure that we have an int pending. + * Also, if PCI, then we are going to check for a PCI bus error status + * should we get too many spurious interrupts. + */ + if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND)) + { +#ifdef CONFIG_PCI + if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) && + !(p->flags & AHC_HANDLING_REQINITS) ) + { + if ( aic_inb(p, ERROR) & PCIERRSTAT ) + { + aic7xxx_pci_intr(p); + } + p->spurious_int = 0; + } + else if ( !(p->flags & AHC_HANDLING_REQINITS) ) + { + p->spurious_int++; + } +#endif + return; + } + + p->spurious_int = 0; + + /* + * Keep track of interrupts for /proc/scsi + */ + p->isr_count++; + +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) && + (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) ) + aic7xxx_check_scbs(p, "Bogus settings at start of interrupt."); +#endif + + /* + * Handle all the interrupt sources - especially for SCSI + * interrupts, we won't get a second chance at them. + */ + if (intstat & CMDCMPLT) + { + aic7xxx_handle_command_completion_intr(p); + } + + if (intstat & BRKADRINT) + { + int i; + unsigned char errno = aic_inb(p, ERROR); + + printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno); + for (i = 0; i < NUMBER(hard_error); i++) + { + if (errno & hard_error[i].errno) + { + printk(KERN_ERR " %s\n", hard_error[i].errmesg); + } + } + printk(KERN_ERR "(scsi%d) SEQADDR=0x%x\n", p->host_no, + (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0))); + if (aic7xxx_panic_on_abort) + aic7xxx_panic_abort(p, NULL); +#ifdef CONFIG_PCI + if (errno & PCIERRSTAT) + aic7xxx_pci_intr(p); +#endif + if (errno & (SQPARERR | ILLOPCODE | ILLSADDR)) + { + sti(); + panic("aic7xxx: unrecoverable BRKADRINT.\n"); + } + if (errno & ILLHADDR) + { + printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first " + "pausing controller!\n", p->host_no); + } +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (errno & DPARERR) + { + if (aic_inb(p, DMAPARAMS) & DIRECTION) + printk("(scsi%d) while DMAing SCB from host to card.\n", p->host_no); + else + printk("(scsi%d) while DMAing SCB from card to host.\n", p->host_no); + } +#endif + aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT); + unpause_sequencer(p, FALSE); + } + + if (intstat & SEQINT) + { + /* + * Read the CCSCBCTL register to work around a bug in the Ultra2 cards + */ + if(p->features & AHC_ULTRA2) + { + aic_inb(p, CCSCBCTL); + } + aic7xxx_handle_seqint(p, intstat); + } + + if (intstat & SCSIINT) + { + aic7xxx_handle_scsiint(p, intstat); + } + +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) && + (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) ) + aic7xxx_check_scbs(p, "Bogus settings at end of interrupt."); +#endif + +} + +/*+F************************************************************************* + * Function: + * do_aic7xxx_isr + * + * Description: + * This is a gross hack to solve a problem in linux kernels 2.1.85 and + * above. Please, children, do not try this at home, and if you ever see + * anything like it, please inform the Gross Hack Police immediately + *-F*************************************************************************/ +static void +do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long cpu_flags; + struct aic7xxx_host *p; + + p = (struct aic7xxx_host *)dev_id; + if(!p) + return; + spin_lock_irqsave(&io_request_lock, cpu_flags); + if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags)) + { + spin_unlock_irqrestore(&io_request_lock, cpu_flags); + return; + } + do + { + aic7xxx_isr(irq, dev_id, regs); + } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); + aic7xxx_done_cmds_complete(p); + aic7xxx_run_waiting_queues(p); + clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags); + spin_unlock_irqrestore(&io_request_lock, cpu_flags); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_device_queue_depth + * + * Description: + * Determines the queue depth for a given device. There are two ways + * a queue depth can be obtained for a tagged queueing device. One + * way is the default queue depth which is determined by whether + * AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used + * as the default queue depth. Otherwise, we use either 4 or 8 as the + * default queue depth (dependent on the number of hardware SCBs). + * The other way we determine queue depth is through the use of the + * aic7xxx_tag_info array which is enabled by defining + * AIC7XXX_TAGGED_QUEUEING_BY_DEVICE. This array can be initialized + * with queue depths for individual devices. It also allows tagged + * queueing to be [en|dis]abled for a specific adapter. + *-F*************************************************************************/ +static int +aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device) +{ + int default_depth = 3; + unsigned char tindex; + unsigned short target_mask; + + tindex = device->id | (device->channel << 3); + target_mask = (1 << tindex); + + if (p->dev_max_queue_depth[tindex] > 1) + { + /* + * We've already scanned this device, leave it alone + */ + return(p->dev_max_queue_depth[tindex]); + } + + device->queue_depth = default_depth; + p->dev_temp_queue_depth[tindex] = 1; + p->dev_max_queue_depth[tindex] = 1; + p->tagenable &= ~target_mask; + + if (device->tagged_supported) + { + int tag_enabled = TRUE; + + default_depth = AIC7XXX_CMDS_PER_DEVICE; + + if (!(p->discenable & target_mask)) + { + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + printk(INFO_LEAD "Disconnection disabled, unable to " + "enable tagged queueing.\n", + p->host_no, device->channel, device->id, device->lun); + } + else + { + if (p->instance >= NUMBER(aic7xxx_tag_info)) + { + static int print_warning = TRUE; + if(print_warning) + { + printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for" + " installed controllers.\n"); + printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in" + " the aic7xxx.c source file.\n"); + print_warning = FALSE; + } + device->queue_depth = default_depth; + } + else + { + + if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255) + { + tag_enabled = FALSE; + device->queue_depth = 3; /* Tagged queueing is disabled. */ + } + else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0) + { + device->queue_depth = default_depth; + } + else + { + device->queue_depth = + aic7xxx_tag_info[p->instance].tag_commands[tindex]; + } + } + if ((device->tagged_queue == 0) && tag_enabled) + { + if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) + { + printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n", + p->host_no, device->channel, device->id, + device->lun, device->queue_depth); + } + p->dev_max_queue_depth[tindex] = device->queue_depth; + p->dev_temp_queue_depth[tindex] = device->queue_depth; + p->tagenable |= target_mask; + p->orderedtag |= target_mask; + device->tagged_queue = 1; + device->current_tag = SCB_LIST_NULL; + } + } + } + return(p->dev_max_queue_depth[tindex]); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_select_queue_depth + * + * Description: + * Sets the queue depth for each SCSI device hanging off the input + * host adapter. We use a queue depth of 2 for devices that do not + * support tagged queueing. If AIC7XXX_CMDS_PER_LUN is defined, we + * use that for tagged queueing devices; otherwise we use our own + * algorithm for determining the queue depth based on the maximum + * SCBs for the controller. + *-F*************************************************************************/ +static void +aic7xxx_select_queue_depth(struct Scsi_Host *host, + Scsi_Device *scsi_devs) +{ + Scsi_Device *device; + struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata; + int scbnum; + + scbnum = 0; + for (device = scsi_devs; device != NULL; device = device->next) + { + if (device->host == host) + { + scbnum += aic7xxx_device_queue_depth(p, device); + } + } + while (scbnum > p->scb_data->numscbs) + { + /* + * Pre-allocate the needed SCBs to get around the possibility of having + * to allocate some when memory is more or less exhausted and we need + * the SCB in order to perform a swap operation (possible deadlock) + */ + if ( aic7xxx_allocate_scb(p) == 0 ) + return; + } +} + +/*+F************************************************************************* + * Function: + * aic7xxx_probe + * + * Description: + * Probing for EISA boards: it looks like the first two bytes + * are a manufacturer code - three characters, five bits each: + * + * BYTE 0 BYTE 1 BYTE 2 BYTE 3 + * ?1111122 22233333 PPPPPPPP RRRRRRRR + * + * The characters are baselined off ASCII '@', so add that value + * to each to get the real ASCII code for it. The next two bytes + * appear to be a product and revision number, probably vendor- + * specific. This is what is being searched for at each port, + * and what should probably correspond to the ID= field in the + * ECU's .cfg file for the card - if your card is not detected, + * make sure your signature is listed in the array. + * + * The fourth byte's lowest bit seems to be an enabled/disabled + * flag (rest of the bits are reserved?). + * + * NOTE: This function is only needed on Intel and Alpha platforms, + * the other platforms we support don't have EISA/VLB busses. So, + * we #ifdef this entire function to avoid compiler warnings about + * an unused function. + *-F*************************************************************************/ +#if defined(__i386__) || defined(__alpha__) +static int +aic7xxx_probe(int slot, int base, ahc_flag_type *flags) +{ + int i; + unsigned char buf[4]; + + static struct { + int n; + unsigned char signature[sizeof(buf)]; + ahc_chip type; + int bios_disabled; + } AIC7xxx[] = { + { 4, { 0x04, 0x90, 0x77, 0x70 }, + AHC_AIC7770|AHC_EISA, FALSE }, /* mb 7770 */ + { 4, { 0x04, 0x90, 0x77, 0x71 }, + AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */ + { 4, { 0x04, 0x90, 0x77, 0x56 }, + AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */ + { 4, { 0x04, 0x90, 0x77, 0x57 }, + AHC_AIC7770|AHC_VL, TRUE } /* 284x BIOS disabled */ + }; + + /* + * The VL-bus cards need to be primed by + * writing before a signature check. + */ + for (i = 0; i < sizeof(buf); i++) + { + outb(0x80 + i, base); + buf[i] = inb(base + i); + } + + for (i = 0; i < NUMBER(AIC7xxx); i++) + { + /* + * Signature match on enabled card? + */ + if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n)) + { + if (inb(base + 4) & 1) + { + if (AIC7xxx[i].bios_disabled) + { + *flags |= AHC_USEDEFAULTS; + } + else + { + *flags |= AHC_BIOS_ENABLED; + } + return (i); + } + + printk("aic7xxx: " + "disabled at slot %d, ignored.\n", slot); + } + } + + return (-1); +} +#endif /* (__i386__) || (__alpha__) */ + + +/*+F************************************************************************* + * Function: + * read_2840_seeprom + * + * Description: + * Reads the 2840 serial EEPROM and returns 1 if successful and 0 if + * not successful. + * + * See read_seeprom (for the 2940) for the instruction set of the 93C46 + * chip. + * + * The 2840 interface to the 93C46 serial EEPROM is through the + * STATUS_2840 and SEECTL_2840 registers. The CS_2840, CK_2840, and + * DO_2840 bits of the SEECTL_2840 register are connected to the chip + * select, clock, and data out lines respectively of the serial EEPROM. + * The DI_2840 bit of the STATUS_2840 is connected to the data in line + * of the serial EEPROM. The EEPROM_TF bit of STATUS_2840 register is + * useful in that it gives us an 800 nsec timer. After a read from the + * SEECTL_2840 register the timing flag is cleared and goes high 800 nsec + * later. + *-F*************************************************************************/ +static int +read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc) +{ + int i = 0, k = 0; + unsigned char temp; + unsigned short checksum = 0; + unsigned short *seeprom = (unsigned short *) sc; + struct seeprom_cmd { + unsigned char len; + unsigned char bits[3]; + }; + struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; + +#define CLOCK_PULSE(p) \ + while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0) \ + { \ + ; /* Do nothing */ \ + } \ + (void) aic_inb(p, SEECTL_2840); + + /* + * Read the first 32 registers of the seeprom. For the 2840, + * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers + * but only the first 32 are used by Adaptec BIOS. The loop + * will range from 0 to 31. + */ + for (k = 0; k < (sizeof(*sc) / 2); k++) + { + /* + * Send chip select for one clock cycle. + */ + aic_outb(p, CK_2840 | CS_2840, SEECTL_2840); + CLOCK_PULSE(p); + + /* + * Now we're ready to send the read command followed by the + * address of the 16-bit register we want to read. + */ + for (i = 0; i < seeprom_read.len; i++) + { + temp = CS_2840 | seeprom_read.bits[i]; + aic_outb(p, temp, SEECTL_2840); + CLOCK_PULSE(p); + temp = temp ^ CK_2840; + aic_outb(p, temp, SEECTL_2840); + CLOCK_PULSE(p); + } + /* + * Send the 6 bit address (MSB first, LSB last). + */ + for (i = 5; i >= 0; i--) + { + temp = k; + temp = (temp >> i) & 1; /* Mask out all but lower bit. */ + temp = CS_2840 | temp; + aic_outb(p, temp, SEECTL_2840); + CLOCK_PULSE(p); + temp = temp ^ CK_2840; + aic_outb(p, temp, SEECTL_2840); + CLOCK_PULSE(p); + } + + /* + * Now read the 16 bit register. An initial 0 precedes the + * register contents which begins with bit 15 (MSB) and ends + * with bit 0 (LSB). The initial 0 will be shifted off the + * top of our word as we let the loop run from 0 to 16. + */ + for (i = 0; i <= 16; i++) + { + temp = CS_2840; + aic_outb(p, temp, SEECTL_2840); + CLOCK_PULSE(p); + temp = temp ^ CK_2840; + seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840); + aic_outb(p, temp, SEECTL_2840); + CLOCK_PULSE(p); + } + /* + * The serial EEPROM has a checksum in the last word. Keep a + * running checksum for all words read except for the last + * word. We'll verify the checksum after all words have been + * read. + */ + if (k < (sizeof(*sc) / 2) - 1) + { + checksum = checksum + seeprom[k]; + } + + /* + * Reset the chip select for the next command cycle. + */ + aic_outb(p, 0, SEECTL_2840); + CLOCK_PULSE(p); + aic_outb(p, CK_2840, SEECTL_2840); + CLOCK_PULSE(p); + aic_outb(p, 0, SEECTL_2840); + CLOCK_PULSE(p); + } + +#if 0 + printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum); + printk("Serial EEPROM:"); + for (k = 0; k < (sizeof(*sc) / 2); k++) + { + if (((k % 8) == 0) && (k != 0)) + { + printk("\n "); + } + printk(" 0x%x", seeprom[k]); + } + printk("\n"); +#endif + + if (checksum != sc->checksum) + { + printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n"); + return (0); + } + + return (1); +#undef CLOCK_PULSE +} + +#define CLOCK_PULSE(p) \ + do { \ + int limit = 0; \ + do { \ + mb(); \ + pause_sequencer(p); /* This is just to generate some PCI */ \ + /* traffic so the PCI read is flushed */ \ + /* it shouldn't be needed, but some */ \ + /* chipsets do indeed appear to need */ \ + /* something to force PCI reads to get */ \ + /* flushed */ \ + udelay(1); /* Do nothing */ \ + } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \ + } while(0) + +/*+F************************************************************************* + * Function: + * acquire_seeprom + * + * Description: + * Acquires access to the memory port on PCI controllers. + *-F*************************************************************************/ +static int +acquire_seeprom(struct aic7xxx_host *p) +{ + + /* + * Request access of the memory port. When access is + * granted, SEERDY will go high. We use a 1 second + * timeout which should be near 1 second more than + * is needed. Reason: after the 7870 chip reset, there + * should be no contention. + */ + aic_outb(p, SEEMS, SEECTL); + CLOCK_PULSE(p); + if ((aic_inb(p, SEECTL) & SEERDY) == 0) + { + aic_outb(p, 0, SEECTL); + return (0); + } + return (1); +} + +/*+F************************************************************************* + * Function: + * release_seeprom + * + * Description: + * Releases access to the memory port on PCI controllers. + *-F*************************************************************************/ +static void +release_seeprom(struct aic7xxx_host *p) +{ + /* + * Make sure the SEEPROM is ready before we release it. + */ + CLOCK_PULSE(p); + aic_outb(p, 0, SEECTL); +} + +/*+F************************************************************************* + * Function: + * read_seeprom + * + * Description: + * Reads the serial EEPROM and returns 1 if successful and 0 if + * not successful. + * + * The instruction set of the 93C46/56/66 chips is as follows: + * + * Start OP + * Function Bit Code Address Data Description + * ------------------------------------------------------------------- + * READ 1 10 A5 - A0 Reads data stored in memory, + * starting at specified address + * EWEN 1 00 11XXXX Write enable must precede + * all programming modes + * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 + * WRITE 1 01 A5 - A0 D15 - D0 Writes register + * ERAL 1 00 10XXXX Erase all registers + * WRAL 1 00 01XXXX D15 - D0 Writes to all registers + * EWDS 1 00 00XXXX Disables all programming + * instructions + * *Note: A value of X for address is a don't care condition. + * *Note: The 93C56 and 93C66 have 8 address bits. + * + * + * The 93C46 has a four wire interface: clock, chip select, data in, and + * data out. In order to perform one of the above functions, you need + * to enable the chip select for a clock period (typically a minimum of + * 1 usec, with the clock high and low a minimum of 750 and 250 nsec + * respectively. While the chip select remains high, you can clock in + * the instructions (above) starting with the start bit, followed by the + * OP code, Address, and Data (if needed). For the READ instruction, the + * requested 16-bit register contents is read from the data out line but + * is preceded by an initial zero (leading 0, followed by 16-bits, MSB + * first). The clock cycling from low to high initiates the next data + * bit to be sent from the chip. + * + * The 78xx interface to the 93C46 serial EEPROM is through the SEECTL + * register. After successful arbitration for the memory port, the + * SEECS bit of the SEECTL register is connected to the chip select. + * The SEECK, SEEDO, and SEEDI are connected to the clock, data out, + * and data in lines respectively. The SEERDY bit of SEECTL is useful + * in that it gives us an 800 nsec timer. After a write to the SEECTL + * register, the SEERDY goes high 800 nsec later. The one exception + * to this is when we first request access to the memory port. The + * SEERDY goes high to signify that access has been granted and, for + * this case, has no implied timing. + *-F*************************************************************************/ +static int +read_seeprom(struct aic7xxx_host *p, int offset, + unsigned short *scarray, unsigned int len, seeprom_chip_type chip) +{ + int i = 0, k; + unsigned char temp; + unsigned short checksum = 0; + struct seeprom_cmd { + unsigned char len; + unsigned char bits[3]; + }; + struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; + + /* + * Request access of the memory port. + */ + if (acquire_seeprom(p) == 0) + { + return (0); + } + + /* + * Read 'len' registers of the seeprom. For the 7870, the 93C46 + * SEEPROM is a 1024-bit device with 64 16-bit registers but only + * the first 32 are used by Adaptec BIOS. Some adapters use the + * 93C56 SEEPROM which is a 2048-bit device. The loop will range + * from 0 to 'len' - 1. + */ + for (k = 0; k < len; k++) + { + /* + * Send chip select for one clock cycle. + */ + aic_outb(p, SEEMS | SEECK | SEECS, SEECTL); + CLOCK_PULSE(p); + + /* + * Now we're ready to send the read command followed by the + * address of the 16-bit register we want to read. + */ + for (i = 0; i < seeprom_read.len; i++) + { + temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1); + aic_outb(p, temp, SEECTL); + CLOCK_PULSE(p); + temp = temp ^ SEECK; + aic_outb(p, temp, SEECTL); + CLOCK_PULSE(p); + } + /* + * Send the 6 or 8 bit address (MSB first, LSB last). + */ + for (i = ((int) chip - 1); i >= 0; i--) + { + temp = k + offset; + temp = (temp >> i) & 1; /* Mask out all but lower bit. */ + temp = SEEMS | SEECS | (temp << 1); + aic_outb(p, temp, SEECTL); + CLOCK_PULSE(p); + temp = temp ^ SEECK; + aic_outb(p, temp, SEECTL); + CLOCK_PULSE(p); + } + + /* + * Now read the 16 bit register. An initial 0 precedes the + * register contents which begins with bit 15 (MSB) and ends + * with bit 0 (LSB). The initial 0 will be shifted off the + * top of our word as we let the loop run from 0 to 16. + */ + for (i = 0; i <= 16; i++) + { + temp = SEEMS | SEECS; + aic_outb(p, temp, SEECTL); + CLOCK_PULSE(p); + temp = temp ^ SEECK; + scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI); + aic_outb(p, temp, SEECTL); + CLOCK_PULSE(p); + } + + /* + * The serial EEPROM should have a checksum in the last word. + * Keep a running checksum for all words read except for the + * last word. We'll verify the checksum after all words have + * been read. + */ + if (k < (len - 1)) + { + checksum = checksum + scarray[k]; + } + + /* + * Reset the chip select for the next command cycle. + */ + aic_outb(p, SEEMS, SEECTL); + CLOCK_PULSE(p); + aic_outb(p, SEEMS | SEECK, SEECTL); + CLOCK_PULSE(p); + aic_outb(p, SEEMS, SEECTL); + CLOCK_PULSE(p); + } + + /* + * Release access to the memory port and the serial EEPROM. + */ + release_seeprom(p); + +#if 0 + printk("Computed checksum 0x%x, checksum read 0x%x\n", + checksum, scarray[len - 1]); + printk("Serial EEPROM:"); + for (k = 0; k < len; k++) + { + if (((k % 8) == 0) && (k != 0)) + { + printk("\n "); + } + printk(" 0x%x", scarray[k]); + } + printk("\n"); +#endif + if ( (checksum != scarray[len - 1]) || (checksum == 0) ) + { + return (0); + } + + return (1); +} + +/*+F************************************************************************* + * Function: + * read_brdctl + * + * Description: + * Reads the BRDCTL register. + *-F*************************************************************************/ +static unsigned char +read_brdctl(struct aic7xxx_host *p) +{ + unsigned char brdctl, value; + + /* + * Make sure the SEEPROM is ready before we access it + */ + CLOCK_PULSE(p); + if (p->features & AHC_ULTRA2) + { + brdctl = BRDRW_ULTRA2; + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + value = aic_inb(p, BRDCTL); + CLOCK_PULSE(p); + return(value); + } + brdctl = BRDRW; + if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || + (p->flags & AHC_CHNLB) ) + { + brdctl |= BRDCS; + } + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + value = aic_inb(p, BRDCTL); + CLOCK_PULSE(p); + aic_outb(p, 0, BRDCTL); + CLOCK_PULSE(p); + return (value); +} + +/*+F************************************************************************* + * Function: + * write_brdctl + * + * Description: + * Writes a value to the BRDCTL register. + *-F*************************************************************************/ +static void +write_brdctl(struct aic7xxx_host *p, unsigned char value) +{ + unsigned char brdctl; + + /* + * Make sure the SEEPROM is ready before we access it + */ + CLOCK_PULSE(p); + if (p->features & AHC_ULTRA2) + { + brdctl = value; + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + brdctl |= BRDSTB_ULTRA2; + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + brdctl &= ~BRDSTB_ULTRA2; + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + read_brdctl(p); + CLOCK_PULSE(p); + } + else + { + brdctl = BRDSTB; + if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || + (p->flags & AHC_CHNLB) ) + { + brdctl |= BRDCS; + } + brdctl = BRDSTB | BRDCS; + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + brdctl |= value; + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + brdctl &= ~BRDSTB; + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + brdctl &= ~BRDCS; + aic_outb(p, brdctl, BRDCTL); + CLOCK_PULSE(p); + } +} + +/*+F************************************************************************* + * Function: + * aic785x_cable_detect + * + * Description: + * Detect the cables that are present on aic785x class controller chips + *-F*************************************************************************/ +static void +aic785x_cable_detect(struct aic7xxx_host *p, int *int_50, + int *ext_present, int *eeprom) +{ + unsigned char brdctl; + + aic_outb(p, BRDRW | BRDCS, BRDCTL); + CLOCK_PULSE(p); + aic_outb(p, 0, BRDCTL); + CLOCK_PULSE(p); + brdctl = aic_inb(p, BRDCTL); + CLOCK_PULSE(p); + *int_50 = !(brdctl & BRDDAT5); + *ext_present = !(brdctl & BRDDAT6); + *eeprom = (aic_inb(p, SPIOCAP) & EEPROM); +} + +#undef CLOCK_PULSE + +/*+F************************************************************************* + * Function: + * aic2940_uwpro_cable_detect + * + * Description: + * Detect the cables that are present on the 2940-UWPro cards + * + * NOTE: This function assumes the SEEPROM will have already been acquired + * prior to invocation of this function. + *-F*************************************************************************/ +static void +aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68, + int *ext_68, int *eeprom) +{ + unsigned char brdctl; + + /* + * First read the status of our cables. Set the rom bank to + * 0 since the bank setting serves as a multiplexor for the + * cable detection logic. BRDDAT5 controls the bank switch. + */ + write_brdctl(p, 0); + + /* + * Now we read the state of the internal 68 connector. BRDDAT6 + * is don't care, BRDDAT7 is internal 68. The cable is + * present if the bit is 0 + */ + brdctl = read_brdctl(p); + *int_68 = !(brdctl & BRDDAT7); + + /* + * Set the bank bit in brdctl and then read the external cable state + * and the EEPROM status + */ + write_brdctl(p, BRDDAT5); + brdctl = read_brdctl(p); + + *ext_68 = !(brdctl & BRDDAT6); + *eeprom = !(brdctl & BRDDAT7); + + /* + * We're done, the calling function will release the SEEPROM for us + */ +} + +/*+F************************************************************************* + * Function: + * aic787x_cable_detect + * + * Description: + * Detect the cables that are present on aic787x class controller chips + * + * NOTE: This function assumes the SEEPROM will have already been acquired + * prior to invocation of this function. + *-F*************************************************************************/ +static void +aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68, + int *ext_present, int *eeprom) +{ + unsigned char brdctl; + + /* + * First read the status of our cables. Set the rom bank to + * 0 since the bank setting serves as a multiplexor for the + * cable detection logic. BRDDAT5 controls the bank switch. + */ + write_brdctl(p, 0); + + /* + * Now we read the state of the two internal connectors. BRDDAT6 + * is internal 50, BRDDAT7 is internal 68. For each, the cable is + * present if the bit is 0 + */ + brdctl = read_brdctl(p); + *int_50 = !(brdctl & BRDDAT6); + *int_68 = !(brdctl & BRDDAT7); + + /* + * Set the bank bit in brdctl and then read the external cable state + * and the EEPROM status + */ + write_brdctl(p, BRDDAT5); + brdctl = read_brdctl(p); + + *ext_present = !(brdctl & BRDDAT6); + *eeprom = !(brdctl & BRDDAT7); + + /* + * We're done, the calling function will release the SEEPROM for us + */ +} + +/*+F************************************************************************* + * Function: + * aic787x_ultra2_term_detect + * + * Description: + * Detect the termination settings present on ultra2 class controllers + * + * NOTE: This function assumes the SEEPROM will have already been acquired + * prior to invocation of this function. + *-F*************************************************************************/ +static void +aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low, + int *enableSE_high, int *enableLVD_low, + int *enableLVD_high, int *eprom_present) +{ + unsigned char brdctl; + + brdctl = read_brdctl(p); + + *eprom_present = (brdctl & BRDDAT7); + *enableSE_high = (brdctl & BRDDAT6); + *enableSE_low = (brdctl & BRDDAT5); + *enableLVD_high = (brdctl & BRDDAT4); + *enableLVD_low = (brdctl & BRDDAT3); +} + +/*+F************************************************************************* + * Function: + * configure_termination + * + * Description: + * Configures the termination settings on PCI adapters that have + * SEEPROMs available. + *-F*************************************************************************/ +static void +configure_termination(struct aic7xxx_host *p) +{ + int internal50_present = 0; + int internal68_present = 0; + int external_present = 0; + int eprom_present = 0; + int enableSE_low = 0; + int enableSE_high = 0; + int enableLVD_low = 0; + int enableLVD_high = 0; + unsigned char brddat = 0; + unsigned char max_target = 0; + unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1); + + if (acquire_seeprom(p)) + { + if (p->features & (AHC_WIDE|AHC_TWIN)) + max_target = 16; + else + max_target = 8; + aic_outb(p, SEEMS | SEECS, SEECTL); + sxfrctl1 &= ~STPWEN; + /* + * The termination/cable detection logic is split into three distinct + * groups. Ultra2 and later controllers, 2940UW-Pro controllers, and + * older 7850, 7860, 7870, 7880, and 7895 controllers. Each has its + * own unique way of detecting their cables and writing the results + * back to the card. + */ + if (p->features & AHC_ULTRA2) + { + /* + * As long as user hasn't overridden term settings, always check the + * cable detection logic + */ + if (aic7xxx_override_term == -1) + { + aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high, + &enableLVD_low, &enableLVD_high, + &eprom_present); + } + + /* + * If the user is overriding settings, then they have been preserved + * to here as fake adapter_control entries. Parse them and allow + * them to override the detected settings (if we even did detection). + */ + if (!(p->adapter_control & CFSEAUTOTERM)) + { + enableSE_low = (p->adapter_control & CFSTERM); + enableSE_high = (p->adapter_control & CFWSTERM); + } + if (!(p->adapter_control & CFAUTOTERM)) + { + enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM); + } + + /* + * Now take those settings that we have and translate them into the + * values that must be written into the registers. + * + * Flash Enable = BRDDAT7 + * Secondary High Term Enable = BRDDAT6 + * Secondary Low Term Enable = BRDDAT5 + * LVD/Primary High Term Enable = BRDDAT4 + * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1 + */ + if (enableLVD_low != 0) + { + sxfrctl1 |= STPWEN; + p->flags |= AHC_TERM_ENB_LVD; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination " + "Enabled\n", p->host_no); + } + + if (enableLVD_high != 0) + { + brddat |= BRDDAT4; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination " + "Enabled\n", p->host_no); + } + + if (enableSE_low != 0) + { + brddat |= BRDDAT5; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Secondary Low byte termination " + "Enabled\n", p->host_no); + } + + if (enableSE_high != 0) + { + brddat |= BRDDAT6; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Secondary High byte termination " + "Enabled\n", p->host_no); + } + } + else if (p->features & AHC_NEW_AUTOTERM) + { + /* + * The 50 pin connector termination is controlled by STPWEN in the + * SXFRCTL1 register. Since the Adaptec docs typically say the + * controller is not allowed to be in the middle of a cable and + * this is the only connection on that stub of the bus, there is + * no need to even check for narrow termination, it's simply + * always on. + */ + sxfrctl1 |= STPWEN; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n", + p->host_no); + + if (p->adapter_control & CFAUTOTERM) + { + aic2940_uwpro_wide_cable_detect(p, &internal68_present, + &external_present, + &eprom_present); + printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " + "Ext-68 %s)\n", p->host_no, + "Don't Care", + internal68_present ? "YES" : "NO", + external_present ? "YES" : "NO"); + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, + eprom_present ? "is" : "is not"); + if (internal68_present && external_present) + { + brddat = 0; + p->flags &= ~AHC_TERM_ENB_SE_HIGH; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n", + p->host_no); + } + else + { + brddat = BRDDAT6; + p->flags |= AHC_TERM_ENB_SE_HIGH; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", + p->host_no); + } + } + else + { + /* + * The termination of the Wide channel is done more like normal + * though, and the setting of this termination is done by writing + * either a 0 or 1 to BRDDAT6 of the BRDDAT register + */ + if (p->adapter_control & CFWSTERM) + { + brddat = BRDDAT6; + p->flags |= AHC_TERM_ENB_SE_HIGH; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", + p->host_no); + } + else + { + brddat = 0; + } + } + } + else + { + if (p->adapter_control & CFAUTOTERM) + { + if (p->flags & AHC_MOTHERBOARD) + { + printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n", + p->host_no); + printk(KERN_INFO "(scsi%d) Please verify driver detected settings " + "are correct.\n", p->host_no); + printk(KERN_INFO "(scsi%d) If not, then please properly set the " + "device termination\n", p->host_no); + printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting " + "CTRL-A when prompted\n", p->host_no); + printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no); + } + /* Configure auto termination. */ + + if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 ) + { + aic787x_cable_detect(p, &internal50_present, &internal68_present, + &external_present, &eprom_present); + } + else + { + aic785x_cable_detect(p, &internal50_present, &external_present, + &eprom_present); + } + + if (max_target <= 8) + internal68_present = 0; + + if (max_target > 8) + { + printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " + "Ext-68 %s)\n", p->host_no, + internal50_present ? "YES" : "NO", + internal68_present ? "YES" : "NO", + external_present ? "YES" : "NO"); + } + else + { + printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)\n", + p->host_no, + internal50_present ? "YES" : "NO", + external_present ? "YES" : "NO"); + } + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, + eprom_present ? "is" : "is not"); + + /* + * Now set the termination based on what we found. BRDDAT6 + * controls wide termination enable. + * Flash Enable = BRDDAT7 + * SE High Term Enable = BRDDAT6 + */ + if (internal50_present && internal68_present && external_present) + { + printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n", + p->host_no); + printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be " + "in use at a time!\n", p->host_no); + /* + * Force termination (low and high byte) on. This is safer than + * leaving it completely off, especially since this message comes + * most often from motherboard controllers that don't even have 3 + * connectors, but instead are failing the cable detection. + */ + internal50_present = external_present = 0; + enableSE_high = enableSE_low = 1; + } + + if ((max_target > 8) && + ((external_present == 0) || (internal68_present == 0)) ) + { + brddat |= BRDDAT6; + p->flags |= AHC_TERM_ENB_SE_HIGH; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", + p->host_no); + } + + if ( ((internal50_present ? 1 : 0) + + (internal68_present ? 1 : 0) + + (external_present ? 1 : 0)) <= 1 ) + { + sxfrctl1 |= STPWEN; + p->flags |= AHC_TERM_ENB_SE_LOW; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", + p->host_no); + } + } + else /* p->adapter_control & CFAUTOTERM */ + { + if (p->adapter_control & CFSTERM) + { + sxfrctl1 |= STPWEN; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", + p->host_no); + } + + if (p->adapter_control & CFWSTERM) + { + brddat |= BRDDAT6; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", + p->host_no); + } + } + } + + aic_outb(p, sxfrctl1, SXFRCTL1); + write_brdctl(p, brddat); + release_seeprom(p); + } +} + +/*+F************************************************************************* + * Function: + * detect_maxscb + * + * Description: + * Detects the maximum number of SCBs for the controller and returns + * the count and a mask in p (p->maxscbs, p->qcntmask). + *-F*************************************************************************/ +static void +detect_maxscb(struct aic7xxx_host *p) +{ + int i; + + /* + * It's possible that we've already done this for multichannel + * adapters. + */ + if (p->scb_data->maxhscbs == 0) + { + /* + * We haven't initialized the SCB settings yet. Walk the SCBs to + * determince how many there are. + */ + aic_outb(p, 0, FREE_SCBH); + + for (i = 0; i < AIC7XXX_MAXSCB; i++) + { + aic_outb(p, i, SCBPTR); + aic_outb(p, i, SCB_CONTROL); + if (aic_inb(p, SCB_CONTROL) != i) + break; + aic_outb(p, 0, SCBPTR); + if (aic_inb(p, SCB_CONTROL) != 0) + break; + + aic_outb(p, i, SCBPTR); + aic_outb(p, 0, SCB_CONTROL); /* Clear the control byte. */ + aic_outb(p, i + 1, SCB_NEXT); /* Set the next pointer. */ + aic_outb(p, SCB_LIST_NULL, SCB_TAG); /* Make the tag invalid. */ + aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS); /* no busy untagged */ + aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */ + aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2); + aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3); + } + + /* Make sure the last SCB terminates the free list. */ + aic_outb(p, i - 1, SCBPTR); + aic_outb(p, SCB_LIST_NULL, SCB_NEXT); + + /* Ensure we clear the first (0) SCBs control byte. */ + aic_outb(p, 0, SCBPTR); + aic_outb(p, 0, SCB_CONTROL); + + p->scb_data->maxhscbs = i; + /* + * Use direct indexing instead for speed + */ + if ( i == AIC7XXX_MAXSCB ) + p->flags &= ~AHC_PAGESCBS; + } + +} + +/*+F************************************************************************* + * Function: + * aic7xxx_register + * + * Description: + * Register a Adaptec aic7xxx chip SCSI controller with the kernel. + *-F*************************************************************************/ +static int +aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p, + int reset_delay) +{ + int i, result; + int max_targets; + int found = 1; + unsigned char term, scsi_conf; + struct Scsi_Host *host; + + host = p->host; + + p->scb_data->maxscbs = AIC7XXX_MAXSCB; + host->can_queue = AIC7XXX_MAXSCB; + host->cmd_per_lun = 3; + host->sg_tablesize = AIC7XXX_MAX_SG; + host->select_queue_depths = aic7xxx_select_queue_depth; + host->this_id = p->scsi_id; + host->io_port = p->base; + host->n_io_port = 0xFF; + host->base = p->mbase; + host->irq = p->irq; + if (p->features & AHC_WIDE) + { + host->max_id = 16; + } + if (p->features & AHC_TWIN) + { + host->max_channel = 1; + } + + p->host = host; + p->host_no = host->host_no; + host->unique_id = p->instance; + p->isr_count = 0; + p->next = NULL; + p->completeq.head = NULL; + p->completeq.tail = NULL; + scbq_init(&p->scb_data->free_scbs); + scbq_init(&p->waiting_scbs); + init_timer(&p->dev_timer); + p->dev_timer.data = (unsigned long)p; + p->dev_timer.function = (void *)aic7xxx_timer; + p->dev_timer_active = 0; + + /* + * We currently have no commands of any type + */ + p->qinfifonext = 0; + p->qoutfifonext = 0; + + for (i = 0; i < MAX_TARGETS; i++) + { + p->dev_commands_sent[i] = 0; + p->dev_flags[i] = 0; + p->dev_active_cmds[i] = 0; + p->dev_last_queue_full[i] = 0; + p->dev_last_queue_full_count[i] = 0; + p->dev_max_queue_depth[i] = 1; + p->dev_temp_queue_depth[i] = 1; + p->dev_expires[i] = 0; + scbq_init(&p->delayed_scbs[i]); + } + + printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no, + board_names[p->board_name_index]); + switch(p->chip) + { + case (AHC_AIC7770|AHC_EISA): + printk("EISA slot %d\n", p->pci_device_fn); + break; + case (AHC_AIC7770|AHC_VL): + printk("VLB slot %d\n", p->pci_device_fn); + break; + default: + printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn), + PCI_FUNC(p->pci_device_fn)); + break; + } + if (p->features & AHC_TWIN) + { + printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ", + p->host_no, p->scsi_id, p->scsi_id_b); + } + else + { + char *channel; + + channel = ""; + + if ((p->flags & AHC_MULTI_CHANNEL) != 0) + { + channel = " A"; + + if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 ) + { + channel = (p->flags & AHC_CHNLB) ? " B" : " C"; + } + } + if (p->features & AHC_WIDE) + { + printk(KERN_INFO "(scsi%d) Wide ", p->host_no); + } + else + { + printk(KERN_INFO "(scsi%d) Narrow ", p->host_no); + } + printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id); + } + aic_outb(p, 0, SEQ_FLAGS); + + detect_maxscb(p); + + printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs); + if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n", + p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis", + p->base, p->irq); + printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n", + p->host_no, p->mbase, (unsigned long)p->maddr); + } + +#ifdef CONFIG_PCI + /* + * Now that we know our instance number, we can set the flags we need to + * force termination if need be. + */ + if (aic7xxx_stpwlev != -1) + { + /* + * This option only applies to PCI controllers. + */ + if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) + { + unsigned char devconfig; + + pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig); + if ( (aic7xxx_stpwlev >> p->instance) & 0x01 ) + { + devconfig |= STPWLEVEL; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no); + } + else + { + devconfig &= ~STPWLEVEL; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no); + } + pci_write_config_byte(p->pdev, DEVCONFIG, devconfig); + } + } +#endif + + /* + * That took care of devconfig and stpwlev, now for the actual termination + * settings. + */ + if (aic7xxx_override_term != -1) + { + /* + * Again, this only applies to PCI controllers. We don't have problems + * with the termination on 274x controllers to the best of my knowledge. + */ + if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) + { + unsigned char term_override; + + term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f); + p->adapter_control &= + ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM); + if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) ) + { + p->adapter_control |= CFLVDSTERM; + } + if (term_override & 0x02) + { + p->adapter_control |= CFWSTERM; + } + if (term_override & 0x01) + { + p->adapter_control |= CFSTERM; + } + } + } + + if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) ) + { + if (p->features & AHC_SPIOCAP) + { + if ( aic_inb(p, SPIOCAP) & SSPIOCPS ) + /* + * Update the settings in sxfrctl1 to match the termination + * settings. + */ + configure_termination(p); + } + else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870) + { + configure_termination(p); + } + } + + /* + * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels + */ + if (p->features & AHC_TWIN) + { + /* Select channel B */ + aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); + + if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) + term = (aic_inb(p, SXFRCTL1) & STPWEN); + else + term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0); + + aic_outb(p, p->scsi_id_b, SCSIID); + scsi_conf = aic_inb(p, SCSICONF + 1); + aic_outb(p, DFON | SPIOEN, SXFRCTL0); + aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | + ENSTIMER | ACTNEGEN, SXFRCTL1); + aic_outb(p, 0, SIMODE0); + aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); + aic_outb(p, 0, SCSIRATE); + + /* Select channel A */ + aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); + } + + if (p->features & AHC_ULTRA2) + { + aic_outb(p, p->scsi_id, SCSIID_ULTRA2); + } + else + { + aic_outb(p, p->scsi_id, SCSIID); + } + if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) + term = (aic_inb(p, SXFRCTL1) & STPWEN); + else + term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0); + scsi_conf = aic_inb(p, SCSICONF); + aic_outb(p, DFON | SPIOEN, SXFRCTL0); + aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | + ENSTIMER | ACTNEGEN, SXFRCTL1); + aic_outb(p, 0, SIMODE0); + /* + * If we are a cardbus adapter then don't enable SCSI reset detection. + * We shouldn't likely be sharing SCSI busses with someone else, and + * if we don't have a cable currently plugged into the controller then + * we won't have a power source for the SCSI termination, which means + * we'll see infinite incoming bus resets. + */ + if(p->flags & AHC_NO_STPWEN) + aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1); + else + aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); + aic_outb(p, 0, SCSIRATE); + if ( p->features & AHC_ULTRA2) + aic_outb(p, 0, SCSIOFFSET); + + /* + * Look at the information that board initialization or the board + * BIOS has left us. In the lower four bits of each target's + * scratch space any value other than 0 indicates that we should + * initiate synchronous transfers. If it's zero, the user or the + * BIOS has decided to disable synchronous negotiation to that + * target so we don't activate the needsdtr flag. + */ + if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0) + { + max_targets = 8; + } + else + { + max_targets = 16; + } + + if (!(aic7xxx_no_reset)) + { + /* + * If we reset the bus, then clear the transfer settings, else leave + * them be + */ + for (i = 0; i < max_targets; i++) + { + aic_outb(p, 0, TARG_SCSIRATE + i); + if (p->features & AHC_ULTRA2) + { + aic_outb(p, 0, TARG_OFFSET + i); + } + p->transinfo[i].cur_offset = 0; + p->transinfo[i].cur_period = 0; + p->transinfo[i].cur_width = MSG_EXT_WDTR_BUS_8_BIT; + } + + /* + * If we reset the bus, then clear the transfer settings, else leave + * them be. + */ + aic_outb(p, 0, ULTRA_ENB); + aic_outb(p, 0, ULTRA_ENB + 1); + p->ultraenb = 0; + } + + /* + * Allocate enough hardware scbs to handle the maximum number of + * concurrent transactions we can have. We have to make sure that + * the allocated memory is contiguous memory. The Linux kmalloc + * routine should only allocate contiguous memory, but note that + * this could be a problem if kmalloc() is changed. + */ + { + size_t array_size; + unsigned int hscb_physaddr; + + array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb); + if (p->scb_data->hscbs == NULL) + { + /* pci_alloc_consistent enforces the alignment already and + * clears the area as well. + */ + p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size, + &p->scb_data->hscbs_dma); + /* We have to use pci_free_consistent, not kfree */ + p->scb_data->hscb_kmalloc_ptr = NULL; + p->scb_data->hscbs_dma_len = array_size; + } + if (p->scb_data->hscbs == NULL) + { + printk("(scsi%d) Unable to allocate hardware SCB array; " + "failing detection.\n", p->host_no); + aic_outb(p, 0, SIMODE1); + p->irq = 0; + return(0); + } + + hscb_physaddr = p->scb_data->hscbs_dma; + aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR); + aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1); + aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2); + aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3); + + /* Set up the fifo areas at the same time */ + p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma); + if (p->untagged_scbs == NULL) + { + printk("(scsi%d) Unable to allocate hardware FIFO arrays; " + "failing detection.\n", p->host_no); + p->irq = 0; + return(0); + } + + p->qoutfifo = p->untagged_scbs + 256; + p->qinfifo = p->qoutfifo + 256; + for (i = 0; i < 256; i++) + { + p->untagged_scbs[i] = SCB_LIST_NULL; + p->qinfifo[i] = SCB_LIST_NULL; + p->qoutfifo[i] = SCB_LIST_NULL; + } + + hscb_physaddr = p->fifo_dma; + aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR); + aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1); + aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2); + aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3); + } + + /* The Q-FIFOs we just set up are all empty */ + aic_outb(p, 0, QINPOS); + aic_outb(p, 0, KERNEL_QINPOS); + aic_outb(p, 0, QOUTPOS); + + if(p->features & AHC_QUEUE_REGS) + { + aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA); + aic_outb(p, 0, SDSCB_QOFF); + aic_outb(p, 0, SNSCB_QOFF); + aic_outb(p, 0, HNSCB_QOFF); + } + + /* + * We don't have any waiting selections or disconnected SCBs. + */ + aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); + aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH); + + /* + * Message out buffer starts empty + */ + aic_outb(p, MSG_NOOP, MSG_OUT); + aic_outb(p, MSG_NOOP, LAST_MSG); + + /* + * Set all the other asundry items that haven't been set yet. + * This includes just dumping init values to a lot of registers simply + * to make sure they've been touched and are ready for use parity wise + * speaking. + */ + aic_outb(p, 0, TMODE_CMDADDR); + aic_outb(p, 0, TMODE_CMDADDR + 1); + aic_outb(p, 0, TMODE_CMDADDR + 2); + aic_outb(p, 0, TMODE_CMDADDR + 3); + aic_outb(p, 0, TMODE_CMDADDR_NEXT); + + /* + * Link us into the list of valid hosts + */ + p->next = first_aic7xxx; + first_aic7xxx = p; + + /* + * Allocate the first set of scbs for this controller. This is to stream- + * line code elsewhere in the driver. If we have to check for the existence + * of scbs in certain code sections, it slows things down. However, as + * soon as we register the IRQ for this card, we could get an interrupt that + * includes possibly the SCSI_RSTI interrupt. If we catch that interrupt + * then we are likely to segfault if we don't have at least one chunk of + * SCBs allocated or add checks all through the reset code to make sure + * that the SCBs have been allocated which is an invalid running condition + * and therefore I think it's preferable to simply pre-allocate the first + * chunk of SCBs. + */ + aic7xxx_allocate_scb(p); + + /* + * Load the sequencer program, then re-enable the board - + * resetting the AIC-7770 disables it, leaving the lights + * on with nobody home. + */ + aic7xxx_loadseq(p); + + /* + * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register + */ + aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL); + + if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) + { + aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */ + } + + if ( !(aic7xxx_no_reset) ) + { + if (p->features & AHC_TWIN) + { + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no); + aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); + aic7xxx_reset_current_bus(p); + aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); + } + /* Reset SCSI bus A. */ + if (aic7xxx_verbose & VERBOSE_PROBE2) + { /* In case we are a 3940, 3985, or 7895, print the right channel */ + char *channel = ""; + if (p->flags & AHC_MULTI_CHANNEL) + { + channel = " A"; + if (p->flags & (AHC_CHNLB|AHC_CHNLC)) + channel = (p->flags & AHC_CHNLB) ? " B" : " C"; + } + printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel); + } + + aic7xxx_reset_current_bus(p); + + /* + * Delay for the reset delay by setting the timer, this will delay + * future commands sent to any devices. + */ + p->flags |= AHC_RESET_DELAY; + for(i=0; idev_expires[i] = jiffies + (4 * HZ); + p->dev_timer_active |= (0x01 << i); + } + p->dev_timer.expires = p->dev_expires[p->scsi_id]; + add_timer(&p->dev_timer); + p->dev_timer_active |= (0x01 << MAX_TARGETS); + } + else + { + if (!reset_delay) + { + printk(KERN_INFO "(scsi%d) Not resetting SCSI bus. Note: Don't use " + "the no_reset\n", p->host_no); + printk(KERN_INFO "(scsi%d) option unless you have a verifiable need " + "for it.\n", p->host_no); + } + } + + /* + * Register IRQ with the kernel. Only allow sharing IRQs with + * PCI devices. + */ + if (!(p->chip & AHC_PCI)) + { + result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p)); + } + else + { + result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ, + "aic7xxx", p)); + if (result < 0) + { + result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ, + "aic7xxx", p)); + } + } + if (result < 0) + { + printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring " + "controller.\n", p->host_no, p->irq); + aic_outb(p, 0, SIMODE1); + p->irq = 0; + return (0); + } + + if(aic_inb(p, INTSTAT) & INT_PEND) + printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n", + p->host_no, -1, -1 , -1); + aic7xxx_clear_intstat(p); + + unpause_sequencer(p, /* unpause_always */ TRUE); + + return (found); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_chip_reset + * + * Description: + * Perform a chip reset on the aic7xxx SCSI controller. The controller + * is paused upon return. + *-F*************************************************************************/ +int +aic7xxx_chip_reset(struct aic7xxx_host *p) +{ + unsigned char sblkctl; + int wait; + + /* + * For some 274x boards, we must clear the CHIPRST bit and pause + * the sequencer. For some reason, this makes the driver work. + */ + aic_outb(p, PAUSE | CHIPRST, HCNTRL); + + /* + * In the future, we may call this function as a last resort for + * error handling. Let's be nice and not do any unecessary delays. + */ + wait = 1000; /* 1 msec (1000 * 1 msec) */ + while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK)) + { + udelay(1); /* 1 usec */ + } + + pause_sequencer(p); + + sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE); + if (p->chip & AHC_PCI) + sblkctl &= ~SELBUSB; + switch( sblkctl ) + { + case 0: /* normal narrow card */ + break; + case 2: /* Wide card */ + p->features |= AHC_WIDE; + break; + case 8: /* Twin card */ + p->features |= AHC_TWIN; + p->flags |= AHC_MULTI_CHANNEL; + break; + default: /* hmmm...we don't know what this is */ + printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n", + aic_inb(p, SBLKCTL) & 0x0a); + return(-1); + } + return(0); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_alloc + * + * Description: + * Allocate and initialize a host structure. Returns NULL upon error + * and a pointer to a aic7xxx_host struct upon success. + *-F*************************************************************************/ +static struct aic7xxx_host * +aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp) +{ + struct aic7xxx_host *p = NULL; + struct Scsi_Host *host; + int i; + + /* + * Allocate a storage area by registering us with the mid-level + * SCSI layer. + */ + host = scsi_register(sht, sizeof(struct aic7xxx_host)); + + if (host != NULL) + { + p = (struct aic7xxx_host *) host->hostdata; + memset(p, 0, sizeof(struct aic7xxx_host)); + *p = *temp; + p->host = host; + + p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC); + if (p->scb_data != NULL) + { + memset(p->scb_data, 0, sizeof(scb_data_type)); + scbq_init (&p->scb_data->free_scbs); + } + else + { + /* + * For some reason we don't have enough memory. Free the + * allocated memory for the aic7xxx_host struct, and return NULL. + */ + release_region(p->base, MAXREG - MINREG); + scsi_unregister(host); + return(NULL); + } + p->host_no = host->host_no; + p->tagenable = 0; + p->orderedtag = 0; + for (i=0; itransinfo[i].goal_period = 255; + p->transinfo[i].goal_offset = 0; + p->transinfo[i].goal_options = 0; + p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT; + } + DRIVER_LOCK_INIT + } + return (p); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_free + * + * Description: + * Frees and releases all resources associated with an instance of + * the driver (struct aic7xxx_host *). + *-F*************************************************************************/ +static void +aic7xxx_free(struct aic7xxx_host *p) +{ + int i; + + /* + * Free the allocated hardware SCB space. + */ + if (p->scb_data != NULL) + { + struct aic7xxx_scb_dma *scb_dma = NULL; + if (p->scb_data->hscbs != NULL) + { + pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len, + p->scb_data->hscbs, p->scb_data->hscbs_dma); + p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL; + } + /* + * Free the driver SCBs. These were allocated on an as-need + * basis. We allocated these in groups depending on how many + * we could fit into a given amount of RAM. The tail SCB for + * these allocations has a pointer to the alloced area. + */ + for (i = 0; i < p->scb_data->numscbs; i++) + { + if (p->scb_data->scb_array[i]->scb_dma != scb_dma) + { + scb_dma = p->scb_data->scb_array[i]->scb_dma; + pci_free_consistent(p->pdev, scb_dma->dma_len, + (void *)((unsigned long)scb_dma->dma_address + - scb_dma->dma_offset), + scb_dma->dma_address); + } + if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL) + kfree(p->scb_data->scb_array[i]->kmalloc_ptr); + p->scb_data->scb_array[i] = NULL; + } + + /* + * Free the SCB data area. + */ + kfree(p->scb_data); + } + + /* + * Free any alloced Scsi_Cmnd structures that might be around for + * negotiation purposes.... + */ + for (i = 0; i < MAX_TARGETS; i++) + { + if(p->dev_dtr_cmnd[i]) + { + if(p->dev_dtr_cmnd[i]->request_buffer) + { + kfree(p->dev_dtr_cmnd[i]->request_buffer); + } + kfree(p->dev_dtr_cmnd[i]); + } + } + + pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_load_seeprom + * + * Description: + * Load the seeprom and configure adapter and target settings. + * Returns 1 if the load was successful and 0 otherwise. + *-F*************************************************************************/ +static void +aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1) +{ + int have_seeprom = 0; + int i, max_targets, mask; + unsigned char scsirate, scsi_conf; + unsigned short scarray[128]; + struct seeprom_config *sc = (struct seeprom_config *) scarray; + + if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk(KERN_INFO "aic7xxx: Loading serial EEPROM..."); + } + switch (p->chip) + { + case (AHC_AIC7770|AHC_EISA): /* None of these adapters have seeproms. */ + if (aic_inb(p, SCSICONF) & TERM_ENB) + p->flags |= AHC_TERM_ENB_A; + if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) ) + p->flags |= AHC_TERM_ENB_B; + break; + + case (AHC_AIC7770|AHC_VL): + have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray); + break; + + default: + have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), + scarray, p->sc_size, p->sc_type); + if (!have_seeprom) + { + if(p->sc_type == C46) + have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), + scarray, p->sc_size, C56_66); + else + have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), + scarray, p->sc_size, C46); + } + if (!have_seeprom) + { + p->sc_size = 128; + have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), + scarray, p->sc_size, p->sc_type); + if (!have_seeprom) + { + if(p->sc_type == C46) + have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), + scarray, p->sc_size, C56_66); + else + have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), + scarray, p->sc_size, C46); + } + } + break; + } + + if (!have_seeprom) + { + if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk("\naic7xxx: No SEEPROM available.\n"); + } + p->flags |= AHC_NEWEEPROM_FMT; + if (aic_inb(p, SCSISEQ) == 0) + { + p->flags |= AHC_USEDEFAULTS; + p->flags &= ~AHC_BIOS_ENABLED; + p->scsi_id = p->scsi_id_b = 7; + *sxfrctl1 |= STPWEN; + if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk("aic7xxx: Using default values.\n"); + } + } + else if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk("aic7xxx: Using leftover BIOS values.\n"); + } + if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) ) + { + p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; + sc->adapter_control &= ~CFAUTOTERM; + sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM; + } + if (aic7xxx_extended) + p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); + else + p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); + } + else + { + if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk("done\n"); + } + + /* + * Note things in our flags + */ + p->flags |= AHC_SEEPROM_FOUND; + + /* + * Update the settings in sxfrctl1 to match the termination settings. + */ + *sxfrctl1 = 0; + + /* + * Get our SCSI ID from the SEEPROM setting... + */ + p->scsi_id = (sc->brtime_id & CFSCSIID); + + /* + * First process the settings that are different between the VLB + * and PCI adapter seeproms. + */ + if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770) + { + /* VLB adapter seeproms */ + if (sc->bios_control & CF284XEXTEND) + p->flags |= AHC_EXTEND_TRANS_A; + + if (sc->adapter_control & CF284XSTERM) + { + *sxfrctl1 |= STPWEN; + p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; + } + } + else + { + /* PCI adapter seeproms */ + if (sc->bios_control & CFEXTEND) + p->flags |= AHC_EXTEND_TRANS_A; + if (sc->bios_control & CFBIOSEN) + p->flags |= AHC_BIOS_ENABLED; + else + p->flags &= ~AHC_BIOS_ENABLED; + + if (sc->adapter_control & CFSTERM) + { + *sxfrctl1 |= STPWEN; + p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; + } + } + memcpy(&p->sc, sc, sizeof(struct seeprom_config)); + } + + p->discenable = 0; + + /* + * Limit to 16 targets just in case. The 2842 for one is known to + * blow the max_targets setting, future cards might also. + */ + max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8); + + if (have_seeprom) + { + for (i = 0; i < max_targets; i++) + { + if( ((p->features & AHC_ULTRA) && + !(sc->adapter_control & CFULTRAEN) && + (sc->device_flags[i] & CFSYNCHISULTRA)) || + (sc->device_flags[i] & CFNEWULTRAFORMAT) ) + { + p->flags |= AHC_NEWEEPROM_FMT; + break; + } + } + } + + for (i = 0; i < max_targets; i++) + { + mask = (0x01 << i); + if (!have_seeprom) + { + if (aic_inb(p, SCSISEQ) != 0) + { + /* + * OK...the BIOS set things up and left behind the settings we need. + * Just make our sc->device_flags[i] entry match what the card has + * set for this device. + */ + p->discenable = + ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) ); + p->ultraenb = + (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) ); + sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0; + if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) + sc->device_flags[i] |= CFWIDEB; + if (p->features & AHC_ULTRA2) + { + if (aic_inb(p, TARG_OFFSET + i)) + { + sc->device_flags[i] |= CFSYNCH; + sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07); + if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 ) + sc->device_flags[i] |= CFSYNCHISULTRA; + } + } + else + { + if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER) + { + sc->device_flags[i] |= CFSYNCH; + if (p->features & AHC_ULTRA) + sc->device_flags[i] |= ((p->ultraenb & mask) ? + CFSYNCHISULTRA : 0); + } + } + } + else + { + /* + * Assume the BIOS has NOT been run on this card and nothing between + * the card and the devices is configured yet. + */ + sc->device_flags[i] = CFDISC; + if (p->features & AHC_WIDE) + sc->device_flags[i] |= CFWIDEB; + if (p->features & AHC_ULTRA3) + sc->device_flags[i] |= 2; + else if (p->features & AHC_ULTRA2) + sc->device_flags[i] |= 3; + else if (p->features & AHC_ULTRA) + sc->device_flags[i] |= CFSYNCHISULTRA; + sc->device_flags[i] |= CFSYNCH; + aic_outb(p, 0, TARG_SCSIRATE + i); + if (p->features & AHC_ULTRA2) + aic_outb(p, 0, TARG_OFFSET + i); + } + } + if (sc->device_flags[i] & CFDISC) + { + p->discenable |= mask; + } + if (p->flags & AHC_NEWEEPROM_FMT) + { + if ( !(p->features & AHC_ULTRA2) ) + { + /* + * I know of two different Ultra BIOSes that do this differently. + * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to + * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s + * while on the IBM Netfinity 5000 they want the same thing + * to be something else, while flags[i] & CFXFER == 0x03 and + * SYNCHISULTRA false should be 40MByte/s. So, we set both to + * 40MByte/s and the lower speeds be damned. People will have + * to select around the conversely mapped lower speeds in order + * to select lower speeds on these boards. + */ + if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && + ((sc->device_flags[i] & CFXFER) == 0x03) ) + { + sc->device_flags[i] &= ~CFXFER; + sc->device_flags[i] |= CFSYNCHISULTRA; + } + if (sc->device_flags[i] & CFSYNCHISULTRA) + { + p->ultraenb |= mask; + } + } + else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) && + (p->features & AHC_ULTRA2) && + (sc->device_flags[i] & CFSYNCHISULTRA) ) + { + p->ultraenb |= mask; + } + } + else if (sc->adapter_control & CFULTRAEN) + { + p->ultraenb |= mask; + } + if ( (sc->device_flags[i] & CFSYNCH) == 0) + { + sc->device_flags[i] &= ~CFXFER; + p->ultraenb &= ~mask; + p->transinfo[i].user_offset = 0; + p->transinfo[i].user_period = 0; + p->transinfo[i].user_options = 0; + p->transinfo[i].cur_offset = 0; + p->transinfo[i].cur_period = 0; + p->transinfo[i].cur_options = 0; + p->needsdtr_copy &= ~mask; + } + else + { + if (p->features & AHC_ULTRA3) + { + p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2; + p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i); + if( (sc->device_flags[i] & CFXFER) < 0x03 ) + { + scsirate = (sc->device_flags[i] & CFXFER); + p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC; + if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 ) + { + p->transinfo[i].cur_options = + ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ? + MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS); + } + else + { + p->transinfo[i].cur_options = 0; + } + } + else + { + scsirate = (sc->device_flags[i] & CFXFER) | + ((p->ultraenb & mask) ? 0x18 : 0x10); + p->transinfo[i].user_options = 0; + p->transinfo[i].cur_options = 0; + } + p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate, + AHC_SYNCRATE_ULTRA3); + p->transinfo[i].cur_period = aic7xxx_find_period(p, + aic_inb(p, TARG_SCSIRATE + i), + AHC_SYNCRATE_ULTRA3); + } + else if (p->features & AHC_ULTRA2) + { + p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2; + p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i); + scsirate = (sc->device_flags[i] & CFXFER) | + ((p->ultraenb & mask) ? 0x18 : 0x10); + p->transinfo[i].user_options = 0; + p->transinfo[i].cur_options = 0; + p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate, + AHC_SYNCRATE_ULTRA2); + p->transinfo[i].cur_period = aic7xxx_find_period(p, + aic_inb(p, TARG_SCSIRATE + i), + AHC_SYNCRATE_ULTRA2); + } + else + { + scsirate = (sc->device_flags[i] & CFXFER) << 4; + p->transinfo[i].user_options = 0; + p->transinfo[i].cur_options = 0; + p->transinfo[i].user_offset = MAX_OFFSET_8BIT; + if (p->features & AHC_ULTRA) + { + short ultraenb; + ultraenb = aic_inb(p, ULTRA_ENB) | + (aic_inb(p, ULTRA_ENB + 1) << 8); + p->transinfo[i].user_period = aic7xxx_find_period(p, + scsirate, + (p->ultraenb & mask) ? + AHC_SYNCRATE_ULTRA : + AHC_SYNCRATE_FAST); + p->transinfo[i].cur_period = aic7xxx_find_period(p, + aic_inb(p, TARG_SCSIRATE + i), + (ultraenb & mask) ? + AHC_SYNCRATE_ULTRA : + AHC_SYNCRATE_FAST); + } + else + p->transinfo[i].user_period = aic7xxx_find_period(p, + scsirate, AHC_SYNCRATE_FAST); + } + p->needsdtr_copy |= mask; + } + if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) ) + { + p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_16_BIT; + p->needwdtr_copy |= mask; + } + else + { + p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_8_BIT; + p->needwdtr_copy &= ~mask; + } + p->transinfo[i].cur_width = + (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) ? + MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT; + } + aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB); + aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1); + p->needppr = p->needppr_copy = p->needdv = 0; + p->needwdtr = p->needwdtr_copy; + p->needsdtr = p->needsdtr_copy; + p->dtr_pending = 0; + + /* + * We set the p->ultraenb from the SEEPROM to begin with, but now we make + * it match what is already down in the card. If we are doing a reset + * on the card then this will get put back to a default state anyway. + * This allows us to not have to pre-emptively negotiate when using the + * no_reset option. + */ + if (p->features & AHC_ULTRA) + p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8); + + + scsi_conf = (p->scsi_id & HSCSIID); + + if(have_seeprom) + { + p->adapter_control = sc->adapter_control; + p->bios_control = sc->bios_control; + + switch (p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7895: + case AHC_AIC7896: + case AHC_AIC7899: + if (p->adapter_control & CFBPRIMARY) + p->flags |= AHC_CHANNEL_B_PRIMARY; + default: + break; + } + + if (sc->adapter_control & CFSPARITY) + scsi_conf |= ENSPCHK; + } + else + { + scsi_conf |= ENSPCHK | RESET_SCSI; + } + + /* + * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card. + * The 2842 and 2742 cards already have these registers set and we don't + * want to muck with them since we don't set all the bits they do. + */ + if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) + { + /* Set the host ID */ + aic_outb(p, scsi_conf, SCSICONF); + /* In case we are a wide card */ + aic_outb(p, p->scsi_id, SCSICONF + 1); + } +} + +/*+F************************************************************************* + * Function: + * aic7xxx_detect + * + * Description: + * Try to detect and register an Adaptec 7770 or 7870 SCSI controller. + * + * XXX - This should really be called aic7xxx_probe(). A sequence of + * probe(), attach()/detach(), and init() makes more sense than + * one do-it-all function. This may be useful when (and if) the + * mid-level SCSI code is overhauled. + *-F*************************************************************************/ +int +aic7xxx_detect(Scsi_Host_Template *template) +{ + struct aic7xxx_host *temp_p = NULL; + struct aic7xxx_host *current_p = NULL; + struct aic7xxx_host *list_p = NULL; + int found = 0; +#if defined(__i386__) || defined(__alpha__) + ahc_flag_type flags = 0; + int type; +#endif + unsigned char sxfrctl1; +#if defined(__i386__) || defined(__alpha__) + unsigned char hcntrl, hostconf; + unsigned int slot, base; +#endif + +#ifdef MODULE + /* + * If we are called as a module, the aic7xxx pointer may not be null + * and it would point to our bootup string, just like on the lilo + * command line. IF not NULL, then process this config string with + * aic7xxx_setup + */ + if(aic7xxx) + aic7xxx_setup(aic7xxx); + if(dummy_buffer[0] != 'P') + printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers" + "/scsi/README.aic7xxx\n" + "aic7xxx: to see the proper way to specify options to the aic7xxx " + "module\n" + "aic7xxx: Specifically, don't use any commas when passing arguments to\n" + "aic7xxx: insmod or else it might trash certain memory areas.\n"); +#endif + + template->proc_name = "aic7xxx"; + template->sg_tablesize = AIC7XXX_MAX_SG; + + +#ifdef CONFIG_PCI + /* + * PCI-bus probe. + */ + if (pci_present()) + { + struct + { + unsigned short vendor_id; + unsigned short device_id; + ahc_chip chip; + ahc_flag_type flags; + ahc_feature features; + int board_name_index; + unsigned short seeprom_size; + unsigned short seeprom_type; + } const aic_pdevs[] = { + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE, + AHC_FNONE, AHC_FENONE, 1, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850, + AHC_PAGESCBS, AHC_AIC7850_FE, 5, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850, + AHC_PAGESCBS, AHC_AIC7850_FE, 6, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 7, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 7, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 7, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 7, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, + AHC_AIC7860_FE, 7, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7860_FE, 8, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870, + AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, + AHC_AIC7870_FE, 9, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 10, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870, + AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7870_FE, 11, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870, + AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7870_FE, 12, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 13, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, + AHC_AIC7880_FE, 14, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 15, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7880_FE, 16, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7880_FE, 17, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880, + AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7895_FE, 20, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7890_FE, 21, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7890_FE, 21, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7890_FE, 22, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7890_FE, 23, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7896_FE, 24, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7896_FE, 25, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7896_FE, 26, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN, + AHC_AIC7860_FE, 27, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7892_FE, 28, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7892_FE, 28, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7892_FE, 28, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, + AHC_AIC7892_FE, 28, + 32, C46 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7899_FE, 29, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7899_FE, 29, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7899_FE, 29, + 32, C56_66 }, + {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899, + AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, + AHC_AIC7899_FE, 29, + 32, C56_66 }, + }; + + unsigned short command; + unsigned int devconfig, i, oldverbose; + struct pci_dev *pdev = NULL; + + for (i = 0; i < NUMBER(aic_pdevs); i++) + { + pdev = NULL; + while ((pdev = pci_find_device(aic_pdevs[i].vendor_id, + aic_pdevs[i].device_id, + pdev))) { + if (pci_enable_device(pdev)) + continue; + if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */ + { + if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2)) + { + printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not " + "supported by\n"); + printk(KERN_INFO " this driver, we are ignoring it.\n"); + } + } + else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host), + GFP_ATOMIC)) != NULL ) + { + memset(temp_p, 0, sizeof(struct aic7xxx_host)); + temp_p->chip = aic_pdevs[i].chip | AHC_PCI; + temp_p->flags = aic_pdevs[i].flags; + temp_p->features = aic_pdevs[i].features; + temp_p->board_name_index = aic_pdevs[i].board_name_index; + temp_p->sc_size = aic_pdevs[i].seeprom_size; + temp_p->sc_type = aic_pdevs[i].seeprom_type; + + /* + * Read sundry information from PCI BIOS. + */ + temp_p->irq = pdev->irq; + temp_p->pdev = pdev; + temp_p->pci_bus = pdev->bus->number; + temp_p->pci_device_fn = pdev->devfn; + temp_p->base = pci_resource_start(pdev, 0); + temp_p->mbase = pci_resource_start(pdev, 1); + current_p = list_p; + while(current_p && temp_p) + { + if ( ((current_p->pci_bus == temp_p->pci_bus) && + (current_p->pci_device_fn == temp_p->pci_device_fn)) || + (temp_p->base && (current_p->base == temp_p->base)) || + (temp_p->mbase && (current_p->mbase == temp_p->mbase)) ) + { + /* duplicate PCI entry, skip it */ + kfree(temp_p); + temp_p = NULL; + } + current_p = current_p->next; + } + if ( temp_p == NULL ) + continue; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk("aic7xxx: <%s> at PCI %d/%d\n", + board_names[aic_pdevs[i].board_name_index], + PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + pci_read_config_word(pdev, PCI_COMMAND, &command); + if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n", + (int)command); + } +#ifdef AIC7XXX_STRICT_PCI_SETUP + command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | + PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; +#else + command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; +#endif + command &= ~PCI_COMMAND_INVALIDATE; + if (aic7xxx_pci_parity == 0) + command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); + pci_write_config_word(pdev, PCI_COMMAND, command); +#ifdef AIC7XXX_STRICT_PCI_SETUP + pci_read_config_dword(pdev, DEVCONFIG, &devconfig); + if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig); + } + devconfig |= 0x80000040; + pci_write_config_dword(pdev, DEVCONFIG, devconfig); +#endif /* AIC7XXX_STRICT_PCI_SETUP */ + + if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG)) + { + printk("aic7xxx: <%s> at PCI %d/%d/%d\n", + board_names[aic_pdevs[i].board_name_index], + temp_p->pci_bus, + PCI_SLOT(temp_p->pci_device_fn), + PCI_FUNC(temp_p->pci_device_fn)); + printk("aic7xxx: I/O ports already in use, ignoring.\n"); + kfree(temp_p); + temp_p = NULL; + continue; + } + + temp_p->unpause = INTEN; + temp_p->pause = temp_p->unpause | PAUSE; + if ( ((temp_p->base == 0) && + (temp_p->mbase == 0)) || + (temp_p->irq == 0) ) + { + printk("aic7xxx: <%s> at PCI %d/%d/%d\n", + board_names[aic_pdevs[i].board_name_index], + temp_p->pci_bus, + PCI_SLOT(temp_p->pci_device_fn), + PCI_FUNC(temp_p->pci_device_fn)); + printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); + kfree(temp_p); + temp_p = NULL; + continue; + } + +#ifdef MMAPIO + if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) || + ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) && + (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) ) + { + unsigned long page_offset, base; + + base = temp_p->mbase & PAGE_MASK; + page_offset = temp_p->mbase - base; + temp_p->maddr = ioremap_nocache(base, page_offset + 256); + if(temp_p->maddr) + { + temp_p->maddr += page_offset; + /* + * We need to check the I/O with the MMAPed address. Some machines + * simply fail to work with MMAPed I/O and certain controllers. + */ + if(aic_inb(temp_p, HCNTRL) == 0xff) + { + /* + * OK.....we failed our test....go back to programmed I/O + */ + printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", + board_names[aic_pdevs[i].board_name_index], + temp_p->pci_bus, + PCI_SLOT(temp_p->pci_device_fn), + PCI_FUNC(temp_p->pci_device_fn)); + printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to " + "Programmed I/O.\n"); + iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK)); + temp_p->maddr = 0; + if(temp_p->base == 0) + { + printk("aic7xxx: <%s> at PCI %d/%d/%d\n", + board_names[aic_pdevs[i].board_name_index], + temp_p->pci_bus, + PCI_SLOT(temp_p->pci_device_fn), + PCI_FUNC(temp_p->pci_device_fn)); + printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); + kfree(temp_p); + temp_p = NULL; + continue; + } + } + } + } +#endif + + /* + * Lock out other contenders for our i/o space. + */ + if(temp_p->base) + request_region(temp_p->base, MAXREG - MINREG, "aic7xxx"); + + /* + * We HAVE to make sure the first pause_sequencer() and all other + * subsequent I/O that isn't PCI config space I/O takes place + * after the MMAPed I/O region is configured and tested. The + * problem is the PowerPC architecture that doesn't support + * programmed I/O at all, so we have to have the MMAP I/O set up + * for this pause to even work on those machines. + */ + pause_sequencer(temp_p); + + /* + * Clear out any pending PCI error status messages. Also set + * verbose to 0 so that we don't emit strange PCI error messages + * while cleaning out the current status bits. + */ + oldverbose = aic7xxx_verbose; + aic7xxx_verbose = 0; + aic7xxx_pci_intr(temp_p); + aic7xxx_verbose = oldverbose; + + temp_p->bios_address = 0; + + /* + * Remember how the card was setup in case there is no seeprom. + */ + if (temp_p->features & AHC_ULTRA2) + temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID; + else + temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID; + /* + * Get current termination setting + */ + sxfrctl1 = aic_inb(temp_p, SXFRCTL1); + + if (aic7xxx_chip_reset(temp_p) == -1) + { + release_region(temp_p->base, MAXREG - MINREG); + kfree(temp_p); + temp_p = NULL; + continue; + } + /* + * Very quickly put the term setting back into the register since + * the chip reset may cause odd things to happen. This is to keep + * LVD busses with lots of drives from draining the power out of + * the diffsense line before we get around to running the + * configure_termination() function. Also restore the STPWLEVEL + * bit of DEVCONFIG + */ + aic_outb(temp_p, sxfrctl1, SXFRCTL1); + pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig); + sxfrctl1 &= STPWEN; + + /* + * We need to set the CHNL? assignments before loading the SEEPROM + * The 3940 and 3985 cards (original stuff, not any of the later + * stuff) are 7870 and 7880 class chips. The Ultra2 stuff falls + * under 7896 and 7897. The 7895 is in a class by itself :) + */ + switch (temp_p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7870: /* 3840 / 3985 */ + case AHC_AIC7880: /* 3840 UW / 3985 UW */ + if(temp_p->flags & AHC_MULTI_CHANNEL) + { + switch(PCI_SLOT(temp_p->pci_device_fn)) + { + case 5: + temp_p->flags |= AHC_CHNLB; + break; + case 8: + temp_p->flags |= AHC_CHNLB; + break; + case 12: + temp_p->flags |= AHC_CHNLC; + break; + default: + break; + } + } + break; + + case AHC_AIC7895: /* 7895 */ + case AHC_AIC7896: /* 7896/7 */ + case AHC_AIC7899: /* 7899 */ + if (PCI_FUNC(pdev->devfn) != 0) + { + temp_p->flags |= AHC_CHNLB; + } + /* + * The 7895 is the only chipset that sets the SCBSIZE32 param + * in the DEVCONFIG register. The Ultra2 chipsets use + * the DSCOMMAND0 register instead. + */ + if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) + { + pci_read_config_dword(pdev, DEVCONFIG, &devconfig); + devconfig |= SCBSIZE32; + pci_write_config_dword(pdev, DEVCONFIG, devconfig); + } + break; + default: + break; + } + + /* + * Loading of the SEEPROM needs to come after we've set the flags + * to indicate possible CHNLB and CHNLC assigments. Otherwise, + * on 394x and 398x cards we'll end up reading the wrong settings + * for channels B and C + */ + switch (temp_p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7892: + case AHC_AIC7899: + aic_outb(temp_p, 0, SCAMCTL); + /* + * Switch to the alt mode of the chip... + */ + aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT); + /* + * Set our options...the last two items set our CRC after x byte + * count in target mode... + */ + aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE); + aic_outb(temp_p, 0x00, 0x0b); + aic_outb(temp_p, 0x10, 0x0a); + /* + * switch back to normal mode... + */ + aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT); + aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN | + TARGCRCENDEN | TARGCRCCNTEN, + CRCCONTROL1); + aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 | + MPARCKEN | CIOPARCKEN | CACHETHEN) & + ~DPARCKEN), DSCOMMAND0); + aic7xxx_load_seeprom(temp_p, &sxfrctl1); + break; + case AHC_AIC7890: + case AHC_AIC7896: + aic_outb(temp_p, 0, SCAMCTL); + aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | + CACHETHEN | MPARCKEN | USCBSIZE32 | + CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0); + aic7xxx_load_seeprom(temp_p, &sxfrctl1); + break; + case AHC_AIC7850: + case AHC_AIC7860: + /* + * Set the DSCOMMAND0 register on these cards different from + * on the 789x cards. Also, read the SEEPROM as well. + */ + aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | + CACHETHEN | MPARCKEN) & ~DPARCKEN, + DSCOMMAND0); + /* FALLTHROUGH */ + default: + aic7xxx_load_seeprom(temp_p, &sxfrctl1); + break; + case AHC_AIC7880: + /* + * Check the rev of the chipset before we change DSCOMMAND0 + */ + pci_read_config_dword(pdev, DEVCONFIG, &devconfig); + if ((devconfig & 0xff) >= 1) + { + aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | + CACHETHEN | MPARCKEN) & ~DPARCKEN, + DSCOMMAND0); + } + aic7xxx_load_seeprom(temp_p, &sxfrctl1); + break; + } + + + /* + * and then we need another switch based on the type in order to + * make sure the channel B primary flag is set properly on 7895 + * controllers....Arrrgggghhh!!! We also have to catch the fact + * that when you disable the BIOS on the 7895 on the Intel DK440LX + * motherboard, and possibly others, it only sets the BIOS disabled + * bit on the A channel...I think I'm starting to lean towards + * going postal.... + */ + switch(temp_p->chip & AHC_CHIPID_MASK) + { + case AHC_AIC7895: + case AHC_AIC7896: + case AHC_AIC7899: + current_p = list_p; + while(current_p != NULL) + { + if ( (current_p->pci_bus == temp_p->pci_bus) && + (PCI_SLOT(current_p->pci_device_fn) == + PCI_SLOT(temp_p->pci_device_fn)) ) + { + if ( PCI_FUNC(current_p->pci_device_fn) == 0 ) + { + temp_p->flags |= + (current_p->flags & AHC_CHANNEL_B_PRIMARY); + temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS); + temp_p->flags |= + (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS)); + } + else + { + current_p->flags |= + (temp_p->flags & AHC_CHANNEL_B_PRIMARY); + current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS); + current_p->flags |= + (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS)); + } + } + current_p = current_p->next; + } + break; + default: + break; + } + + /* + * We only support external SCB RAM on the 7895/6/7 chipsets. + * We could support it on the 7890/1 easy enough, but I don't + * know of any 7890/1 based cards that have it. I do know + * of 7895/6/7 cards that have it and they work properly. + */ + switch(temp_p->chip & AHC_CHIPID_MASK) + { + default: + break; + case AHC_AIC7895: + case AHC_AIC7896: + case AHC_AIC7899: + pci_read_config_dword(pdev, DEVCONFIG, &devconfig); + if (temp_p->features & AHC_ULTRA2) + { + if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) && + (aic7xxx_scbram) ) + { + aic_outb(temp_p, + aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2, + DSCOMMAND0); + temp_p->flags |= AHC_EXTERNAL_SRAM; + devconfig |= EXTSCBPEN; + } + else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) + { + printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", + board_names[aic_pdevs[i].board_name_index], + temp_p->pci_bus, + PCI_SLOT(temp_p->pci_device_fn), + PCI_FUNC(temp_p->pci_device_fn)); + printk("aic7xxx: external SCB RAM detected, " + "but not enabled\n"); + } + } + else + { + if ((devconfig & RAMPSM) && (aic7xxx_scbram)) + { + devconfig &= ~SCBRAMSEL; + devconfig |= EXTSCBPEN; + temp_p->flags |= AHC_EXTERNAL_SRAM; + } + else if (devconfig & RAMPSM) + { + printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", + board_names[aic_pdevs[i].board_name_index], + temp_p->pci_bus, + PCI_SLOT(temp_p->pci_device_fn), + PCI_FUNC(temp_p->pci_device_fn)); + printk("aic7xxx: external SCB RAM detected, " + "but not enabled\n"); + } + } + pci_write_config_dword(pdev, DEVCONFIG, devconfig); + if ( (temp_p->flags & AHC_EXTERNAL_SRAM) && + (temp_p->flags & AHC_CHNLB) ) + aic_outb(temp_p, 1, CCSCBBADDR); + break; + } + + /* + * Take the LED out of diagnostic mode + */ + aic_outb(temp_p, + (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)), + SBLKCTL); + + /* + * We don't know where this is set in the SEEPROM or by the + * BIOS, so we default to 100%. On Ultra2 controllers, use 75% + * instead. + */ + if (temp_p->features & AHC_ULTRA2) + { + aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH); + } + else + { + aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS); + } + + if ( list_p == NULL ) + { + list_p = current_p = temp_p; + } + else + { + current_p = list_p; + while(current_p->next != NULL) + current_p = current_p->next; + current_p->next = temp_p; + } + temp_p->next = NULL; + found++; + } /* Found an Adaptec PCI device. */ + else /* Well, we found one, but we couldn't get any memory */ + { + printk("aic7xxx: Found <%s>\n", + board_names[aic_pdevs[i].board_name_index]); + printk(KERN_INFO "aic7xxx: Unable to allocate device memory, " + "skipping.\n"); + } + } /* while(pdev=....) */ + } /* for PCI_DEVICES */ + } /* PCI BIOS present */ +#endif CONFIG_PCI + +#if defined(__i386__) || defined(__alpha__) + /* + * EISA/VL-bus card signature probe. + */ + slot = MINSLOT; + while ( (slot <= MAXSLOT) && + !(aic7xxx_no_probe) ) + { + base = SLOTBASE(slot) + MINREG; + + if (check_region(base, MAXREG - MINREG)) + { + /* + * Some other driver has staked a + * claim to this i/o region already. + */ + slot++; + continue; /* back to the beginning of the for loop */ + } + flags = 0; + type = aic7xxx_probe(slot, base + AHC_HID0, &flags); + if (type == -1) + { + slot++; + continue; + } + temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC); + if (temp_p == NULL) + { + printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n"); + slot++; + continue; /* back to the beginning of the while loop */ + } + /* + * Lock out other contenders for our i/o space. + */ + request_region(base, MAXREG - MINREG, "aic7xxx"); + + /* + * Pause the card preserving the IRQ type. Allow the operator + * to override the IRQ trigger. + */ + if (aic7xxx_irq_trigger == 1) + hcntrl = IRQMS; /* Level */ + else if (aic7xxx_irq_trigger == 0) + hcntrl = 0; /* Edge */ + else + hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */ + memset(temp_p, 0, sizeof(struct aic7xxx_host)); + temp_p->unpause = hcntrl | INTEN; + temp_p->pause = hcntrl | PAUSE | INTEN; + temp_p->base = base; + temp_p->mbase = 0; + temp_p->maddr = 0; + temp_p->pci_bus = 0; + temp_p->pci_device_fn = slot; + aic_outb(temp_p, hcntrl | PAUSE, HCNTRL); + while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ; + if (aic7xxx_chip_reset(temp_p) == -1) + temp_p->irq = 0; + else + temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F; + temp_p->flags |= AHC_PAGESCBS; + + switch (temp_p->irq) + { + case 9: + case 10: + case 11: + case 12: + case 14: + case 15: + break; + + default: + printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ " + "level %d, ignoring.\n", temp_p->irq); + kfree(temp_p); + release_region(base, MAXREG - MINREG); + slot++; + continue; /* back to the beginning of the while loop */ + } + + /* + * We are commited now, everything has been checked and this card + * has been found, now we just set it up + */ + + /* + * Insert our new struct into the list at the end + */ + if (list_p == NULL) + { + list_p = current_p = temp_p; + } + else + { + current_p = list_p; + while (current_p->next != NULL) + current_p = current_p->next; + current_p->next = temp_p; + } + + switch (type) + { + case 0: + temp_p->board_name_index = 2; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk("aic7xxx: <%s> at EISA %d\n", + board_names[2], slot); + /* FALLTHROUGH */ + case 1: + { + temp_p->chip = AHC_AIC7770 | AHC_EISA; + temp_p->features |= AHC_AIC7770_FE; + temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL); + + /* + * Get the primary channel information. Right now we don't + * do anything with this, but someday we will be able to inform + * the mid-level SCSI code which channel is primary. + */ + if (temp_p->board_name_index == 0) + { + temp_p->board_name_index = 3; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk("aic7xxx: <%s> at EISA %d\n", + board_names[3], slot); + } + if (temp_p->bios_control & CHANNEL_B_PRIMARY) + { + temp_p->flags |= AHC_CHANNEL_B_PRIMARY; + } + + if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED) + { + temp_p->flags &= ~AHC_BIOS_ENABLED; + } + else + { + temp_p->flags &= ~AHC_USEDEFAULTS; + temp_p->flags |= AHC_BIOS_ENABLED; + if ( (temp_p->bios_control & 0x20) == 0 ) + { + temp_p->bios_address = 0xcc000; + temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07)); + } + else + { + temp_p->bios_address = 0xd0000; + temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06)); + } + } + temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8; + temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1); + if (temp_p->features & AHC_WIDE) + { + temp_p->scsi_id = temp_p->adapter_control & HWSCSIID; + temp_p->scsi_id_b = temp_p->scsi_id; + } + else + { + temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID; + temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID; + } + aic7xxx_load_seeprom(temp_p, &sxfrctl1); + break; + } + + case 2: + case 3: + temp_p->chip = AHC_AIC7770 | AHC_VL; + temp_p->features |= AHC_AIC7770_FE; + if (type == 2) + temp_p->flags |= AHC_BIOS_ENABLED; + else + temp_p->flags &= ~AHC_BIOS_ENABLED; + if (aic_inb(temp_p, SCSICONF) & TERM_ENB) + sxfrctl1 = STPWEN; + aic7xxx_load_seeprom(temp_p, &sxfrctl1); + temp_p->board_name_index = 4; + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk("aic7xxx: <%s> at VLB %d\n", + board_names[2], slot); + switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL ) + { + case 0x00: + temp_p->bios_address = 0xe0000; + break; + case 0x20: + temp_p->bios_address = 0xc8000; + break; + case 0x40: + temp_p->bios_address = 0xd0000; + break; + case 0x60: + temp_p->bios_address = 0xd8000; + break; + default: + break; /* can't get here */ + } + break; + + default: /* Won't get here. */ + break; + } + if (aic7xxx_verbose & VERBOSE_PROBE2) + { + printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n", + (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base, + temp_p->irq, + (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered"); + printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n", + (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis"); + } + + /* + * Set the FIFO threshold and the bus off time. + */ + hostconf = aic_inb(temp_p, HOSTCONF); + aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD); + aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME); + slot++; + found++; + } + +#endif /* defined(__i386__) || defined(__alpha__) */ + + /* + * Now, we re-order the probed devices by BIOS address and BUS class. + * In general, we follow this algorithm to make the adapters show up + * in the same order under linux that the computer finds them. + * 1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS + * address, going from lowest to highest. + * 2: All PCI controllers with BIOS_ENABLED next, according to BIOS + * address, going from lowest to highest. + * 3: Remaining VLB/EISA controllers going in slot order. + * 4: Remaining PCI controllers, going in PCI device order (reversable) + */ + + { + struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL }; + struct aic7xxx_host *vlb, *pci; + struct aic7xxx_host *prev_p; + struct aic7xxx_host *p; + unsigned char left; + + prev_p = vlb = pci = NULL; + + temp_p = list_p; + while (temp_p != NULL) + { + switch(temp_p->chip & ~AHC_CHIPID_MASK) + { + case AHC_EISA: + case AHC_VL: + { + p = temp_p; + if (p->flags & AHC_BIOS_ENABLED) + vlb = sort_list[0]; + else + vlb = sort_list[2]; + + if (vlb == NULL) + { + vlb = temp_p; + temp_p = temp_p->next; + vlb->next = NULL; + } + else + { + current_p = vlb; + prev_p = NULL; + while ( (current_p != NULL) && + (current_p->bios_address < temp_p->bios_address)) + { + prev_p = current_p; + current_p = current_p->next; + } + if (prev_p != NULL) + { + prev_p->next = temp_p; + temp_p = temp_p->next; + prev_p->next->next = current_p; + } + else + { + vlb = temp_p; + temp_p = temp_p->next; + vlb->next = current_p; + } + } + + if (p->flags & AHC_BIOS_ENABLED) + sort_list[0] = vlb; + else + sort_list[2] = vlb; + + break; + } + default: /* All PCI controllers fall through to default */ + { + + p = temp_p; + if (p->flags & AHC_BIOS_ENABLED) + pci = sort_list[1]; + else + pci = sort_list[3]; + + if (pci == NULL) + { + pci = temp_p; + temp_p = temp_p->next; + pci->next = NULL; + } + else + { + current_p = pci; + prev_p = NULL; + if (!aic7xxx_reverse_scan) + { + while ( (current_p != NULL) && + ( (PCI_SLOT(current_p->pci_device_fn) | + (current_p->pci_bus << 8)) < + (PCI_SLOT(temp_p->pci_device_fn) | + (temp_p->pci_bus << 8)) ) ) + { + prev_p = current_p; + current_p = current_p->next; + } + } + else + { + while ( (current_p != NULL) && + ( (PCI_SLOT(current_p->pci_device_fn) | + (current_p->pci_bus << 8)) > + (PCI_SLOT(temp_p->pci_device_fn) | + (temp_p->pci_bus << 8)) ) ) + { + prev_p = current_p; + current_p = current_p->next; + } + } + /* + * Are we dealing with a 7895/6/7/9 where we need to sort the + * channels as well, if so, the bios_address values should + * be the same + */ + if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) && + (temp_p->pci_bus == current_p->pci_bus) && + (PCI_SLOT(temp_p->pci_device_fn) == + PCI_SLOT(current_p->pci_device_fn)) ) + { + if (temp_p->flags & AHC_CHNLB) + { + if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) ) + { + prev_p = current_p; + current_p = current_p->next; + } + } + else + { + if (temp_p->flags & AHC_CHANNEL_B_PRIMARY) + { + prev_p = current_p; + current_p = current_p->next; + } + } + } + if (prev_p != NULL) + { + prev_p->next = temp_p; + temp_p = temp_p->next; + prev_p->next->next = current_p; + } + else + { + pci = temp_p; + temp_p = temp_p->next; + pci->next = current_p; + } + } + + if (p->flags & AHC_BIOS_ENABLED) + sort_list[1] = pci; + else + sort_list[3] = pci; + + break; + } + } /* End of switch(temp_p->type) */ + } /* End of while (temp_p != NULL) */ + /* + * At this point, the cards have been broken into 4 sorted lists, now + * we run through the lists in order and register each controller + */ + { + int i; + + left = found; + for (i=0; iname = board_names[temp_p->board_name_index]; + p = aic7xxx_alloc(template, temp_p); + if (p != NULL) + { + p->instance = found - left; + if (aic7xxx_register(template, p, (--left)) == 0) + { + found--; + aic7xxx_release(p->host); + scsi_unregister(p->host); + } + else if (aic7xxx_dump_card) + { + pause_sequencer(p); + aic7xxx_print_card(p); + aic7xxx_print_scratch_ram(p); + unpause_sequencer(p, TRUE); + } + } + current_p = temp_p; + temp_p = (struct aic7xxx_host *)temp_p->next; + kfree(current_p); + } + } + } + } + return (found); +} + +static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, + Scsi_Cmnd *old_cmd, int tindex); + +/*+F************************************************************************* + * Function: + * aic7xxx_allocate_negotiation_command + * + * Description: + * allocate the actual command struct and fill in the gaps... + *-F*************************************************************************/ +static Scsi_Cmnd * +aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p, + Scsi_Cmnd *old_cmd, int tindex) +{ + Scsi_Cmnd *cmd; + char *buffer; + + if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) ) + { + return(NULL); + } + if (!(buffer = kmalloc(256, GFP_ATOMIC))) + { + kfree(p->dev_dtr_cmnd[tindex]); + p->dev_dtr_cmnd[tindex] = NULL; + return(NULL); + } + cmd = p->dev_dtr_cmnd[tindex]; + memset(cmd, 0, sizeof(Scsi_Cmnd)); + memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd)); + memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd)); + memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd)); + cmd->lun = 0; + cmd->request_bufflen = 255; + cmd->request_buffer = buffer; + cmd->sc_data_direction = SCSI_DATA_READ; + cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0; + cmd->bufflen = 0; + cmd->buffer = NULL; + cmd->underflow = 0; + cmd->cmd_len = 6; + cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY; + cmd->cmnd[1] = cmd->data_cmnd[1] = 0; + cmd->cmnd[2] = cmd->data_cmnd[2] = 0; + cmd->cmnd[3] = cmd->data_cmnd[3] = 0; + cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */ + cmd->cmnd[5] = cmd->data_cmnd[5] = 0; + return(cmd); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_negotiation_complete + * + * Description: + * Handle completion events for our Negotiation commands. Clear out the + * struct and get it ready for its next use. + *-F*************************************************************************/ +static void +aic7xxx_negotiation_complete(Scsi_Cmnd *cmd) +{ + unsigned int checksum; + int i; + int *ibuffer; + struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata; + int tindex = TARGET_INDEX(cmd); + struct aic7xxx_syncrate *syncrate; + + /* + * perform our minimalistic domain validation + */ + if(p->dev_flags[tindex] & DEVICE_SCANNED) + { + ibuffer = (int *)cmd->request_buffer; + checksum = 0; + for(i = 0; i < (cmd->request_bufflen >> 2); i++) + { + checksum += ibuffer[i]; + } + if( (checksum != p->dev_checksum[tindex]) && + (p->transinfo[tindex].cur_offset != 0) ) + { + unsigned int period = p->transinfo[tindex].cur_period; + unsigned char options = p->transinfo[tindex].cur_options; + + if (p->needdv & (1<host_no, CTL_OF_CMD(cmd)); + } + if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL) + { + syncrate++; + if( (syncrate->rate[0] != NULL) && + (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) ) + { + p->transinfo[tindex].goal_period = syncrate->period; + if( p->transinfo[tindex].goal_period > 9 ) + { + p->transinfo[tindex].goal_options = 0; + p->needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_width) + { + p->needwdtr |= (1<needwdtr_copy |= (1<transinfo[tindex].goal_width) + { + p->transinfo[tindex].goal_width = 0; + p->needwdtr &= ~(1<needwdtr_copy &= ~(1<transinfo[tindex].goal_offset = + p->transinfo[tindex].user_offset; + p->transinfo[tindex].goal_period = + p->transinfo[tindex].user_period; + p->transinfo[tindex].goal_options = + p->transinfo[tindex].user_options; + if( p->transinfo[tindex].goal_period <= 9 ) + { + p->needppr |= (1<needsdtr &= ~(1<needppr_copy |= (1<needsdtr_copy &= ~(1<needppr &= ~(1<needsdtr |= (1<needppr_copy &= ~(1<needsdtr_copy |= (1<transinfo[tindex].goal_offset = 0; + p->transinfo[tindex].goal_period = 255; + p->transinfo[tindex].goal_options = 0; + p->transinfo[tindex].goal_width = 0; + p->needppr &= ~(1<needsdtr &= ~(1<needwdtr &= ~(1<needppr_copy &= ~(1<needsdtr_copy &= ~(1<needwdtr_copy &= ~(1<needdv &= ~(1<host_no, CTL_OF_CMD(cmd)); + } + /* + * Update the checksum in case the INQUIRY data has changed, maybe + * in relation to a change in the mode pages, or whatever. + */ + p->dev_checksum[tindex] = checksum; + /* + * Signal that we are trying out the domain validation + */ + p->needdv |= (1<needppr |= (p->needppr_copy & (1<needsdtr |= (p->needsdtr_copy & (1<needwdtr |= (p->needwdtr_copy & (1<needdv & (1<host_no, CTL_OF_CMD(cmd)); + } + /* + * We successfully did our checksum, so don't leave the needdv flag set + * in case we might have set it last time through. + */ + p->needdv &= ~(1<dtr_pending &= ~(0x01 << tindex); + /* + * This looks recursive in the extreme, but if this was a WDTR negotiation + * and we didn't follow up with SDTR yet, then this will get it started. + * For all other cases, this should work out to be a no-op, unless we are + * doing domain validation and happen to need a new negotiation command. + * + * In case we don't want this to go any further, the cmdcmplt interrupt + * handler will NULL out the cmd->next entry so that the real SCSI command + * can be sent back to the mid layer code with SENSE data intact. We'll + * finish things up when the cmd gets sent back down to us, so no worries. + */ + if(cmd->next) + { + aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex); + } + return; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_build_negotiation_command + * + * Description: + * Build a Scsi_Cmnd structure to perform negotiation with or else send + * a pre-built command specifically for this purpose. + *-F*************************************************************************/ +static void +aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd, + int tindex) +{ + + if ( !(p->dtr_pending & (1<needppr & (1<needwdtr & (1<needsdtr & (1<dev_dtr_cmnd[tindex] == NULL) && + (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) ) + { + return; + } + /* + * Before sending this thing out, we also make the cmd->next pointer + * point to the real command so we can stuff any possible SENSE data + * into the real command instead of this fake command. This has to be + * done each time the command is built, not just the first time, hence + * it's outside of the above if()... + */ + p->dev_dtr_cmnd[tindex]->next = old_cmd; + /* + * Clear the buffer so checksums come out right.... + */ + memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0, + p->dev_dtr_cmnd[tindex]->request_bufflen); + /* + * Remove any commands for this particular device that might be on the + * waiting_scbs queue or qinfifo so that this command goes out first. + * This is vital for our implementation of domain validation. + */ + pause_sequencer(p); + aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS, + SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]); + unpause_sequencer(p, FALSE); + { + struct aic7xxx_scb *scb, *next; + + scb = p->waiting_scbs.head; + while(scb != NULL) + { + if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel, + ALL_LUNS, SCB_LIST_NULL) ) + { + next = scb->q_next; + scbq_remove(&p->waiting_scbs, scb); + scbq_insert_tail(&p->delayed_scbs[tindex], scb); + scb = next; + } + else + { + scb = scb->q_next; + } + } + } + aic7xxx_queue(p->dev_dtr_cmnd[tindex], + aic7xxx_negotiation_complete); + } +} + +#ifdef AIC7XXX_VERBOSE_DEBUGGING +/*+F************************************************************************* + * Function: + * aic7xxx_print_scb + * + * Description: + * Dump the byte codes for an about to be sent SCB. + *-F*************************************************************************/ +static void +aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + int i; + unsigned char *x; + + x = (unsigned char *)&scb->hscb->control; + + for(i=0; i<32; i++) + { + printk("%02x ", x[i]); + } + printk("\n"); +} +#endif + +/*+F************************************************************************* + * Function: + * aic7xxx_buildscb + * + * Description: + * Build a SCB. + *-F*************************************************************************/ +static void +aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd, + struct aic7xxx_scb *scb) +{ + unsigned short mask; + struct aic7xxx_hwscb *hscb; + unsigned char tindex = TARGET_INDEX(cmd); + + mask = (0x01 << tindex); + hscb = scb->hscb; + + /* + * Setup the control byte if we need negotiation and have not + * already requested it. + */ + hscb->control = 0; + scb->tag_action = 0; + cmd->tag = hscb->tag; + if (p->discenable & mask) + { + hscb->control |= DISCENB; + if ( (p->tagenable & mask) && + (cmd->cmnd[0] != TEST_UNIT_READY) ) + { + p->dev_commands_sent[tindex]++; + if (p->dev_commands_sent[tindex] < 200) + { + hscb->control |= MSG_SIMPLE_Q_TAG; + scb->tag_action = MSG_SIMPLE_Q_TAG; + } + else + { + if (p->orderedtag & mask) + { + hscb->control |= MSG_ORDERED_Q_TAG; + scb->tag_action = MSG_ORDERED_Q_TAG; + } + else + { + hscb->control |= MSG_SIMPLE_Q_TAG; + scb->tag_action = MSG_SIMPLE_Q_TAG; + } + p->dev_commands_sent[tindex] = 0; + } + } + } + if ( cmd == p->dev_dtr_cmnd[tindex] ) + { + p->dtr_pending |= mask; + scb->tag_action = 0; + if (p->dev_flags[tindex] & DEVICE_SCANNED) + { + hscb->control &= DISCENB; + hscb->control |= MK_MESSAGE; + if(p->needppr & mask) + { + scb->flags |= SCB_MSGOUT_PPR; + } + else if(p->needwdtr & mask) + { + scb->flags |= SCB_MSGOUT_WDTR; + } + else if(p->needsdtr & mask) + { + scb->flags |= SCB_MSGOUT_SDTR; + } + } + } + if ( !(p->dtr_pending & mask) && + ( (p->needppr & mask) || + (p->needwdtr & mask) || + (p->needsdtr & mask) ) ) + { + aic7xxx_build_negotiation_cmnd(p, cmd, tindex); + } + hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) | + ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07); + + /* + * The interpretation of request_buffer and request_bufflen + * changes depending on whether or not use_sg is zero; a + * non-zero use_sg indicates the number of elements in the + * scatter-gather array. + */ + + /* + * XXX - this relies on the host data being stored in a + * little-endian format. + */ + hscb->SCSI_cmd_length = cmd->cmd_len; + memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len); + hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd)); + + if (cmd->use_sg) + { + struct scatterlist *sg; /* Must be mid-level SCSI code scatterlist */ + + /* + * We must build an SG list in adapter format, as the kernel's SG list + * cannot be used directly because of data field size (__alpha__) + * differences and the kernel SG list uses virtual addresses where + * we need physical addresses. + */ + int i, use_sg; + + sg = (struct scatterlist *)cmd->request_buffer; + scb->sg_length = 0; + use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction)); + /* + * Copy the segments into the SG array. NOTE!!! - We used to + * have the first entry both in the data_pointer area and the first + * SG element. That has changed somewhat. We still have the first + * entry in both places, but now we download the address of + * scb->sg_list[1] instead of 0 to the sg pointer in the hscb. + */ + for (i = 0; i < use_sg; i++) + { + unsigned int len = sg_dma_len(sg+i); + scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i)); + scb->sg_list[i].length = cpu_to_le32(len); + scb->sg_length += len; + } + /* Copy the first SG into the data pointer area. */ + hscb->data_pointer = scb->sg_list[0].address; + hscb->data_count = scb->sg_list[0].length; + scb->sg_count = i; + hscb->SG_segment_count = i; + hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1])); + } + else + { + if (cmd->request_bufflen) + { + unsigned int address = pci_map_single(p->pdev, cmd->request_buffer, + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + aic7xxx_mapping(cmd) = address; + scb->sg_list[0].address = cpu_to_le32(address); + scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen); + scb->sg_count = 1; + scb->sg_length = cmd->request_bufflen; + hscb->SG_segment_count = 1; + hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0])); + hscb->data_count = scb->sg_list[0].length; + hscb->data_pointer = scb->sg_list[0].address; + } + else + { + scb->sg_count = 0; + scb->sg_length = 0; + hscb->SG_segment_count = 0; + hscb->SG_list_pointer = 0; + hscb->data_count = 0; + hscb->data_pointer = 0; + } + } +} + +/*+F************************************************************************* + * Function: + * aic7xxx_queue + * + * Description: + * Queue a SCB to the controller. + *-F*************************************************************************/ +int +aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *)) +{ + struct aic7xxx_host *p; + struct aic7xxx_scb *scb; +#ifdef AIC7XXX_VERBOSE_DEBUGGING + int tindex = TARGET_INDEX(cmd); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + + p = (struct aic7xxx_host *) cmd->host->hostdata; + /* + * Check to see if channel was scanned. + */ + +#ifdef AIC7XXX_VERBOSE_DEBUGGING + if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0)) + { + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(INFO_LEAD "Scanning channel for devices.\n", + p->host_no, 0, -1, -1); + p->flags |= AHC_A_SCANNED; + } + else + { + if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1)) + { + if (aic7xxx_verbose & VERBOSE_PROBE2) + printk(INFO_LEAD "Scanning channel for devices.\n", + p->host_no, 1, -1, -1); + p->flags |= AHC_B_SCANNED; + } + } + + if (p->dev_active_cmds[tindex] > (cmd->device->queue_depth + 1)) + { + printk(WARN_LEAD "Commands queued exceeds queue " + "depth, active=%d\n", + p->host_no, CTL_OF_CMD(cmd), + p->dev_active_cmds[tindex]); + if ( p->dev_active_cmds[tindex] > 220 ) + p->dev_active_cmds[tindex] = 0; + } +#endif + + scb = scbq_remove_head(&p->scb_data->free_scbs); + if (scb == NULL) + { + DRIVER_LOCK + aic7xxx_allocate_scb(p); + DRIVER_UNLOCK + scb = scbq_remove_head(&p->scb_data->free_scbs); + } + if (scb == NULL) + { + printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, + CTL_OF_CMD(cmd)); + cmd->result = (DID_BUS_BUSY << 16); + DRIVER_LOCK + aic7xxx_queue_cmd_complete(p, cmd); + DRIVER_UNLOCK + return 0; + } + else + { + scb->cmd = cmd; + aic7xxx_position(cmd) = scb->hscb->tag; + + /* + * Construct the SCB beforehand, so the sequencer is + * paused a minimal amount of time. + */ + aic7xxx_buildscb(p, cmd, scb); + + /* + * Make sure the Scsi_Cmnd pointer is saved, the struct it points to + * is set up properly, and the parity error flag is reset, then send + * the SCB to the sequencer and watch the fun begin. + */ + cmd->scsi_done = fn; + cmd->result = DID_OK; + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + aic7xxx_error(cmd) = DID_OK; + aic7xxx_status(cmd) = 0; + cmd->host_scribble = NULL; + + scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; + + DRIVER_LOCK + scbq_insert_tail(&p->waiting_scbs, scb); + if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0) + { + aic7xxx_run_waiting_queues(p); + } + DRIVER_UNLOCK + } + return (0); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_bus_device_reset + * + * Description: + * Abort or reset the current SCSI command(s). If the scb has not + * previously been aborted, then we attempt to send a BUS_DEVICE_RESET + * message to the target. If the scb has previously been unsuccessfully + * aborted, then we will reset the channel and have all devices renegotiate. + * Returns an enumerated type that indicates the status of the operation. + *-F*************************************************************************/ +static int +aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd) +{ + struct aic7xxx_scb *scb; + struct aic7xxx_hwscb *hscb; + int result = -1; + int channel; + unsigned char saved_scbptr, lastphase; + unsigned char hscb_index; + int disconnected; + + scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); + hscb = scb->hscb; + + lastphase = aic_inb(p, LASTPHASE); + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + { + printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ", + p->host_no, CTL_OF_SCB(scb), scb->flags); + switch (lastphase) + { + case P_DATAOUT: + printk("Data-Out phase\n"); + break; + case P_DATAIN: + printk("Data-In phase\n"); + break; + case P_COMMAND: + printk("Command phase\n"); + break; + case P_MESGOUT: + printk("Message-Out phase\n"); + break; + case P_STATUS: + printk("Status phase\n"); + break; + case P_MESGIN: + printk("Message-In phase\n"); + break; + default: + /* + * We're not in a valid phase, so assume we're idle. + */ + printk("while idle, LASTPHASE = 0x%x\n", lastphase); + break; + } + printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " + "0x%x\n", p->host_no, CTL_OF_SCB(scb), + aic_inb(p, SCSISIGI), + aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), + aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); + } + + channel = cmd->channel; + + /* + * Send a Device Reset Message: + * The target that is holding up the bus may not be the same as + * the one that triggered this timeout (different commands have + * different timeout lengths). Our strategy here is to queue an + * abort message to the timed out target if it is disconnected. + * Otherwise, if we have an active target we stuff the message buffer + * with an abort message and assert ATN in the hopes that the target + * will let go of the bus and go to the mesgout phase. If this + * fails, we'll get another timeout a few seconds later which will + * attempt a bus reset. + */ + saved_scbptr = aic_inb(p, SCBPTR); + disconnected = FALSE; + + if (lastphase != P_BUSFREE) + { + if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs) + { + printk(WARN_LEAD "Invalid SCB ID %d is active, " + "SCB flags = 0x%x.\n", p->host_no, + CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags); + return(SCSI_RESET_ERROR); + } + if (scb->hscb->tag == aic_inb(p, SCB_TAG)) + { + if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) ) + { + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Device reset message in " + "message buffer\n", p->host_no, CTL_OF_SCB(scb)); + scb->flags |= SCB_RESET | SCB_DEVICE_RESET; + aic7xxx_error(scb->cmd) = DID_RESET; + p->dev_flags[TARGET_INDEX(scb->cmd)] |= + BUS_DEVICE_RESET_PENDING; + /* Send the abort message to the active SCB. */ + aic_outb(p, HOST_MSG, MSG_OUT); + aic_outb(p, lastphase | ATNO, SCSISIGO); + return(SCSI_RESET_PENDING); + } + else + { + /* We want to send out the message, but it could screw an already */ + /* in place and being used message. Instead, we return an error */ + /* to try and start the bus reset phase since this command is */ + /* probably hung (aborts failed, and now reset is failing). We */ + /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */ + /* any more on this device, but instead will escalate to a bus or */ + /* host reset (additionally, we won't try to abort any more). */ + printk(WARN_LEAD "Device reset, Message buffer " + "in use\n", p->host_no, CTL_OF_SCB(scb)); + scb->flags |= SCB_RESET | SCB_DEVICE_RESET; + aic7xxx_error(scb->cmd) = DID_RESET; + p->dev_flags[TARGET_INDEX(scb->cmd)] |= + BUS_DEVICE_RESET_PENDING; + return(SCSI_RESET_ERROR); + } + } + } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */ + hscb_index = aic7xxx_find_scb(p, scb); + if (hscb_index == SCB_LIST_NULL) + { + disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE; + } + else + { + aic_outb(p, hscb_index, SCBPTR); + if (aic_inb(p, SCB_CONTROL) & DISCONNECTED) + { + disconnected = TRUE; + } + } + if (disconnected) + { + /* + * Simply set the MK_MESSAGE flag and the SEQINT handler will do + * the rest on a reconnect. + */ + scb->hscb->control |= MK_MESSAGE; + scb->flags |= SCB_RESET | SCB_DEVICE_RESET; + p->dev_flags[TARGET_INDEX(scb->cmd)] |= + BUS_DEVICE_RESET_PENDING; + if (hscb_index != SCB_LIST_NULL) + { + unsigned char scb_control; + + aic_outb(p, hscb_index, SCBPTR); + scb_control = aic_inb(p, SCB_CONTROL); + aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL); + } + /* + * Actually requeue this SCB in case we can select the + * device before it reconnects. If the transaction we + * want to abort is not tagged, then this will be the only + * outstanding command and we can simply shove it on the + * qoutfifo and be done. If it is tagged, then it goes right + * in with all the others, no problem :) We need to add it + * to the qinfifo and let the sequencer know it is there. + * Now, the only problem left to deal with is, *IF* this + * command completes, in spite of the MK_MESSAGE bit in the + * control byte, then we need to pick that up in the interrupt + * routine and clean things up. This *shouldn't* ever happen. + */ + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Queueing device reset " + "command.\n", p->host_no, CTL_OF_SCB(scb)); + p->qinfifo[p->qinfifonext++] = scb->hscb->tag; + if (p->features & AHC_QUEUE_REGS) + aic_outb(p, p->qinfifonext, HNSCB_QOFF); + else + aic_outb(p, p->qinfifonext, KERNEL_QINPOS); + scb->flags |= SCB_QUEUED_ABORT; + result = SCSI_RESET_PENDING; + } + else if (result == -1) + { + result = SCSI_RESET_ERROR; + } + aic_outb(p, saved_scbptr, SCBPTR); + return (result); +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_panic_abort + * + * Description: + * Abort the current SCSI command(s). + *-F*************************************************************************/ +void +aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd) +{ + + printk("aic7xxx driver version %s/%s\n", AIC7XXX_C_VERSION, + UTS_RELEASE); + printk("Controller type:\n %s\n", board_names[p->board_name_index]); + printk("p->flags=0x%lx, p->chip=0x%x, p->features=0x%x, " + "sequencer %s paused\n", + p->flags, p->chip, p->features, + (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" ); + pause_sequencer(p); + disable_irq(p->irq); + aic7xxx_print_card(p); + aic7xxx_print_scratch_ram(p); + spin_unlock_irq(&io_request_lock); + for(;;) barrier(); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_abort + * + * Description: + * Abort the current SCSI command(s). + *-F*************************************************************************/ +int +aic7xxx_abort(Scsi_Cmnd *cmd) +{ + struct aic7xxx_scb *scb = NULL; + struct aic7xxx_host *p; + int result, found=0; + unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif + Scsi_Cmnd *cmd_next, *cmd_prev; + + p = (struct aic7xxx_host *) cmd->host->hostdata; + scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); + + /* + * I added a new config option to the driver: "panic_on_abort" that will + * cause the driver to panic and the machine to stop on the first abort + * or reset call into the driver. At that point, it prints out a lot of + * usefull information for me which I can then use to try and debug the + * problem. Simply enable the boot time prompt in order to activate this + * code. + */ + if (aic7xxx_panic_on_abort) + aic7xxx_panic_abort(p, cmd); + + DRIVER_LOCK + +/* + * Run the isr to grab any command in the QOUTFIFO and any other misc. + * assundry tasks. This should also set up the bh handler if there is + * anything to be done, but it won't run until we are done here since + * we are following a straight code path without entering the scheduler + * code. + */ + pause_sequencer(p); + while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) + { + aic7xxx_isr(p->irq, p, (void *)NULL); + pause_sequencer(p); + aic7xxx_done_cmds_complete(p); + } + + if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout)) + /* Totally bogus cmd since it points beyond our */ + { /* valid SCB range or doesn't even match it's own*/ + /* timeout serial number. */ + if (aic7xxx_verbose & VERBOSE_ABORT_MID) + printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd " + "pointer.\n", p->host_no, CTL_OF_CMD(cmd)); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_ABORT_NOT_RUNNING); + } + if (scb->cmd != cmd) /* Hmmm...either this SCB is currently free with a */ + { /* NULL cmd pointer (NULLed out when freed) or it */ + /* has already been recycled for another command */ + /* Either way, this SCB has nothing to do with this*/ + /* command and we need to deal with cmd without */ + /* touching the SCB. */ + /* The theory here is to return a value that will */ + /* make the queued for complete command actually */ + /* finish successfully, or to indicate that we */ + /* don't have this cmd any more and the mid level */ + /* code needs to find it. */ + cmd_next = p->completeq.head; + cmd_prev = NULL; + while (cmd_next != NULL) + { + if (cmd_next == cmd) + { + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "Abort called for command " + "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd)); + if ( cmd_prev == NULL ) + p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble; + else + cmd_prev->host_scribble = cmd_next->host_scribble; + cmd_next->scsi_done(cmd_next); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful + * completion */ + } + cmd_prev = cmd_next; + cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; + } + if (aic7xxx_verbose & VERBOSE_ABORT_MID) + printk(INFO_LEAD "Abort called for already completed" + " command.\n", p->host_no, CTL_OF_CMD(cmd)); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_ABORT_NOT_RUNNING); + } + +/* At this point we know the following: + * the SCB pointer is valid + * the command pointer passed in to us and the scb->cmd pointer match + * this then means that the command we need to abort is the same as the + * command held by the scb pointer and is a valid abort request. + * Now, we just have to figure out what to do from here. Current plan is: + * if we have already been here on this command, escalate to a reset + * if scb is on waiting list or QINFIFO, send it back as aborted, but + * we also need to be aware of the possibility that we could be using + * a faked negotiation command that is holding this command up, if + * so we need to take care of that command instead, which means we + * would then treat this one like it was sitting around disconnected + * instead. + * if scb is on WAITING_SCB list in sequencer, free scb and send back + * if scb is disconnected and not completed, abort with abort message + * if scb is currently running, then it may be causing the bus to hang + * so we want a return value that indicates a reset would be appropriate + * if the command does not finish shortly + * if scb is already complete but not on completeq, we're screwed because + * this can't happen (except if the command is in the QOUTFIFO, in which + * case we would like it to complete successfully instead of having to + * to be re-done) + * All other scenarios already dealt with by previous code. + */ + + if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) ) + { + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "SCB aborted once already, " + "escalating.\n", p->host_no, CTL_OF_SCB(scb)); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_ABORT_SNOOZE); + } + if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || + (p->dev_flags[TARGET_INDEX(scb->cmd)] & + BUS_DEVICE_RESET_PENDING) ) + { + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "Reset/Abort pending for this " + "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb)); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_ABORT_PENDING); + } + + found = 0; + p->flags |= AHC_IN_ABORT; + if (aic7xxx_verbose & VERBOSE_ABORT) + printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n", + p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); + +/* + * First, let's check to see if the currently running command is our target + * since if it is, the return is fairly easy and quick since we don't want + * to touch the command in case it might complete, but we do want a timeout + * in case it's actually hung, so we really do nothing, but tell the mid + * level code to reset the timeout. + */ + + if ( scb->hscb->tag == aic_inb(p, SCB_TAG) ) + { + /* + * Check to see if the sequencer is just sitting on this command, or + * if it's actively being run. + */ + result = aic_inb(p, LASTPHASE); + switch (result) + { + case P_DATAOUT: /* For any of these cases, we can assume we are */ + case P_DATAIN: /* an active command and act according. For */ + case P_COMMAND: /* anything else we are going to fall on through*/ + case P_STATUS: /* The SCSI_ABORT_SNOOZE will give us two abort */ + case P_MESGOUT: /* chances to finish and then escalate to a */ + case P_MESGIN: /* reset call */ + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "SCB is currently active. " + "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb)); + unpause_sequencer(p, FALSE); + p->flags &= ~AHC_IN_ABORT; + scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */ + p->flags |= AHC_ABORT_PENDING; /* here so we will know not to */ + DRIVER_UNLOCK /* muck with other SCBs if this */ + return(SCSI_ABORT_PENDING); /* one doesn't complete and clear */ + break; /* out. */ + default: + break; + } + } + + if ((found == 0) && (scb->flags & SCB_WAITINGQ)) + { + int tindex = TARGET_INDEX(cmd); + unsigned short mask; + + mask = (1 << tindex); + + if (p->dtr_pending & mask) + { + if (p->dev_dtr_cmnd[tindex]->next != cmd) + found = 1; + else + found = 0; + } + else + { + found = 1; + } + if (found == 0) + { + /* + * OK..this means the command we are currently getting an abort + * for has an outstanding negotiation command in front of it. + * We don't really have a way to tie back into the negotiation + * commands, so we just send this back as pending, then it + * will get reset in 2 seconds. + */ + unpause_sequencer(p, TRUE); + scb->flags |= SCB_ABORT; + DRIVER_UNLOCK + return(SCSI_ABORT_PENDING); + } + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "SCB found on waiting list and " + "aborted.\n", p->host_no, CTL_OF_SCB(scb)); + scbq_remove(&p->waiting_scbs, scb); + scbq_remove(&p->delayed_scbs[tindex], scb); + p->dev_active_cmds[tindex]++; + p->activescbs++; + scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE); + scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE; + found = 1; + } + +/* + * We just checked the waiting_q, now for the QINFIFO + */ + if ( found == 0 ) + { + if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, + cmd->channel, + cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE, + FALSE, NULL)) != 0) && + (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)) + printk(INFO_LEAD "SCB found in QINFIFO and " + "aborted.\n", p->host_no, CTL_OF_SCB(scb)); + } + +/* + * QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card + */ + + if ( found == 0 ) + { + unsigned char scb_next_ptr; + prev_hscbptr = SCB_LIST_NULL; + saved_hscbptr = aic_inb(p, SCBPTR); + next_hscbptr = aic_inb(p, WAITING_SCBH); + while ( next_hscbptr != SCB_LIST_NULL ) + { + aic_outb(p, next_hscbptr, SCBPTR ); + if ( scb->hscb->tag == aic_inb(p, SCB_TAG) ) + { + found = 1; + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "SCB found on hardware waiting" + " list and aborted.\n", p->host_no, CTL_OF_SCB(scb)); + if ( prev_hscbptr == SCB_LIST_NULL ) + { + aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH); + /* stop the selection since we just + * grabbed the scb out from under the + * card + */ + aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); + aic_outb(p, CLRSELTIMEO, CLRSINT1); + } + else + { + scb_next_ptr = aic_inb(p, SCB_NEXT); + aic_outb(p, prev_hscbptr, SCBPTR); + aic_outb(p, scb_next_ptr, SCB_NEXT); + aic_outb(p, next_hscbptr, SCBPTR); + } + aic_outb(p, SCB_LIST_NULL, SCB_TAG); + aic_outb(p, 0, SCB_CONTROL); + aic7xxx_add_curscb_to_free_list(p); + scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE; + break; + } + prev_hscbptr = next_hscbptr; + next_hscbptr = aic_inb(p, SCB_NEXT); + } + aic_outb(p, saved_hscbptr, SCBPTR ); + } + +/* + * Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked. + * OK...the sequencer's paused, interrupts are off, and we haven't found the + * command anyplace where it could be easily aborted. Time for the hard + * work. We also know the command is valid. This essentially means the + * command is disconnected, or connected but not into any phases yet, which + * we know due to the tests we ran earlier on the current active scb phase. + * At this point we can queue the abort tag and go on with life. + */ + + if ( found == 0 ) + { + p->flags |= AHC_ABORT_PENDING; + scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB; + scb->hscb->control |= MK_MESSAGE; + result=aic7xxx_find_scb(p, scb); + if ( result != SCB_LIST_NULL ) + { + saved_hscbptr = aic_inb(p, SCBPTR); + aic_outb(p, result, SCBPTR); + tmp_char = aic_inb(p, SCB_CONTROL); + aic_outb(p, tmp_char | MK_MESSAGE, SCB_CONTROL); + aic_outb(p, saved_hscbptr, SCBPTR); + } + if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) + printk(INFO_LEAD "SCB disconnected. Queueing Abort" + " SCB.\n", p->host_no, CTL_OF_SCB(scb)); + p->qinfifo[p->qinfifonext++] = scb->hscb->tag; + if (p->features & AHC_QUEUE_REGS) + aic_outb(p, p->qinfifonext, HNSCB_QOFF); + else + aic_outb(p, p->qinfifonext, KERNEL_QINPOS); + } + if (found) + { + aic7xxx_run_done_queue(p, TRUE); + aic7xxx_run_waiting_queues(p); + } + p->flags &= ~AHC_IN_ABORT; + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + +/* + * On the return value. If we found the command and aborted it, then we know + * it's already sent back and there is no reason for a further timeout, so + * we use SCSI_ABORT_SUCCESS. On the queued abort side, we aren't so certain + * there hasn't been a bus hang or something that might keep the abort from + * from completing. Therefore, we use SCSI_ABORT_PENDING. The first time this + * is passed back, the timeout on the command gets extended, the second time + * we pass this back, the mid level SCSI code calls our reset function, which + * would shake loose a hung bus. + */ + if ( found != 0 ) + return(SCSI_ABORT_SUCCESS); + else + return(SCSI_ABORT_PENDING); +} + + +/*+F************************************************************************* + * Function: + * aic7xxx_reset + * + * Description: + * Resetting the bus always succeeds - is has to, otherwise the + * kernel will panic! Try a surgical technique - sending a BUS + * DEVICE RESET message - on the offending target before pulling + * the SCSI bus reset line. + *-F*************************************************************************/ +int +aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags) +{ + struct aic7xxx_scb *scb = NULL; + struct aic7xxx_host *p; + int tindex; + int result = -1; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95) + unsigned long cpu_flags = 0; +#endif +#define DEVICE_RESET 0x01 +#define BUS_RESET 0x02 +#define HOST_RESET 0x04 +#define FAIL 0x08 +#define RESET_DELAY 0x10 + int action; + Scsi_Cmnd *cmd_prev, *cmd_next; + + + if ( cmd == NULL ) + { + printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd " + "pointer, failing.\n"); + return(SCSI_RESET_SNOOZE); + } + + p = (struct aic7xxx_host *) cmd->host->hostdata; + scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); + tindex = TARGET_INDEX(cmd); + + /* + * I added a new config option to the driver: "panic_on_abort" that will + * cause the driver to panic and the machine to stop on the first abort + * or reset call into the driver. At that point, it prints out a lot of + * usefull information for me which I can then use to try and debug the + * problem. Simply enable the boot time prompt in order to activate this + * code. + */ + if (aic7xxx_panic_on_abort) + aic7xxx_panic_abort(p, cmd); + + DRIVER_LOCK + + pause_sequencer(p); + while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) + { + aic7xxx_isr(p->irq, p, (void *)NULL ); + pause_sequencer(p); + aic7xxx_done_cmds_complete(p); + } + + if (scb == NULL) + { + if (aic7xxx_verbose & VERBOSE_RESET_MID) + printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd" + "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd)); + if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) + { + action = HOST_RESET; + } + else + { + action = BUS_RESET; + } + } + else if (scb->cmd != cmd) + { + if (aic7xxx_verbose & VERBOSE_RESET_MID) + printk(INFO_LEAD "Reset called with recycled SCB " + "for cmd.\n", p->host_no, CTL_OF_CMD(cmd)); + cmd_prev = NULL; + cmd_next = p->completeq.head; + while ( cmd_next != NULL ) + { + if (cmd_next == cmd) + { + if (aic7xxx_verbose & VERBOSE_RESET_RETURN) + printk(INFO_LEAD "Reset, found cmd on completeq" + ", completing.\n", p->host_no, CTL_OF_CMD(cmd)); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_NOT_RUNNING); + } + cmd_prev = cmd_next; + cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble; + } + if ( !(flags & SCSI_RESET_SYNCHRONOUS) ) + { + if (aic7xxx_verbose & VERBOSE_RESET_RETURN) + printk(INFO_LEAD "Reset, cmd not found," + " failing.\n", p->host_no, CTL_OF_CMD(cmd)); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_NOT_RUNNING); + } + else + { + if (aic7xxx_verbose & VERBOSE_RESET_MID) + printk(INFO_LEAD "Reset called, no scb, " + "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags); + scb = NULL; + action = HOST_RESET; + } + } + else + { + if (aic7xxx_verbose & VERBOSE_RESET_MID) + printk(INFO_LEAD "Reset called, scb %d, flags " + "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags); + if ( aic7xxx_scb_on_qoutfifo(p, scb) ) + { + if(aic7xxx_verbose & VERBOSE_RESET_RETURN) + printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no, + CTL_OF_SCB(scb)); + if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0) + printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no, + CTL_OF_SCB(scb)); + aic7xxx_handle_command_completion_intr(p); + aic7xxx_done_cmds_complete(p); + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_SUCCESS); + } + if ( flags & SCSI_RESET_SUGGEST_HOST_RESET ) + { + action = HOST_RESET; + } + else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET ) + { + action = BUS_RESET; + } + else + { + action = DEVICE_RESET; + } + } + if ( (action & DEVICE_RESET) && + (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) ) + { + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Bus device reset already sent to " + "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd)); + action = BUS_RESET; + } + if ( (action & DEVICE_RESET) && + (scb->flags & SCB_QUEUED_ABORT) ) + { + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + { + printk(INFO_LEAD "Have already attempted to reach " + "device with queued\n", p->host_no, CTL_OF_CMD(cmd)); + printk(INFO_LEAD "message, will escalate to bus " + "reset.\n", p->host_no, CTL_OF_CMD(cmd)); + } + action = BUS_RESET; + } + if ( (action & DEVICE_RESET) && + (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) ) + { + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Bus device reset stupid when " + "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd)); + action = BUS_RESET; + } + if ( (action & BUS_RESET) && !(p->features & AHC_TWIN) ) + { + action = HOST_RESET; + } + if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) && + !(action & (HOST_RESET | BUS_RESET))) + { + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + { + printk(INFO_LEAD "Reset called too soon after last " + "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd)); + printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no, + CTL_OF_CMD(cmd)); + } + action = BUS_RESET; + } + if ( (p->flags & AHC_RESET_DELAY) && + (action & (HOST_RESET | BUS_RESET)) ) + { + if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) + printk(INFO_LEAD "Reset called too soon after " + "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd)); + action = RESET_DELAY; + } +/* + * By this point, we want to already know what we are going to do and + * only have the following code implement our course of action. + */ + switch (action) + { + case RESET_DELAY: + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_PENDING); + break; + case FAIL: + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(SCSI_RESET_ERROR); + break; + case DEVICE_RESET: + p->flags |= AHC_IN_RESET; + result = aic7xxx_bus_device_reset(p, cmd); + aic7xxx_run_done_queue(p, TRUE); + /* We can't rely on run_waiting_queues to unpause the sequencer for + * PCI based controllers since we use AAP */ + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + p->flags &= ~AHC_IN_RESET; + DRIVER_UNLOCK + return(result); + break; + case BUS_RESET: + case HOST_RESET: + default: + p->flags |= AHC_IN_RESET | AHC_RESET_DELAY; + p->dev_expires[p->scsi_id] = jiffies + (3 * HZ); + p->dev_timer_active |= (0x01 << p->scsi_id); + if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) || + time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) ) + { + mod_timer(&p->dev_timer, p->dev_expires[p->scsi_id]); + p->dev_timer_active |= (0x01 << MAX_TARGETS); + } + aic7xxx_reset_channel(p, cmd->channel, TRUE); + if ( (p->features & AHC_TWIN) && (action & HOST_RESET) ) + { + aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE); + restart_sequencer(p); + } + if (action != HOST_RESET) + result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; + else + { + result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; + aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), + SIMODE1); + aic7xxx_clear_intstat(p); + p->flags &= ~AHC_HANDLING_REQINITS; + p->msg_type = MSG_TYPE_NONE; + p->msg_index = 0; + p->msg_len = 0; + } + aic7xxx_run_done_queue(p, TRUE); + /* + * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is + * in need of being re-started, so send it on through to aic7xxx_queue + * and let it set until the delay is over. This keeps it from dying + * entirely and avoids getting a bogus dead command back through the + * mid-level code due to too many retries. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132) + if ( flags & SCSI_RESET_SYNCHRONOUS ) + { + cmd->result = DID_BUS_BUSY << 16; + cmd->done(cmd); + } +#endif + p->flags &= ~AHC_IN_RESET; + /* + * We can't rely on run_waiting_queues to unpause the sequencer for + * PCI based controllers since we use AAP. NOTE: this also sets + * the timer for the one command we might have queued in the case + * of a synch reset. + */ + aic7xxx_run_waiting_queues(p); + unpause_sequencer(p, FALSE); + DRIVER_UNLOCK + return(result); + break; + } +} + +/*+F************************************************************************* + * Function: + * aic7xxx_biosparam + * + * Description: + * Return the disk geometry for the given SCSI device. + *-F*************************************************************************/ +int +aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) +{ + int heads, sectors, cylinders, ret; + struct aic7xxx_host *p; + struct buffer_head *bh; + + p = (struct aic7xxx_host *) disk->device->host->hostdata; + bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024); + + if ( bh ) + { + ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]); + brelse(bh); + if ( ret != -1 ) + return(ret); + } + + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + + if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024)) + { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return (0); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_release + * + * Description: + * Free the passed in Scsi_Host memory structures prior to unloading the + * module. + *-F*************************************************************************/ +int +aic7xxx_release(struct Scsi_Host *host) +{ + struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata; + struct aic7xxx_host *next, *prev; + + if(p->irq) + free_irq(p->irq, p); + if(p->base) + release_region(p->base, MAXREG - MINREG); +#ifdef MMAPIO + if(p->maddr) + { + iounmap((void *) (((unsigned long) p->maddr) & PAGE_MASK)); + } +#endif /* MMAPIO */ + prev = NULL; + next = first_aic7xxx; + while(next != NULL) + { + if(next == p) + { + if(prev == NULL) + first_aic7xxx = next->next; + else + prev->next = next->next; + } + else + { + prev = next; + } + next = next->next; + } + aic7xxx_free(p); + return(0); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_print_card + * + * Description: + * Print out all of the control registers on the card + * + * NOTE: This function is not yet safe for use on the VLB and EISA + * controllers, so it isn't used on those controllers at all. + *-F*************************************************************************/ +static void +aic7xxx_print_card(struct aic7xxx_host *p) +{ + int i, j, k, chip; + static struct register_ranges { + int num_ranges; + int range_val[32]; + } cards_ds[] = { + { 0, {0,} }, /* none */ + {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/ + 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} }, + { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/ + 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, + { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/ + 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, + {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/ + 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, + {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/ + 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, + {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/ + 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f, + 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc, + 0xfe, 0xff} }, + {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/ + 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, + 0x9f, 0x9f, 0xe0, 0xf1} }, + {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/ + 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f, + 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc, + 0xfe, 0xff} }, + {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/ + 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, + 0xe0, 0xf1, 0xf4, 0xfc} }, + {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/ + 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, + 0xe0, 0xf1, 0xf4, 0xfc} }, + }; + chip = p->chip & AHC_CHIPID_MASK; + printk("%s at ", + board_names[p->board_name_index]); + switch(p->chip & ~AHC_CHIPID_MASK) + { + case AHC_VL: + printk("VLB Slot %d.\n", p->pci_device_fn); + break; + case AHC_EISA: + printk("EISA Slot %d.\n", p->pci_device_fn); + break; + case AHC_PCI: + default: + printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn), + PCI_FUNC(p->pci_device_fn)); + break; + } + + /* + * the registers on the card.... + */ + printk("Card Dump:\n"); + k = 0; + for(i=0; ifeatures & AHC_QUEUE_REGS) + { + aic_outb(p, 0, SDSCB_QOFF); + aic_outb(p, 0, SNSCB_QOFF); + aic_outb(p, 0, HNSCB_QOFF); + } + +} + +/*+F************************************************************************* + * Function: + * aic7xxx_print_scratch_ram + * + * Description: + * Print out the scratch RAM values on the card. + *-F*************************************************************************/ +static void +aic7xxx_print_scratch_ram(struct aic7xxx_host *p) +{ + int i, k; + + k = 0; + printk("Scratch RAM:\n"); + for(i = SRAM_BASE; i < SEQCTL; i++) + { + printk("%02x:%02x ", i, aic_inb(p, i)); + if(++k == 13) + { + printk("\n"); + k=0; + } + } + if (p->features & AHC_MORE_SRAM) + { + for(i = TARG_OFFSET; i < 0x80; i++) + { + printk("%02x:%02x ", i, aic_inb(p, i)); + if(++k == 13) + { + printk("\n"); + k=0; + } + } + } + printk("\n"); +} + + +#include "aic7xxx_old/aic7xxx_proc.c" + +/* Eventually this will go into an include file, but this will be later */ +static Scsi_Host_Template driver_template = AIC7XXX; + +#include "scsi_module.c" + +/* + * Overrides for Emacs so that we almost follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 2 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -2 + * c-argdecl-indent: 2 + * c-label-offset: -2 + * c-continued-statement-offset: 2 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c --- v2.4.2/linux/drivers/scsi/aic7xxx_proc.c Wed Jun 21 17:25:03 2000 +++ linux/drivers/scsi/aic7xxx_proc.c Wed Dec 31 16:00:00 1969 @@ -1,413 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver proc support for Linux. - * - * Copyright (c) 1995, 1996 Dean W. Gehnert - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ---------------------------------------------------------------- - * o Modified from the EATA-DMA /proc support. - * o Additional support for device block statistics provided by - * Matthew Jacob. - * o Correction of overflow by Heinz Mauelshagen - * o Adittional corrections by Doug Ledford - * - * Dean W. Gehnert, deang@teleport.com, 05/01/96 - * - * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ - *-M*************************************************************************/ - -#include - -#define BLS (&aic7xxx_buffer[size]) -#define HDRB \ -" < 2K 2K+ 4K+ 8K+ 16K+ 32K+ 64K+ 128K+" - -#ifdef PROC_DEBUG -extern int vsprintf(char *, const char *, va_list); - -static void -proc_debug(const char *fmt, ...) -{ - va_list ap; - char buf[256]; - - va_start(ap, fmt); - vsprintf(buf, fmt, ap); - printk(buf); - va_end(ap); -} -#else /* PROC_DEBUG */ -# define proc_debug(fmt, args...) -#endif /* PROC_DEBUG */ - -static int aic7xxx_buffer_size = 0; -static char *aic7xxx_buffer = NULL; - - -/*+F************************************************************************* - * Function: - * aic7xxx_set_info - * - * Description: - * Set parameters for the driver from the /proc filesystem. - *-F*************************************************************************/ -int -aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) -{ - proc_debug("aic7xxx_set_info(): %s\n", buffer); - return (-ENOSYS); /* Currently this is a no-op */ -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_proc_info - * - * Description: - * Return information to handle /proc support for the driver. - *-F*************************************************************************/ -int -aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, - int hostno, int inout) -{ - struct Scsi_Host *HBAptr; - struct aic7xxx_host *p; - int size = 0; - unsigned char i; - struct aic7xxx_xferstats *sp; - unsigned char target; - - HBAptr = NULL; - - for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next) - ; - - if (!p) - { - size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); - if (size > length) - { - return (size); - } - else - { - return (length); - } - } - - HBAptr = p->host; - - if (inout == TRUE) /* Has data been written to the file? */ - { - return (aic7xxx_set_info(buffer, length, HBAptr)); - } - - p = (struct aic7xxx_host *) HBAptr->hostdata; - - /* - * It takes roughly 1K of space to hold all relevant card info, not - * counting any proc stats, so we start out with a 1.5k buffer size and - * if proc_stats is defined, then we sweep the stats structure to see - * how many drives we will be printing out for and add 384 bytes per - * device with active stats. - * - * Hmmmm...that 1.5k seems to keep growing as items get added so they - * can be easily viewed for debugging purposes. So, we bumped that - * 1.5k to 4k so we can quit having to bump it all the time. - */ - - size = 4096; - for (target = 0; target < MAX_TARGETS; target++) - { - if (p->dev_flags[target] & DEVICE_PRESENT) -#ifdef AIC7XXX_PROC_STATS - size += 512; -#else - size += 256; -#endif - } - if (aic7xxx_buffer_size != size) - { - if (aic7xxx_buffer != NULL) - { - kfree(aic7xxx_buffer); - aic7xxx_buffer_size = 0; - } - aic7xxx_buffer = kmalloc(size, GFP_KERNEL); - } - if (aic7xxx_buffer == NULL) - { - size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n", - __LINE__); - return size; - } - aic7xxx_buffer_size = size; - - size = 0; - size += sprintf(BLS, "Adaptec AIC7xxx driver version: "); - size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION); - size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Compile Options:\n"); -#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT - size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n"); -#else - size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n"); -#endif -#ifdef AIC7XXX_PROC_STATS - size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n"); -#else - size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n"); -#endif - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Adapter Configuration:\n"); - size += sprintf(BLS, " SCSI Adapter: %s\n", - board_names[p->board_name_index]); - if (p->flags & AHC_TWIN) - size += sprintf(BLS, " Twin Channel Controller "); - else - { - char *channel = ""; - char *ultra = ""; - char *wide = "Narrow "; - if (p->flags & AHC_MULTI_CHANNEL) - { - channel = " Channel A"; - if (p->flags & (AHC_CHNLB|AHC_CHNLC)) - channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C"; - } - if (p->features & AHC_WIDE) - wide = "Wide "; - if (p->features & AHC_ULTRA3) - { - switch(p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7892: - case AHC_AIC7899: - ultra = "Ultra-160/m LVD/SE "; - break; - default: - ultra = "Ultra-3 LVD/SE "; - break; - } - } - else if (p->features & AHC_ULTRA2) - ultra = "Ultra-2 LVD/SE "; - else if (p->features & AHC_ULTRA) - ultra = "Ultra "; - size += sprintf(BLS, " %s%sController%s ", - ultra, wide, channel); - } - switch(p->chip & ~AHC_CHIPID_MASK) - { - case AHC_VL: - size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn); - break; - case AHC_EISA: - size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn); - break; - default: - size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus, - PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn)); - break; - } - if( !(p->maddr) ) - { - size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base); - } - else - { - size += sprintf(BLS, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase); - } - if( (p->chip & (AHC_VL | AHC_EISA)) ) - { - size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address); - } - size += sprintf(BLS, " Adapter SEEPROM Config: %s\n", - (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." : - ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." : - "SEEPROM not found, using leftover BIOS values.") ); - size += sprintf(BLS, " Adaptec SCSI BIOS: %s\n", - (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled"); - size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); - size += sprintf(BLS, " SCBs: Active %d, Max Active %d,\n", - p->activescbs, p->max_activescbs); - size += sprintf(BLS, " Allocated %d, HW %d, " - "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs, - p->scb_data->maxscbs); - if (p->flags & AHC_EXTERNAL_SRAM) - size += sprintf(BLS, " Using External SCB SRAM\n"); - size += sprintf(BLS, " Interrupts: %ld", p->isr_count); - if (p->chip & AHC_EISA) - { - size += sprintf(BLS, " %s\n", - (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)"); - } - else - { - size += sprintf(BLS, "\n"); - } - size += sprintf(BLS, " BIOS Control Word: 0x%04x\n", - p->bios_control); - size += sprintf(BLS, " Adapter Control Word: 0x%04x\n", - p->adapter_control); - size += sprintf(BLS, " Extended Translation: %sabled\n", - (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis"); - size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable); - if (p->features & (AHC_ULTRA | AHC_ULTRA2)) - { - size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb); - } - size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable); - size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag); - size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE); - size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host " - "instance %d:\n", p->instance); - size += sprintf(BLS, " {"); - for(i=0; i < (MAX_TARGETS - 1); i++) - size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]); - size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]); - size += sprintf(BLS, " Actual queue depth per device for aic7xxx host " - "instance %d:\n", p->instance); - size += sprintf(BLS, " {"); - for(i=0; i < (MAX_TARGETS - 1); i++) - size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]); - size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]); - - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Statistics:\n\n"); - for (target = 0; target < MAX_TARGETS; target++) - { - sp = &p->stats[target]; - if ((p->dev_flags[target] & DEVICE_PRESENT) == 0) - { - continue; - } - if (p->features & AHC_TWIN) - { - size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", - p->host_no, (target >> 3), (target & 0x7), 0); - } - else - { - size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", - p->host_no, 0, target, 0); - } - size += sprintf(BLS, " Device using %s/%s", - (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ? - "Wide" : "Narrow", - (p->transinfo[target].cur_offset != 0) ? - "Sync transfers at " : "Async transfers.\n" ); - if (p->transinfo[target].cur_offset != 0) - { - struct aic7xxx_syncrate *sync_rate; - unsigned char options = p->transinfo[target].cur_options; - int period = p->transinfo[target].cur_period; - int rate = (p->transinfo[target].cur_width == - MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0; - - sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options); - if (sync_rate != NULL) - { - size += sprintf(BLS, "%s MByte/sec, offset %d\n", - sync_rate->rate[rate], - p->transinfo[target].cur_offset ); - } - else - { - size += sprintf(BLS, "3.3 MByte/sec, offset %d\n", - p->transinfo[target].cur_offset ); - } - } - size += sprintf(BLS, " Transinfo settings: "); - size += sprintf(BLS, "current(%d/%d/%d/%d), ", - p->transinfo[target].cur_period, - p->transinfo[target].cur_offset, - p->transinfo[target].cur_width, - p->transinfo[target].cur_options); - size += sprintf(BLS, "goal(%d/%d/%d/%d), ", - p->transinfo[target].goal_period, - p->transinfo[target].goal_offset, - p->transinfo[target].goal_width, - p->transinfo[target].goal_options); - size += sprintf(BLS, "user(%d/%d/%d/%d)\n", - p->transinfo[target].user_period, - p->transinfo[target].user_offset, - p->transinfo[target].user_width, - p->transinfo[target].user_options); -#ifdef AIC7XXX_PROC_STATS - size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", - sp->r_total + sp->w_total, sp->r_total, sp->w_total); - size += sprintf(BLS, "%s\n", HDRB); - size += sprintf(BLS, " Reads:"); - for (i = 0; i < NUMBER(sp->r_bins); i++) - { - size += sprintf(BLS, " %7ld", sp->r_bins[i]); - } - size += sprintf(BLS, "\n"); - size += sprintf(BLS, " Writes:"); - for (i = 0; i < NUMBER(sp->w_bins); i++) - { - size += sprintf(BLS, " %7ld", sp->w_bins[i]); - } - size += sprintf(BLS, "\n"); -#else - size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n", - sp->r_total + sp->w_total, sp->r_total, sp->w_total); -#endif /* AIC7XXX_PROC_STATS */ - size += sprintf(BLS, "\n\n"); - } - - if (size >= aic7xxx_buffer_size) - { - printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n"); - } - - if (offset > size - 1) - { - kfree(aic7xxx_buffer); - aic7xxx_buffer = NULL; - aic7xxx_buffer_size = length = 0; - *start = NULL; - } - else - { - *start = buffer; - length = MIN(length, size - offset); - memcpy(buffer, &aic7xxx_buffer[offset], length); - } - - return (length); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h --- v2.4.2/linux/drivers/scsi/aic7xxx_reg.h Thu Feb 10 19:00:35 2000 +++ linux/drivers/scsi/aic7xxx_reg.h Wed Dec 31 16:00:00 1969 @@ -1,629 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated. - */ - -#define SCSISEQ 0x00 -#define TEMODE 0x80 -#define ENSELO 0x40 -#define ENSELI 0x20 -#define ENRSELI 0x10 -#define ENAUTOATNO 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNP 0x02 -#define SCSIRSTO 0x01 - -#define SXFRCTL0 0x01 -#define DFON 0x80 -#define DFPEXP 0x40 -#define FAST20 0x20 -#define CLRSTCNT 0x10 -#define SPIOEN 0x08 -#define SCAMEN 0x04 -#define CLRCHN 0x02 - -#define SXFRCTL1 0x02 -#define BITBUCKET 0x80 -#define SWRAPEN 0x40 -#define ENSPCHK 0x20 -#define STIMESEL 0x18 -#define ENSTIMER 0x04 -#define ACTNEGEN 0x02 -#define STPWEN 0x01 - -#define SCSISIGO 0x03 -#define CDO 0x80 -#define IOO 0x40 -#define MSGO 0x20 -#define ATNO 0x10 -#define SELO 0x08 -#define BSYO 0x04 -#define REQO 0x02 -#define ACKO 0x01 - -#define SCSISIGI 0x03 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 - -#define SCSIRATE 0x04 -#define WIDEXFER 0x80 -#define SXFR_ULTRA2 0x7f -#define SXFR 0x70 -#define SOFS 0x0f - -#define SCSIID 0x05 -#define SCSIOFFSET 0x05 -#define SOFS_ULTRA2 0x7f - -#define SCSIDATL 0x06 - -#define SCSIDATH 0x07 - -#define STCNT 0x08 - -#define OPTIONMODE 0x08 -#define AUTORATEEN 0x80 -#define AUTOACKEN 0x40 -#define ATNMGMNTEN 0x20 -#define BUSFREEREV 0x10 -#define EXPPHASEDIS 0x08 -#define SCSIDATL_IMGEN 0x04 -#define AUTO_MSGOUT_DE 0x02 -#define DIS_MSGIN_DUALEDGE 0x01 - -#define CLRSINT0 0x0b -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRSWRAP 0x08 -#define CLRSPIORDY 0x02 - -#define SSTAT0 0x0b -#define TARGET 0x80 -#define SELDO 0x40 -#define SELDI 0x20 -#define SELINGO 0x10 -#define IOERR 0x08 -#define SWRAP 0x08 -#define SDONE 0x04 -#define SPIORDY 0x02 -#define DMADONE 0x01 - -#define CLRSINT1 0x0c -#define CLRSELTIMEO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRPHASECHG 0x02 -#define CLRREQINIT 0x01 - -#define SSTAT1 0x0c -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define PHASECHG 0x02 -#define REQINIT 0x01 - -#define SSTAT2 0x0d -#define OVERRUN 0x80 -#define SHVALID 0x40 -#define WIDE_RES 0x20 -#define SFCNT 0x1f -#define EXP_ACTIVE 0x10 -#define CRCVALERR 0x08 -#define CRCENDERR 0x04 -#define CRCREQERR 0x02 -#define DUAL_EDGE_ERROR 0x01 - -#define SSTAT3 0x0e -#define SCSICNT 0xf0 -#define OFFCNT 0x0f - -#define SCSIID_ULTRA2 0x0f -#define OID 0x0f - -#define SIMODE0 0x10 -#define ENSELDO 0x40 -#define ENSELDI 0x20 -#define ENSELINGO 0x10 -#define ENIOERR 0x08 -#define ENSWRAP 0x08 -#define ENSDONE 0x04 -#define ENSPIORDY 0x02 -#define ENDMADONE 0x01 - -#define SIMODE1 0x11 -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENPHASECHG 0x02 -#define ENREQINIT 0x01 - -#define SCSIBUSL 0x12 - -#define SCSIBUSH 0x13 - -#define SHADDR 0x14 - -#define SELTIMER 0x18 -#define STAGE6 0x20 -#define STAGE5 0x10 -#define STAGE4 0x08 -#define STAGE3 0x04 -#define STAGE2 0x02 -#define STAGE1 0x01 - -#define SELID 0x19 -#define SELID_MASK 0xf0 -#define ONEBIT 0x08 - -#define SPIOCAP 0x1b -#define SOFT1 0x80 -#define SOFT0 0x40 -#define SOFTCMDEN 0x20 -#define HAS_BRDCTL 0x10 -#define SEEPROM 0x08 -#define EEPROM 0x04 -#define ROM 0x02 -#define SSPIOCPS 0x01 - -#define BRDCTL 0x1d -#define BRDDAT7 0x80 -#define BRDDAT6 0x40 -#define BRDDAT5 0x20 -#define BRDDAT4 0x10 -#define BRDSTB 0x10 -#define BRDCS 0x08 -#define BRDDAT3 0x08 -#define BRDDAT2 0x04 -#define BRDRW 0x04 -#define BRDRW_ULTRA2 0x02 -#define BRDCTL1 0x02 -#define BRDCTL0 0x01 -#define BRDSTB_ULTRA2 0x01 - -#define SEECTL 0x1e -#define EXTARBACK 0x80 -#define EXTARBREQ 0x40 -#define SEEMS 0x20 -#define SEERDY 0x10 -#define SEECS 0x08 -#define SEECK 0x04 -#define SEEDO 0x02 -#define SEEDI 0x01 - -#define SBLKCTL 0x1f -#define DIAGLEDEN 0x80 -#define DIAGLEDON 0x40 -#define AUTOFLUSHDIS 0x20 -#define ENAB40 0x08 -#define ENAB20 0x04 -#define SELWIDE 0x02 -#define XCVR 0x01 - -#define SRAM_BASE 0x20 - -#define TARG_SCSIRATE 0x20 - -#define ULTRA_ENB 0x30 - -#define DISC_DSB 0x32 - -#define MSG_OUT 0x34 - -#define DMAPARAMS 0x35 -#define PRELOADEN 0x80 -#define WIDEODD 0x40 -#define SCSIEN 0x20 -#define SDMAENACK 0x10 -#define SDMAEN 0x10 -#define HDMAEN 0x08 -#define HDMAENACK 0x08 -#define DIRECTION 0x04 -#define FIFOFLUSH 0x02 -#define FIFORESET 0x01 - -#define SEQ_FLAGS 0x36 -#define IDENTIFY_SEEN 0x80 -#define SCBPTR_VALID 0x20 -#define DPHASE 0x10 -#define AMTARGET 0x08 -#define WIDE_BUS 0x02 -#define TWIN_BUS 0x01 - -#define SAVED_TCL 0x37 - -#define SG_COUNT 0x38 - -#define SG_NEXT 0x39 - -#define LASTPHASE 0x3d -#define P_MESGIN 0xe0 -#define PHASE_MASK 0xe0 -#define P_STATUS 0xc0 -#define P_MESGOUT 0xa0 -#define P_COMMAND 0x80 -#define CDI 0x80 -#define IOI 0x40 -#define P_DATAIN 0x40 -#define MSGI 0x20 -#define P_BUSFREE 0x01 -#define P_DATAOUT 0x00 - -#define WAITING_SCBH 0x3e - -#define DISCONNECTED_SCBH 0x3f - -#define FREE_SCBH 0x40 - -#define HSCB_ADDR 0x41 - -#define SCBID_ADDR 0x45 - -#define TMODE_CMDADDR 0x49 - -#define KERNEL_QINPOS 0x4d - -#define QINPOS 0x4e - -#define QOUTPOS 0x4f - -#define TMODE_CMDADDR_NEXT 0x50 - -#define ARG_1 0x51 -#define RETURN_1 0x51 -#define SEND_MSG 0x80 -#define SEND_SENSE 0x40 -#define SEND_REJ 0x20 -#define MSGOUT_PHASEMIS 0x10 - -#define ARG_2 0x52 -#define RETURN_2 0x52 - -#define LAST_MSG 0x53 - -#define PREFETCH_CNT 0x54 - -#define SCSICONF 0x5a -#define TERM_ENB 0x80 -#define RESET_SCSI 0x40 -#define HWSCSIID 0x0f -#define HSCSIID 0x07 - -#define HOSTCONF 0x5d - -#define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 -#define BIOSDISABLED 0x30 -#define CHANNEL_B_PRIMARY 0x08 - -#define SEQCTL 0x60 -#define PERRORDIS 0x80 -#define PAUSEDIS 0x40 -#define FAILDIS 0x20 -#define FASTMODE 0x10 -#define BRKADRINTEN 0x08 -#define STEP 0x04 -#define SEQRESET 0x02 -#define LOADRAM 0x01 - -#define SEQRAM 0x61 - -#define SEQADDR0 0x62 - -#define SEQADDR1 0x63 -#define SEQADDR1_MASK 0x01 - -#define ACCUM 0x64 - -#define SINDEX 0x65 - -#define DINDEX 0x66 - -#define ALLONES 0x69 - -#define ALLZEROS 0x6a - -#define NONE 0x6a - -#define FLAGS 0x6b -#define ZERO 0x02 -#define CARRY 0x01 - -#define SINDIR 0x6c - -#define DINDIR 0x6d - -#define FUNCTION1 0x6e - -#define STACK 0x6f - -#define TARG_OFFSET 0x70 - -#define BCTL 0x84 -#define ACE 0x08 -#define ENABLE 0x01 - -#define DSCOMMAND0 0x84 -#define INTSCBRAMSEL 0x08 -#define RAMPS 0x04 -#define USCBSIZE32 0x02 -#define CIOPARCKEN 0x01 - -#define DSCOMMAND 0x84 -#define CACHETHEN 0x80 -#define DPARCKEN 0x40 -#define MPARCKEN 0x20 -#define EXTREQLCK 0x10 - -#define BUSTIME 0x85 -#define BOFF 0xf0 -#define BON 0x0f - -#define BUSSPD 0x86 -#define DFTHRSH 0xc0 -#define STBOFF 0x38 -#define STBON 0x07 - -#define DSPCISTATUS 0x86 -#define DFTHRSH_100 0xc0 - -#define HCNTRL 0x87 -#define POWRDN 0x40 -#define SWINT 0x10 -#define IRQMS 0x08 -#define PAUSE 0x04 -#define INTEN 0x02 -#define CHIPRST 0x01 -#define CHIPRSTACK 0x01 - -#define HADDR 0x88 - -#define HCNT 0x8c - -#define SCBPTR 0x90 - -#define INTSTAT 0x91 -#define SEQINT_MASK 0xf1 -#define DATA_OVERRUN 0xe1 -#define MSGIN_PHASEMIS 0xd1 -#define TRACEPOINT2 0xc1 -#define TRACEPOINT 0xb1 -#define AWAITING_MSG 0xa1 -#define RESIDUAL 0x81 -#define BAD_STATUS 0x71 -#define REJECT_MSG 0x61 -#define WIDE_RESIDUE 0x51 -#define EXTENDED_MSG 0x41 -#define NO_MATCH 0x31 -#define NO_IDENT 0x21 -#define SEND_REJECT 0x11 -#define INT_PEND 0x0f -#define BRKADRINT 0x08 -#define SCSIINT 0x04 -#define CMDCMPLT 0x02 -#define BAD_PHASE 0x01 -#define SEQINT 0x01 - -#define CLRINT 0x92 -#define CLRPARERR 0x10 -#define CLRBRKADRINT 0x08 -#define CLRSCSIINT 0x04 -#define CLRCMDINT 0x02 -#define CLRSEQINT 0x01 - -#define ERROR 0x92 -#define CIOPARERR 0x80 -#define PCIERRSTAT 0x40 -#define MPARERR 0x20 -#define DPARERR 0x10 -#define SQPARERR 0x08 -#define ILLOPCODE 0x04 -#define DSCTMOUT 0x02 -#define ILLSADDR 0x02 -#define ILLHADDR 0x01 - -#define DFCNTRL 0x93 - -#define DFSTATUS 0x94 -#define PRELOAD_AVAIL 0x80 -#define DWORDEMP 0x20 -#define MREQPEND 0x10 -#define HDONE 0x08 -#define DFTHRESH 0x04 -#define FIFOFULL 0x02 -#define FIFOEMP 0x01 - -#define DFDAT 0x99 - -#define SCBCNT 0x9a -#define SCBAUTO 0x80 -#define SCBCNT_MASK 0x1f - -#define QINFIFO 0x9b - -#define QINCNT 0x9c - -#define SCSIDATL_IMG 0x9c - -#define QOUTFIFO 0x9d - -#define CRCCONTROL1 0x9d -#define CRCONSEEN 0x80 -#define CRCVALCHKEN 0x40 -#define CRCENDCHKEN 0x20 -#define CRCREQCHKEN 0x10 -#define TARGCRCENDEN 0x08 -#define TARGCRCCNTEN 0x04 - -#define QOUTCNT 0x9e - -#define SCSIPHASE 0x9e -#define SP_STATUS 0x20 -#define SP_COMMAND 0x10 -#define SP_MSG_IN 0x08 -#define SP_MSG_OUT 0x04 -#define SP_DATA_IN 0x02 -#define SP_DATA_OUT 0x01 - -#define SFUNCT 0x9f -#define ALT_MODE 0x80 - -#define SCB_CONTROL 0xa0 -#define MK_MESSAGE 0x80 -#define DISCENB 0x40 -#define TAG_ENB 0x20 -#define DISCONNECTED 0x04 -#define SCB_TAG_TYPE 0x03 - -#define SCB_BASE 0xa0 - -#define SCB_TCL 0xa1 -#define TID 0xf0 -#define SELBUSB 0x08 -#define LID 0x07 - -#define SCB_TARGET_STATUS 0xa2 - -#define SCB_SGCOUNT 0xa3 - -#define SCB_SGPTR 0xa4 - -#define SCB_RESID_SGCNT 0xa8 - -#define SCB_RESID_DCNT 0xa9 - -#define SCB_DATAPTR 0xac - -#define SCB_DATACNT 0xb0 - -#define SCB_CMDPTR 0xb4 - -#define SCB_CMDLEN 0xb8 - -#define SCB_TAG 0xb9 - -#define SCB_NEXT 0xba - -#define SCB_PREV 0xbb - -#define SCB_BUSYTARGETS 0xbc - -#define SEECTL_2840 0xc0 -#define CS_2840 0x04 -#define CK_2840 0x02 -#define DO_2840 0x01 - -#define STATUS_2840 0xc1 -#define EEPROM_TF 0x80 -#define BIOS_SEL 0x60 -#define ADSEL 0x1e -#define DI_2840 0x01 - -#define CCHADDR 0xe0 - -#define CCHCNT 0xe8 - -#define CCSGRAM 0xe9 - -#define CCSGADDR 0xea - -#define CCSGCTL 0xeb -#define CCSGDONE 0x80 -#define CCSGEN 0x08 -#define FLAG 0x02 -#define CCSGRESET 0x01 - -#define CCSCBRAM 0xec - -#define CCSCBADDR 0xed - -#define CCSCBCTL 0xee -#define CCSCBDONE 0x80 -#define ARRDONE 0x40 -#define CCARREN 0x10 -#define CCSCBEN 0x08 -#define CCSCBDIR 0x04 -#define CCSCBRESET 0x01 - -#define CCSCBCNT 0xef - -#define CCSCBPTR 0xf1 - -#define HNSCB_QOFF 0xf4 - -#define HESCB_QOFF 0xf5 - -#define SNSCB_QOFF 0xf6 - -#define SESCB_QOFF 0xf7 - -#define SDSCB_QOFF 0xf8 - -#define QOFF_CTLSTA 0xfa -#define ESTABLISH_SCB_AVAIL 0x80 -#define SCB_AVAIL 0x40 -#define SNSCB_ROLLOVER 0x20 -#define SDSCB_ROLLOVER 0x10 -#define SESCB_ROLLOVER 0x08 -#define SCB_QSIZE 0x07 -#define SCB_QSIZE_256 0x06 - -#define DFF_THRSH 0xfb -#define WR_DFTHRSH 0x70 -#define WR_DFTHRSH_MAX 0x70 -#define WR_DFTHRSH_90 0x60 -#define WR_DFTHRSH_85 0x50 -#define WR_DFTHRSH_75 0x40 -#define WR_DFTHRSH_63 0x30 -#define WR_DFTHRSH_50 0x20 -#define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 -#define RD_DFTHRSH 0x07 -#define RD_DFTHRSH_90 0x06 -#define RD_DFTHRSH_85 0x05 -#define RD_DFTHRSH_75 0x04 -#define RD_DFTHRSH_63 0x03 -#define RD_DFTHRSH_50 0x02 -#define RD_DFTHRSH_25 0x01 -#define RD_DFTHRSH_MIN 0x00 -#define WR_DFTHRSH_MIN 0x00 - -#define SG_CACHEPTR 0xfc -#define SG_USER_DATA 0xfc -#define LAST_SEG 0x02 -#define LAST_SEG_DONE 0x01 - - -#define CMD_GROUP_CODE_SHIFT 0x05 -#define BUS_8_BIT 0x00 -#define QOUTFIFO_OFFSET 0x01 -#define CCSGRAM_MAXSEGS 0x10 -#define CMD_GROUP2_BYTE_DELTA 0xfa -#define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 -#define QINFIFO_OFFSET 0x02 -#define CMD_GROUP5_BYTE_DELTA 0x0b -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define UNTAGGEDSCB_OFFSET 0x00 -#define SCB_LIST_NULL 0xff -#define SG_SIZEOF 0x08 -#define CMD_GROUP4_BYTE_DELTA 0x04 -#define CMD_GROUP0_BYTE_DELTA 0xfc -#define HOST_MSG 0xff -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 - - -/* Downloaded Constant Definitions */ -#define TMODE_NUMCMDS 0x00 diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_seq.c --- v2.4.2/linux/drivers/scsi/aic7xxx_seq.c Wed Jun 21 17:25:03 2000 +++ linux/drivers/scsi/aic7xxx_seq.c Wed Dec 31 16:00:00 1969 @@ -1,745 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated. - */ -static unsigned char seqprog[] = { - 0xff, 0x6a, 0x06, 0x08, - 0x7f, 0x02, 0x04, 0x08, - 0x12, 0x6a, 0x00, 0x00, - 0xff, 0x6a, 0xd6, 0x09, - 0xff, 0x6a, 0xdc, 0x09, - 0x00, 0x65, 0xca, 0x58, - 0xf7, 0x01, 0x02, 0x08, - 0xff, 0x4e, 0xc8, 0x08, - 0xbf, 0x60, 0xc0, 0x08, - 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0c, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0c, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0xff, 0x3e, 0x48, 0x60, - 0x40, 0xfa, 0x10, 0x78, - 0xff, 0xf6, 0xd4, 0x08, - 0x01, 0x4e, 0x9c, 0x18, - 0x40, 0x60, 0xc0, 0x00, - 0x00, 0x4d, 0x10, 0x70, - 0x01, 0x4e, 0x9c, 0x18, - 0xbf, 0x60, 0xc0, 0x08, - 0x00, 0x6a, 0x3e, 0x5c, - 0xff, 0x4e, 0xc8, 0x18, - 0x02, 0x6a, 0x54, 0x5b, - 0xff, 0x52, 0x20, 0x09, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x52, 0xca, 0x5b, - 0x03, 0xb0, 0x52, 0x31, - 0xff, 0xb0, 0x52, 0x09, - 0xff, 0xb1, 0x54, 0x09, - 0xff, 0xb2, 0x56, 0x09, - 0xff, 0xa3, 0x50, 0x09, - 0xff, 0x3e, 0x74, 0x09, - 0xff, 0x90, 0x7c, 0x08, - 0xff, 0x3e, 0x20, 0x09, - 0x00, 0x65, 0x4e, 0x58, - 0x00, 0x65, 0x0c, 0x40, - 0xf7, 0x1f, 0xca, 0x08, - 0x08, 0xa1, 0xc8, 0x08, - 0x00, 0x65, 0xca, 0x00, - 0xff, 0x65, 0x3e, 0x08, - 0xf0, 0xa1, 0xc8, 0x08, - 0x0f, 0x0f, 0x1e, 0x08, - 0x00, 0x0f, 0x1e, 0x00, - 0xf0, 0xa1, 0xc8, 0x08, - 0x0f, 0x05, 0x0a, 0x08, - 0x00, 0x05, 0x0a, 0x00, - 0xff, 0x6a, 0x0c, 0x08, - 0x5a, 0x6a, 0x00, 0x04, - 0x12, 0x65, 0x02, 0x00, - 0x31, 0x6a, 0xca, 0x00, - 0x80, 0x37, 0x6e, 0x68, - 0xff, 0x65, 0xca, 0x18, - 0xff, 0x37, 0xdc, 0x08, - 0xff, 0x6e, 0xc8, 0x08, - 0x00, 0x6c, 0x76, 0x78, - 0x20, 0x01, 0x02, 0x00, - 0x4c, 0x37, 0xc8, 0x28, - 0x08, 0x1f, 0x7e, 0x78, - 0x08, 0x37, 0x6e, 0x00, - 0x08, 0x64, 0xc8, 0x00, - 0x70, 0x64, 0xca, 0x18, - 0xff, 0x6c, 0x0a, 0x08, - 0x20, 0x64, 0xca, 0x18, - 0xff, 0x6c, 0x08, 0x0c, - 0x40, 0x0b, 0x96, 0x68, - 0x20, 0x6a, 0x16, 0x00, - 0xf0, 0x19, 0x6e, 0x08, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x08, 0x6a, 0x66, 0x58, - 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x12, 0x6a, 0x00, 0x00, - 0x40, 0x6a, 0x16, 0x00, - 0xff, 0x3e, 0x20, 0x09, - 0xff, 0xba, 0x7c, 0x08, - 0xff, 0xa1, 0x6e, 0x08, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x08, 0x6a, 0x66, 0x58, - 0x80, 0x6a, 0x68, 0x00, - 0x80, 0x36, 0x6c, 0x00, - 0x00, 0x65, 0x9e, 0x5b, - 0xff, 0x3d, 0xc8, 0x08, - 0xbf, 0x64, 0xe2, 0x78, - 0x80, 0x64, 0xac, 0x71, - 0xa0, 0x64, 0xdc, 0x71, - 0xc0, 0x64, 0xd4, 0x71, - 0xe0, 0x64, 0x1c, 0x72, - 0x01, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xca, 0x58, - 0xff, 0x06, 0xd4, 0x08, - 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xc4, 0x78, - 0x08, 0x0c, 0x0c, 0x68, - 0x01, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0x26, 0x09, - 0x02, 0x6a, 0x08, 0x30, - 0xff, 0x6a, 0x08, 0x08, - 0xdf, 0x01, 0x02, 0x08, - 0x01, 0x6a, 0x7a, 0x00, - 0xff, 0x6a, 0x6c, 0x0c, - 0x04, 0x14, 0x10, 0x31, - 0x03, 0xa9, 0x18, 0x31, - 0x03, 0xa9, 0x10, 0x30, - 0x08, 0x6a, 0xcc, 0x00, - 0xa9, 0x6a, 0xb4, 0x5b, - 0x00, 0x65, 0x02, 0x41, - 0xa8, 0x6a, 0x6a, 0x00, - 0x79, 0x6a, 0x6a, 0x00, - 0x40, 0x3d, 0xea, 0x68, - 0x04, 0x35, 0x6a, 0x00, - 0x00, 0x65, 0x0e, 0x5b, - 0x80, 0x6a, 0xd4, 0x01, - 0x10, 0x36, 0xd6, 0x68, - 0x10, 0x36, 0x6c, 0x00, - 0x07, 0xac, 0x10, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0x05, 0xa3, 0x70, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xac, 0x5b, - 0x00, 0x65, 0xa6, 0x5b, - 0x38, 0x6a, 0xcc, 0x00, - 0xa3, 0x6a, 0xb0, 0x5b, - 0xff, 0x38, 0x12, 0x69, - 0x80, 0x02, 0x04, 0x00, - 0xe7, 0x35, 0x6a, 0x08, - 0x03, 0x69, 0x18, 0x31, - 0x03, 0x69, 0x10, 0x30, - 0xff, 0x6a, 0x10, 0x00, - 0xff, 0x6a, 0x12, 0x00, - 0xff, 0x6a, 0x14, 0x00, - 0x01, 0x38, 0x18, 0x61, - 0xbf, 0x35, 0x6a, 0x08, - 0x02, 0x6a, 0xf8, 0x01, - 0xff, 0x69, 0xca, 0x08, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x1c, 0x69, - 0x04, 0x0b, 0x28, 0x69, - 0x10, 0x0c, 0x1e, 0x79, - 0x04, 0x0b, 0x28, 0x69, - 0xff, 0x6a, 0xca, 0x08, - 0x00, 0x35, 0xee, 0x5a, - 0x80, 0x02, 0x7c, 0x69, - 0xff, 0x65, 0x6c, 0x79, - 0xff, 0x38, 0x70, 0x18, - 0xff, 0x38, 0x6c, 0x79, - 0x80, 0xea, 0x48, 0x61, - 0xef, 0x38, 0xc8, 0x18, - 0x80, 0x6a, 0xc8, 0x00, - 0x00, 0x65, 0x3a, 0x49, - 0x33, 0x38, 0xc8, 0x28, - 0xff, 0x64, 0xd0, 0x09, - 0x04, 0x39, 0xc0, 0x31, - 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x40, 0x79, - 0xf7, 0xeb, 0xd6, 0x09, - 0x08, 0xeb, 0x44, 0x69, - 0x01, 0x6a, 0xd6, 0x01, - 0x08, 0xe9, 0x10, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0x39, 0x6a, 0xb2, 0x5b, - 0x08, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0x88, 0x6a, 0x20, 0x5c, - 0x00, 0x65, 0xa6, 0x5b, - 0xff, 0x6a, 0xc8, 0x08, - 0x08, 0x39, 0x72, 0x18, - 0x00, 0x3a, 0x74, 0x20, - 0x01, 0x0c, 0x64, 0x79, - 0x10, 0x0c, 0x02, 0x79, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x0b, 0x6a, 0x69, - 0x00, 0x65, 0x84, 0x59, - 0x03, 0x08, 0x52, 0x31, - 0xff, 0x38, 0x50, 0x09, - 0xff, 0x08, 0x52, 0x09, - 0xff, 0x09, 0x54, 0x09, - 0xff, 0x0a, 0x56, 0x09, - 0xff, 0x38, 0x50, 0x09, - 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x84, 0x59, - 0x7f, 0x02, 0x04, 0x08, - 0xe1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0x04, 0x93, 0x9a, 0x69, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0x88, 0x69, - 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x01, 0x94, 0x8a, 0x79, - 0x10, 0x94, 0x98, 0x69, - 0x7f, 0x05, 0xa0, 0x69, - 0x02, 0x03, 0xa0, 0x79, - 0x11, 0x0c, 0x9c, 0x79, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xa2, 0x69, - 0x03, 0x08, 0x52, 0x31, - 0xff, 0x38, 0x50, 0x09, - 0x12, 0x01, 0x02, 0x00, - 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x0e, 0x5b, - 0x05, 0xb4, 0x10, 0x31, - 0x02, 0x6a, 0x1a, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0xb4, 0x6a, 0xb0, 0x5b, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x00, 0x65, 0xa6, 0x5b, - 0x3d, 0x6a, 0xee, 0x5a, - 0xac, 0x6a, 0x26, 0x01, - 0x04, 0x0b, 0xc2, 0x69, - 0x04, 0x0b, 0xc8, 0x69, - 0x10, 0x0c, 0xc4, 0x79, - 0x02, 0x03, 0xcc, 0x79, - 0x11, 0x0c, 0xc8, 0x79, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xce, 0x69, - 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x0e, 0x5b, - 0xff, 0x06, 0x44, 0x09, - 0x00, 0x65, 0xaa, 0x40, - 0x10, 0x3d, 0x06, 0x00, - 0xff, 0x34, 0xca, 0x08, - 0x80, 0x65, 0x00, 0x62, - 0x0f, 0xa1, 0xca, 0x08, - 0x07, 0xa1, 0xca, 0x08, - 0x40, 0xa0, 0xc8, 0x08, - 0x00, 0x65, 0xca, 0x00, - 0x80, 0x65, 0xca, 0x00, - 0x80, 0xa0, 0xf0, 0x79, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x02, 0x42, - 0x20, 0xa0, 0x08, 0x7a, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0x10, 0x62, - 0x23, 0xa0, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0x10, 0x62, - 0x00, 0xb9, 0x08, 0x42, - 0xff, 0x65, 0x08, 0x62, - 0xa1, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x10, 0x51, 0x10, 0x72, - 0x40, 0x6a, 0x18, 0x00, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xa0, 0x3d, 0xda, 0x71, - 0x40, 0x6a, 0x18, 0x00, - 0xff, 0x34, 0xa6, 0x08, - 0x80, 0x34, 0x18, 0x62, - 0x7f, 0xa0, 0x40, 0x09, - 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x64, 0x6a, 0xe4, 0x5a, - 0x80, 0x64, 0x8e, 0x6a, - 0x04, 0x64, 0x70, 0x72, - 0x02, 0x64, 0x76, 0x72, - 0x00, 0x6a, 0x38, 0x72, - 0x03, 0x64, 0x8a, 0x72, - 0x01, 0x64, 0x6c, 0x72, - 0x07, 0x64, 0xcc, 0x72, - 0x08, 0x64, 0x34, 0x72, - 0x23, 0x64, 0xd0, 0x72, - 0x11, 0x6a, 0x22, 0x01, - 0x07, 0x6a, 0xd6, 0x5a, - 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0xaa, 0x40, - 0xff, 0xa8, 0x3c, 0x6a, - 0xff, 0xa2, 0x54, 0x7a, - 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, - 0xff, 0xa2, 0x54, 0x7a, - 0x71, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x40, 0x51, 0x54, 0x62, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, - 0xff, 0x3e, 0x74, 0x09, - 0xff, 0x90, 0x7c, 0x08, - 0x00, 0x65, 0x4e, 0x58, - 0x00, 0x65, 0xbc, 0x40, - 0x20, 0xa0, 0x5c, 0x6a, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x74, 0x5b, - 0xff, 0x6a, 0x8a, 0x5b, - 0xff, 0xf8, 0xc8, 0x08, - 0xff, 0x4f, 0xc8, 0x08, - 0x01, 0x6a, 0x74, 0x5b, - 0x00, 0xb9, 0x8a, 0x5b, - 0x01, 0x4f, 0x9e, 0x18, - 0x02, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x38, 0x5c, - 0x00, 0x65, 0xbc, 0x40, - 0x41, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0x04, 0xa0, 0x40, 0x01, - 0x00, 0x65, 0x50, 0x5c, - 0x00, 0x65, 0xbc, 0x40, - 0x10, 0x36, 0x34, 0x7a, - 0x05, 0x38, 0x46, 0x31, - 0x04, 0x14, 0x58, 0x31, - 0x03, 0xa9, 0x60, 0x31, - 0xa3, 0x6a, 0xcc, 0x00, - 0x38, 0x6a, 0xb0, 0x5b, - 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xb2, 0x5b, - 0xa9, 0x6a, 0xb4, 0x5b, - 0x00, 0x65, 0x34, 0x42, - 0xef, 0x36, 0x6c, 0x08, - 0x00, 0x65, 0x34, 0x42, - 0x0f, 0x64, 0xc8, 0x08, - 0x07, 0x64, 0xc8, 0x08, - 0x00, 0x37, 0x6e, 0x00, - 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x44, 0x5b, - 0xff, 0x51, 0xa0, 0x72, - 0x20, 0x36, 0xaa, 0x7a, - 0x00, 0x90, 0x32, 0x5b, - 0x00, 0x65, 0xac, 0x42, - 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0x9e, 0x5b, - 0xe0, 0x3d, 0xc6, 0x62, - 0x20, 0x12, 0xc6, 0x62, - 0x51, 0x6a, 0xda, 0x5a, - 0x00, 0x65, 0x2c, 0x5b, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0xa1, 0xbe, 0x62, - 0x04, 0xa0, 0xbe, 0x7a, - 0xfb, 0xa0, 0x40, 0x09, - 0x80, 0x36, 0x6c, 0x00, - 0x80, 0xa0, 0x34, 0x7a, - 0x7f, 0xa0, 0x40, 0x09, - 0xff, 0x6a, 0xd6, 0x5a, - 0x00, 0x65, 0x34, 0x42, - 0x04, 0xa0, 0xc4, 0x7a, - 0x00, 0x65, 0x50, 0x5c, - 0x00, 0x65, 0xc6, 0x42, - 0x00, 0x65, 0x38, 0x5c, - 0x31, 0x6a, 0x22, 0x01, - 0x0c, 0x6a, 0xd6, 0x5a, - 0x00, 0x65, 0x34, 0x42, - 0x61, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x34, 0x42, - 0x51, 0x6a, 0xda, 0x5a, - 0x51, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x34, 0x42, - 0x10, 0x3d, 0x06, 0x00, - 0xff, 0x65, 0x68, 0x0c, - 0xff, 0x06, 0xd4, 0x08, - 0x01, 0x0c, 0xdc, 0x7a, - 0x04, 0x0c, 0xde, 0x6a, - 0xe0, 0x03, 0x7a, 0x08, - 0xe0, 0x3d, 0xea, 0x62, - 0xff, 0x65, 0xcc, 0x08, - 0xff, 0x12, 0xda, 0x0c, - 0xff, 0x06, 0xd4, 0x0c, - 0xd1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0xff, 0x65, 0x26, 0x09, - 0x01, 0x0b, 0xfe, 0x6a, - 0x10, 0x0c, 0xf0, 0x7a, - 0x04, 0x0b, 0xf8, 0x6a, - 0xff, 0x6a, 0xca, 0x08, - 0x04, 0x93, 0xfc, 0x6a, - 0x01, 0x94, 0xfa, 0x7a, - 0x10, 0x94, 0xfc, 0x6a, - 0x80, 0x3d, 0x02, 0x73, - 0x0f, 0x04, 0x06, 0x6b, - 0x02, 0x03, 0x06, 0x7b, - 0x11, 0x0c, 0x02, 0x7b, - 0xc7, 0x93, 0x26, 0x09, - 0xff, 0x99, 0xd4, 0x08, - 0x38, 0x93, 0x08, 0x6b, - 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0x36, 0x0c, 0x6b, - 0x21, 0x6a, 0x22, 0x05, - 0xff, 0x65, 0x20, 0x09, - 0xff, 0x51, 0x1a, 0x63, - 0xff, 0x37, 0xc8, 0x08, - 0xa1, 0x6a, 0x26, 0x43, - 0xff, 0x51, 0xc8, 0x08, - 0xb9, 0x6a, 0x26, 0x43, - 0xff, 0x90, 0xa4, 0x08, - 0xff, 0xba, 0x2a, 0x73, - 0xff, 0xba, 0x20, 0x09, - 0xff, 0x65, 0xca, 0x18, - 0x00, 0x6c, 0x1e, 0x63, - 0xff, 0x90, 0xca, 0x0c, - 0xff, 0x6a, 0xca, 0x04, - 0x20, 0x36, 0x3e, 0x7b, - 0x00, 0x90, 0x12, 0x5b, - 0xff, 0x65, 0x3e, 0x73, - 0xff, 0x52, 0x3c, 0x73, - 0xff, 0xba, 0xcc, 0x08, - 0xff, 0x52, 0x20, 0x09, - 0xff, 0x66, 0x74, 0x09, - 0xff, 0x65, 0x20, 0x0d, - 0xff, 0xba, 0x7e, 0x0c, - 0x00, 0x6a, 0x3e, 0x5c, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x51, 0xca, 0x43, - 0xff, 0x3f, 0x98, 0x73, - 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3f, 0x12, 0x5b, - 0xff, 0x65, 0x98, 0x73, - 0x20, 0x36, 0x6c, 0x00, - 0x20, 0xa0, 0x52, 0x6b, - 0xff, 0xb9, 0xa2, 0x0c, - 0xff, 0x6a, 0xa2, 0x04, - 0xff, 0x65, 0xa4, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, - 0x01, 0x6a, 0xd0, 0x01, - 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x5e, 0x7b, - 0x01, 0x6a, 0xd6, 0x01, - 0x01, 0xe9, 0xa4, 0x34, - 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, - 0x01, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x0d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0xff, 0x99, 0xa4, 0x0c, - 0xff, 0x65, 0xa4, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, - 0x01, 0x6a, 0xd0, 0x01, - 0x01, 0x6a, 0xdc, 0x05, - 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xbe, 0x5b, - 0x01, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x01, 0x6a, 0x26, 0x05, - 0x01, 0x65, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x8e, 0x7b, - 0xff, 0x6a, 0xdc, 0x0d, - 0xff, 0x65, 0x32, 0x09, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x44, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x54, 0x5b, - 0xff, 0x52, 0xa2, 0x0c, - 0x01, 0x0c, 0x9e, 0x7b, - 0x04, 0x0c, 0x9e, 0x6b, - 0xe0, 0x03, 0x06, 0x08, - 0xe0, 0x03, 0x7a, 0x0c, - 0xff, 0x8c, 0x10, 0x08, - 0xff, 0x8d, 0x12, 0x08, - 0xff, 0x8e, 0x14, 0x0c, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x0c, - 0x3d, 0x64, 0xa4, 0x28, - 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x6c, 0xda, 0x18, - 0xff, 0x52, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0xff, 0x6a, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0x00, 0x6c, 0xda, 0x24, - 0xff, 0x65, 0xc8, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xba, 0x5b, - 0xff, 0x90, 0xe2, 0x09, - 0x20, 0x6a, 0xd0, 0x01, - 0x04, 0x35, 0xdc, 0x7b, - 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xd8, 0x63, - 0x00, 0x65, 0xe8, 0x43, - 0x01, 0x6a, 0xdc, 0x01, - 0x20, 0xa0, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xe2, 0x7b, - 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0xe6, 0x63, - 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0xea, 0x6b, - 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xba, 0x5b, - 0x20, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x35, 0x14, 0x6c, - 0xa0, 0x6a, 0xca, 0x00, - 0x20, 0x65, 0xc8, 0x18, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0x00, 0x65, 0x00, 0x64, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x30, 0x5c, - 0x04, 0x35, 0x0c, 0x7b, - 0xa0, 0x6a, 0x20, 0x5c, - 0x00, 0x65, 0x22, 0x5c, - 0x00, 0x65, 0x22, 0x5c, - 0x00, 0x65, 0x22, 0x44, - 0xff, 0x65, 0xcc, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x0c, - 0x08, 0x94, 0x30, 0x7c, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x34, 0x6c, - 0xff, 0x6a, 0xd4, 0x0c, - 0xff, 0x40, 0x74, 0x09, - 0xff, 0x90, 0x80, 0x08, - 0xff, 0x6a, 0x72, 0x05, - 0xff, 0x40, 0x4c, 0x64, - 0xff, 0x3f, 0x44, 0x64, - 0xff, 0x6a, 0xca, 0x04, - 0xff, 0x3f, 0x20, 0x09, - 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xca, 0x5b, - 0xff, 0xba, 0x7e, 0x0c, - 0xff, 0x40, 0x20, 0x09, - 0xff, 0xba, 0x80, 0x0c, - 0xff, 0x3f, 0x74, 0x09, - 0xff, 0x90, 0x7e, 0x0c, -}; - -static int aic7xxx_patch12_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch12_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_WIDE) != 0); -} - -static int aic7xxx_patch11_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch11_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA2) == 0); -} - -static int aic7xxx_patch10_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch10_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_CMD_CHAN) == 0); -} - -static int aic7xxx_patch9_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch9_func(struct aic7xxx_host *p) -{ - return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895); -} - -static int aic7xxx_patch8_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch8_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA) != 0); -} - -static int aic7xxx_patch7_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch7_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA2) != 0); -} - -static int aic7xxx_patch6_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch6_func(struct aic7xxx_host *p) -{ - return ((p->flags & AHC_PAGESCBS) == 0); -} - -static int aic7xxx_patch5_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch5_func(struct aic7xxx_host *p) -{ - return ((p->flags & AHC_PAGESCBS) != 0); -} - -static int aic7xxx_patch4_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch4_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_QUEUE_REGS) != 0); -} - -static int aic7xxx_patch3_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch3_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_TWIN) != 0); -} - -static int aic7xxx_patch2_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch2_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_QUEUE_REGS) == 0); -} - -static int aic7xxx_patch1_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch1_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_CMD_CHAN) != 0); -} - -static int aic7xxx_patch0_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch0_func(struct aic7xxx_host *p) -{ - return (0); -} - -struct sequencer_patch { - int (*patch_func)(struct aic7xxx_host *); - unsigned int begin :10, - skip_instr :10, - skip_patch :12; -} sequencer_patches[] = { - { aic7xxx_patch1_func, 3, 2, 1 }, - { aic7xxx_patch2_func, 7, 1, 1 }, - { aic7xxx_patch2_func, 8, 1, 1 }, - { aic7xxx_patch3_func, 11, 4, 1 }, - { aic7xxx_patch4_func, 16, 3, 2 }, - { aic7xxx_patch0_func, 19, 4, 1 }, - { aic7xxx_patch5_func, 23, 1, 1 }, - { aic7xxx_patch6_func, 26, 1, 1 }, - { aic7xxx_patch1_func, 29, 1, 2 }, - { aic7xxx_patch0_func, 30, 3, 1 }, - { aic7xxx_patch3_func, 39, 4, 1 }, - { aic7xxx_patch7_func, 43, 3, 2 }, - { aic7xxx_patch0_func, 46, 3, 1 }, - { aic7xxx_patch8_func, 52, 7, 1 }, - { aic7xxx_patch3_func, 60, 3, 1 }, - { aic7xxx_patch7_func, 63, 2, 1 }, - { aic7xxx_patch7_func, 102, 1, 2 }, - { aic7xxx_patch0_func, 103, 2, 1 }, - { aic7xxx_patch7_func, 107, 2, 1 }, - { aic7xxx_patch9_func, 109, 1, 1 }, - { aic7xxx_patch10_func, 110, 2, 1 }, - { aic7xxx_patch7_func, 113, 1, 2 }, - { aic7xxx_patch0_func, 114, 1, 1 }, - { aic7xxx_patch1_func, 118, 1, 1 }, - { aic7xxx_patch1_func, 121, 3, 2 }, - { aic7xxx_patch0_func, 124, 5, 1 }, - { aic7xxx_patch1_func, 132, 2, 3 }, - { aic7xxx_patch7_func, 132, 1, 1 }, - { aic7xxx_patch0_func, 134, 3, 1 }, - { aic7xxx_patch11_func, 138, 1, 2 }, - { aic7xxx_patch0_func, 139, 1, 1 }, - { aic7xxx_patch7_func, 140, 7, 2 }, - { aic7xxx_patch0_func, 147, 1, 1 }, - { aic7xxx_patch1_func, 152, 14, 3 }, - { aic7xxx_patch11_func, 165, 1, 1 }, - { aic7xxx_patch0_func, 166, 9, 1 }, - { aic7xxx_patch7_func, 180, 2, 1 }, - { aic7xxx_patch7_func, 182, 1, 1 }, - { aic7xxx_patch11_func, 183, 6, 3 }, - { aic7xxx_patch1_func, 183, 2, 2 }, - { aic7xxx_patch0_func, 185, 4, 1 }, - { aic7xxx_patch7_func, 190, 1, 1 }, - { aic7xxx_patch7_func, 194, 20, 1 }, - { aic7xxx_patch1_func, 215, 3, 3 }, - { aic7xxx_patch11_func, 217, 1, 1 }, - { aic7xxx_patch0_func, 218, 5, 1 }, - { aic7xxx_patch11_func, 223, 1, 2 }, - { aic7xxx_patch0_func, 224, 9, 1 }, - { aic7xxx_patch12_func, 240, 1, 2 }, - { aic7xxx_patch0_func, 241, 1, 1 }, - { aic7xxx_patch4_func, 302, 1, 2 }, - { aic7xxx_patch0_func, 303, 1, 1 }, - { aic7xxx_patch2_func, 306, 1, 1 }, - { aic7xxx_patch1_func, 316, 3, 2 }, - { aic7xxx_patch0_func, 319, 5, 1 }, - { aic7xxx_patch12_func, 327, 1, 2 }, - { aic7xxx_patch0_func, 328, 1, 1 }, - { aic7xxx_patch5_func, 333, 1, 1 }, - { aic7xxx_patch11_func, 375, 15, 1 }, - { aic7xxx_patch1_func, 427, 7, 2 }, - { aic7xxx_patch0_func, 434, 8, 1 }, - { aic7xxx_patch1_func, 443, 4, 2 }, - { aic7xxx_patch0_func, 447, 6, 1 }, - { aic7xxx_patch1_func, 453, 4, 2 }, - { aic7xxx_patch0_func, 457, 3, 1 }, - { aic7xxx_patch10_func, 467, 10, 1 }, - { aic7xxx_patch1_func, 486, 17, 4 }, - { aic7xxx_patch9_func, 494, 4, 2 }, - { aic7xxx_patch0_func, 498, 2, 1 }, - { aic7xxx_patch0_func, 503, 33, 1 }, - { aic7xxx_patch10_func, 536, 4, 1 }, - { aic7xxx_patch5_func, 540, 2, 1 }, - { aic7xxx_patch5_func, 543, 9, 1 }, - -}; diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/atari_dma_emul.c linux/drivers/scsi/atari_dma_emul.c --- v2.4.2/linux/drivers/scsi/atari_dma_emul.c Sat Jan 9 19:16:43 1999 +++ linux/drivers/scsi/atari_dma_emul.c Tue Mar 6 19:44:37 2001 @@ -131,7 +131,7 @@ * * 4. When this function is left, the address pointer (start_addr) is * converted to a physical address. Because it points one byte - * further than the last transfered byte, it can point outside the + * further than the last transferred byte, it can point outside the * current page. If virt_to_phys() is called with this address we * might get an access error. Therefore virt_to_phys() is called with * start_addr - 1 if the count has reached zero. The result is diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c --- v2.4.2/linux/drivers/scsi/atari_scsi.c Mon Nov 27 17:57:34 2000 +++ linux/drivers/scsi/atari_scsi.c Tue Mar 6 19:44:37 2001 @@ -690,19 +690,30 @@ /* This int is actually "pseudo-slow", i.e. it acts like a slow * interrupt after having cleared the pending flag for the DMA * interrupt. */ - request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW, - "SCSI NCR5380", scsi_tt_intr); + if (request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW, + "SCSI NCR5380", scsi_tt_intr)) { + printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting",IRQ_TT_MFP_SCSI); + scsi_unregister(atari_scsi_host); + atari_stram_free(atari_dma_buffer); + atari_dma_buffer = 0; + return 0; + } tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */ #ifdef REAL_DMA tt_scsi_dma.dma_ctrl = 0; atari_dma_residual = 0; -#endif /* REAL_DMA */ -#ifdef REAL_DMA #ifdef CONFIG_TT_DMA_EMUL if (MACH_IS_HADES) { - request_irq(IRQ_AUTO_2, hades_dma_emulator, - IRQ_TYPE_PRIO, "Hades DMA emulator", - hades_dma_emulator); + if (request_irq(IRQ_AUTO_2, hades_dma_emulator, + IRQ_TYPE_PRIO, "Hades DMA emulator", + hades_dma_emulator)) { + printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting (MACH_IS_HADES)",IRQ_AUTO_2); + free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr); + scsi_unregister(atari_scsi_host); + atari_stram_free(atari_dma_buffer); + atari_dma_buffer = 0; + return 0; + } } #endif if (MACH_IS_MEDUSA || MACH_IS_HADES) { @@ -719,9 +730,8 @@ * the rest data bug is fixed, this can be lowered to 1. */ atari_read_overruns = 4; - } -#endif - + } +#endif /*REAL_DMA*/ } else { /* ! IS_A_TT */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/blz1230.c linux/drivers/scsi/blz1230.c --- v2.4.2/linux/drivers/scsi/blz1230.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/blz1230.c Tue Mar 6 19:44:37 2001 @@ -53,7 +53,7 @@ volatile unsigned char cmd_buffer[16]; /* This is where all commands are put - * before they are transfered to the ESP chip + * before they are transferred to the ESP chip * via PIO. */ @@ -88,13 +88,8 @@ esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7)); udelay(5); - if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)){ - esp_deallocate(esp); - scsi_unregister(esp->ehost); - release_mem_region(board+REAL_BLZ1230_ESP_ADDR, - sizeof(struct ESP_regs)); - return 0; /* Bail out if address did not hold data */ - } + if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) + goto err_out; /* Do command transfer with programmed I/O */ esp->do_pio_cmds = 1; @@ -140,8 +135,9 @@ esp->irq = IRQ_AMIGA_PORTS; esp->slot = board+REAL_BLZ1230_ESP_ADDR; - request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, - "Blizzard 1230 SCSI IV", esp_intr); + if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ, + "Blizzard 1230 SCSI IV", esp_intr)) + goto err_out; /* Figure out our scsi ID on the bus */ esp->scsi_id = 7; @@ -156,6 +152,13 @@ return esps_in_use; } } + return 0; + + err_out: + scsi_unregister(esp->ehost); + esp_deallocate(esp); + release_mem_region(board+REAL_BLZ1230_ESP_ADDR, + sizeof(struct ESP_regs)); return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/blz2060.c linux/drivers/scsi/blz2060.c --- v2.4.2/linux/drivers/scsi/blz2060.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/blz2060.c Fri Mar 2 18:38:38 2001 @@ -53,7 +53,7 @@ volatile unsigned char cmd_buffer[16]; /* This is where all commands are put - * before they are transfered to the ESP chip + * before they are transferred to the ESP chip * via PIO. */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cpqfcTScontrol.c linux/drivers/scsi/cpqfcTScontrol.c --- v2.4.2/linux/drivers/scsi/cpqfcTScontrol.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/cpqfcTScontrol.c Fri Mar 2 18:38:38 2001 @@ -1204,7 +1204,7 @@ // open Login exchanges, in case the LinkDown happened in the // middle of logins. It's possible that some ports already // ACCepted login commands which we have not processed before - // another LinkDown occured. Any accepted Login exhanges are + // another LinkDown occurred. Any accepted Login exhanges are // invalidated by LinkDown, even before they are acknowledged. // It's also possible for a port to have a Queued Reply or Request // for login which was interrupted by LinkDown; it may come later, diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c --- v2.4.2/linux/drivers/scsi/cpqfcTSinit.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/cpqfcTSinit.c Fri Mar 2 18:38:38 2001 @@ -1701,7 +1701,7 @@ // removal time (load and unload times) // ALGORITHM notes: // Memory allocation varies by compiler and platform. In the worst case, -// we are only assured BYTE allignment, but in the best case, we can +// we are only assured BYTE alignment, but in the best case, we can // request allocation on any desired boundary. Our strategy: pad the // allocation request size (i.e. waste memory) so that we are assured // of passing desired boundary near beginning of contiguous space, then diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c --- v2.4.2/linux/drivers/scsi/cpqfcTSworker.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/cpqfcTSworker.c Fri Mar 2 18:38:38 2001 @@ -422,7 +422,7 @@ // printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type); // if PortDiscDone is not set, it means the SendLogins routine - // failed to complete -- assume that LDn occured, so login frames + // failed to complete -- assume that LDn occurred, so login frames // are invalid if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn { @@ -4143,7 +4143,7 @@ TachLiteIRE* pIRE; TachLiteTWE* pTWE; TachLiteTRE* pTRE; - ULONG fcp_dl; // total byte length of DATA transfered + ULONG fcp_dl; // total byte length of DATA transferred ULONG fl; // frame length (FC frame size, 128, 256, 512, 1024) ULONG sgPairs; // number of valid scatter/gather pairs int FCP_SCSI_command; diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cyberstorm.c linux/drivers/scsi/cyberstorm.c --- v2.4.2/linux/drivers/scsi/cyberstorm.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/cyberstorm.c Fri Mar 2 18:38:38 2001 @@ -62,7 +62,7 @@ volatile unsigned char cmd_buffer[16]; /* This is where all commands are put - * before they are transfered to the ESP chip + * before they are transferred to the ESP chip * via PIO. */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cyberstormII.c linux/drivers/scsi/cyberstormII.c --- v2.4.2/linux/drivers/scsi/cyberstormII.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/cyberstormII.c Fri Mar 2 18:38:38 2001 @@ -52,7 +52,7 @@ volatile unsigned char cmd_buffer[16]; /* This is where all commands are put - * before they are transfered to the ESP chip + * before they are transferred to the ESP chip * via PIO. */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/dmx3191d.c linux/drivers/scsi/dmx3191d.c --- v2.4.2/linux/drivers/scsi/dmx3191d.c Sat Nov 11 19:01:11 2000 +++ linux/drivers/scsi/dmx3191d.c Fri Mar 2 11:12:11 2001 @@ -68,18 +68,17 @@ while ((pdev = pci_find_device(PCI_VENDOR_ID_DOMEX, PCI_DEVICE_ID_DOMEX_DMX3191D, pdev))) { - unsigned long port = pci_resource_start (pdev, 0); - + unsigned long port; if (pci_enable_device(pdev)) continue; - if (check_region(port, DMX3191D_REGION)) { + port = pci_resource_start (pdev, 0); + + if (!request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME)) { dmx3191d_printk("region 0x%lx-0x%lx already reserved\n", port, port + DMX3191D_REGION); continue; } - - request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME); instance = scsi_register(tmpl, sizeof(struct NCR5380_hostdata)); if(instance == NULL) diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c --- v2.4.2/linux/drivers/scsi/g_NCR5380.c Sat Nov 11 19:01:11 2000 +++ linux/drivers/scsi/g_NCR5380.c Tue Mar 6 19:44:37 2001 @@ -139,7 +139,7 @@ int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ } overrides #ifdef GENERIC_NCR5380_OVERRIDE - [] __initdata = GENERIC_NCR5380_OVERRIDE + [] __initdata = GENERIC_NCR5380_OVERRIDE; #else [1] __initdata = {{0,},}; #endif @@ -911,6 +911,64 @@ MODULE_PARM(ncr_53c400, "i"); MODULE_PARM(ncr_53c400a, "i"); MODULE_PARM(dtc_3181e, "i"); + +#else + +static int __init do_NCR5380_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints)/sizeof(int), ints); + generic_NCR5380_setup(str,ints); + + return 1; +} + +static int __init do_NCR53C400_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints)/sizeof(int), ints); + generic_NCR53C400_setup(str,ints); + + return 1; +} + +static int __init do_NCR53C400A_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints)/sizeof(int), ints); + generic_NCR53C400A_setup(str,ints); + + return 1; +} + +static int __init do_DTC3181E_setup(char *str) +{ + int ints[10]; + + get_options(str, sizeof(ints)/sizeof(int), ints); + generic_DTC3181E_setup(str,ints); + + return 1; +} + +__setup("ncr5380=", do_NCR5380_setup); +__setup("ncr53c400=", do_NCR53C400_setup); +__setup("ncr53c400a=", do_NCR53C400A_setup); +__setup("dtc3181e=", do_DTC3181E_setup); + +static struct isapnp_device_id id_table[] __devinitdata = { + { + ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), + 0 + }, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, id_table); #endif diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/i60uscsi.c linux/drivers/scsi/i60uscsi.c --- v2.4.2/linux/drivers/scsi/i60uscsi.c Thu Sep 2 10:03:26 1999 +++ linux/drivers/scsi/i60uscsi.c Fri Mar 2 18:38:38 2001 @@ -33,7 +33,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/i60uscsi.h linux/drivers/scsi/i60uscsi.h --- v2.4.2/linux/drivers/scsi/i60uscsi.h Fri Nov 12 04:29:47 1999 +++ linux/drivers/scsi/i60uscsi.h Fri Mar 2 18:38:38 2001 @@ -33,7 +33,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/i91uscsi.c linux/drivers/scsi/i91uscsi.c --- v2.4.2/linux/drivers/scsi/i91uscsi.c Mon Aug 23 10:23:23 1999 +++ linux/drivers/scsi/i91uscsi.c Fri Mar 2 18:38:38 2001 @@ -34,7 +34,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/i91uscsi.h linux/drivers/scsi/i91uscsi.h --- v2.4.2/linux/drivers/scsi/i91uscsi.h Fri Dec 18 10:12:25 1998 +++ linux/drivers/scsi/i91uscsi.h Fri Mar 2 18:38:38 2001 @@ -33,7 +33,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c --- v2.4.2/linux/drivers/scsi/ibmmca.c Sat Feb 3 19:51:29 2001 +++ linux/drivers/scsi/ibmmca.c Fri Mar 2 18:38:38 2001 @@ -1594,7 +1594,7 @@ if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */ port = IM_IO_PORT; else { /* if disabled, no IRQs will be generated, as the chip won't - * listen to the incomming commands and will do really nothing, + * listen to the incoming commands and will do really nothing, * except for listening to the pos-register settings. If this * happens, I need to hugely think about it, as one has to * write something to the MCA-Bus pos register in order to diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ibmmca.h linux/drivers/scsi/ibmmca.h --- v2.4.2/linux/drivers/scsi/ibmmca.h Sun Dec 31 09:36:15 2000 +++ linux/drivers/scsi/ibmmca.h Fri Mar 2 18:38:38 2001 @@ -1,7 +1,7 @@ /* * Low Level Driver for the IBM Microchannel SCSI Subsystem * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver - * For use under the GNU public license within the Linux-kernel project. + * For use under the GNU General Public License within the Linux-kernel project. * This include file works only correctly with kernel 2.4.0 or higher!!! */ #ifndef _IBMMCA_H diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c --- v2.4.2/linux/drivers/scsi/imm.c Mon Dec 11 13:43:20 2000 +++ linux/drivers/scsi/imm.c Fri Mar 2 18:38:38 2001 @@ -36,7 +36,7 @@ int mode; /* Transfer mode */ int host; /* Host number (for proc) */ Scsi_Cmnd *cur_cmd; /* Current queued command */ - struct tq_struct imm_tq; /* Polling interupt stuff */ + struct tq_struct imm_tq; /* Polling interrupt stuff */ unsigned long jstart; /* Jiffies at start */ unsigned failed:1; /* Failure flag */ unsigned dp:1; /* Data phase present */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/imm.h linux/drivers/scsi/imm.h --- v2.4.2/linux/drivers/scsi/imm.h Mon Dec 11 13:43:20 2000 +++ linux/drivers/scsi/imm.h Fri Mar 2 18:38:38 2001 @@ -118,7 +118,7 @@ #define IMM_BURST_SIZE 512 /* data burst size */ #define IMM_SELECT_TMO 500 /* 500 how long to wait for target ? */ #define IMM_SPIN_TMO 5000 /* 50000 imm_wait loop limiter */ -#define IMM_DEBUG 0 /* debuging option */ +#define IMM_DEBUG 0 /* debugging option */ #define IN_EPP_MODE(x) (x == IMM_EPP_8 || x == IMM_EPP_16 || x == IMM_EPP_32) /* args to imm_connect */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c --- v2.4.2/linux/drivers/scsi/in2000.c Sat Nov 11 19:01:11 2000 +++ linux/drivers/scsi/in2000.c Fri Mar 2 18:38:38 2001 @@ -681,7 +681,7 @@ else { write1_io(0, IO_FIFO_READ); /* put fifo in read mode */ hostdata->fifo = FI_FIFO_READING; - cmd->SCp.have_data_in = 0; /* nothing transfered yet */ + cmd->SCp.have_data_in = 0; /* nothing transferred yet */ } } diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c --- v2.4.2/linux/drivers/scsi/ini9100u.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/ini9100u.c Fri Mar 2 18:38:38 2001 @@ -34,7 +34,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ini9100u.h linux/drivers/scsi/ini9100u.h --- v2.4.2/linux/drivers/scsi/ini9100u.h Mon Dec 11 13:19:45 2000 +++ linux/drivers/scsi/ini9100u.h Fri Mar 2 18:38:38 2001 @@ -33,7 +33,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c --- v2.4.2/linux/drivers/scsi/inia100.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/inia100.c Fri Mar 2 18:38:38 2001 @@ -33,7 +33,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h --- v2.4.2/linux/drivers/scsi/inia100.h Mon Dec 11 13:19:47 2000 +++ linux/drivers/scsi/inia100.h Fri Mar 2 18:38:38 2001 @@ -33,7 +33,7 @@ * derived from this software without specific prior written permission. * * Where this Software is combined with software released under the terms of - * the GNU Public License ("GPL") and the terms of the GPL would require the + * the GNU General Public License ("GPL") and the terms of the GPL would require the * combined work to also be released under the terms of the GPL, the terms * and conditions of this License will apply in addition to those of the * GPL with the exception of any terms or conditions of this License that diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- v2.4.2/linux/drivers/scsi/ips.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/ips.c Fri Mar 2 18:38:38 2001 @@ -4831,7 +4831,7 @@ } if (j >= 45) - /* error occured */ + /* error occurred */ return (0); PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); @@ -4855,7 +4855,7 @@ } if (j >= 240) - /* error occured */ + /* error occurred */ return (0); ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR); @@ -4920,7 +4920,7 @@ } if (j >= 45) - /* error occured */ + /* error occurred */ return (0); PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); @@ -4944,7 +4944,7 @@ } if (j >= 240) - /* error occured */ + /* error occurred */ return (0); ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); @@ -4961,7 +4961,7 @@ } if (i >= 240) - /* error occured */ + /* error occurred */ return (0); /* setup CCCR */ @@ -5011,7 +5011,7 @@ } if (i >= 45) { - /* error occured */ + /* error occurred */ printk(KERN_WARNING "(%s%d) timeout waiting for post.\n", ips_name, ha->host_num); @@ -5042,7 +5042,7 @@ } if (i >= 240) { - /* error occured */ + /* error occurred */ printk(KERN_WARNING "(%s%d) timeout waiting for config.\n", ips_name, ha->host_num); @@ -5657,7 +5657,7 @@ } else if (intr == IPS_INTR_IORL) { if (ha->waitflag == FALSE) { /* - * controller generated an interupt to + * controller generated an interrupt to * acknowledge completion of the command * and ips_intr() has serviced the interrupt. */ @@ -5681,7 +5681,7 @@ } else if (intr == IPS_INTR_HAL) { if (ha->waitflag == FALSE) { /* - * controller generated an interupt to + * controller generated an interrupt to * acknowledge completion of the command * and ips_intr() has serviced the interrupt. */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/mac_esp.c linux/drivers/scsi/mac_esp.c --- v2.4.2/linux/drivers/scsi/mac_esp.c Wed Feb 21 18:20:32 2001 +++ linux/drivers/scsi/mac_esp.c Fri Mar 2 18:38:38 2001 @@ -67,7 +67,7 @@ volatile unsigned char cmd_buffer[16]; /* This is where all commands are put - * before they are transfered to the ESP chip + * before they are transferred to the ESP chip * via PIO. */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.4.2/linux/drivers/scsi/megaraid.c Sat Feb 3 19:51:29 2001 +++ linux/drivers/scsi/megaraid.c Tue Mar 6 19:44:37 2001 @@ -2,25 +2,24 @@ * * Linux MegaRAID device driver * - * Copyright 1999 American Megatrends Inc. + * Copyright 2001 American Megatrends Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version : 1.07b - * + * Version : v1.14g (Feb 5, 2001) + * * Description: Linux device driver for AMI MegaRAID controller * - * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 490 - * + * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490 + * 493. * History: * * Version 0.90: * Original source contributed by Dell; integrated it into the kernel and * cleaned up some things. Added support for 438/466 controllers. - * * Version 0.91: * Aligned mailbox area on 16-byte boundry. * Added schedule() at the end to properly clean up. @@ -42,10 +41,10 @@ * 8 Oct 98 Alan Cox * * Merged with 2.1.131 source tree. - * 12 Dec 98 K. Baranowski + * 12 Dec 98 K. Baranowski * * Version 0.93: - * Added support for vendor specific ioctl commands (0x80+xxh) + * Added support for vendor specific ioctl commands (M_RD_IOCTL_CMD+xxh) * Changed some fields in MEGARAID struct to better values. * Added signature check for Rp controllers under 2.0 kernels * Changed busy-wait loop to be time-based @@ -74,9 +73,7 @@ * * Version 0.97: * Changed megaraid_command to use wait_queue. - * Fixed bug of undesirably detecting HP onboard controllers which - * are disabled. - * + * * Version 1.00: * Checks to see if an irq ocurred while in isr, and runs through * routine again. @@ -89,13 +86,13 @@ * * Version 1.01: * Fixed bug in mega_cmd_done() for megamgr control commands, - * the host_byte in the result code from the scsi request to - * scsi midlayer is set to DID_BAD_TARGET when adapter's - * returned codes are 0xF0 and 0xF4. + * the host_byte in the result code from the scsi request to + * scsi midlayer is set to DID_BAD_TARGET when adapter's + * returned codes are 0xF0 and 0xF4. * * Version 1.02: * Fixed the tape drive bug by extending the adapter timeout value - * for passthrough command to 60 seconds in mega_build_cmd(). + * for passthrough command to 60 seconds in mega_build_cmd(). * * Version 1.03: * Fixed Madrona support. @@ -104,7 +101,7 @@ * Added driver version printout at driver loadup time * * Version 1.04 - * Added code for 40 ld FW support. + * Added code for 40 ld FW support. * Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with * data area greater than 4 KB, which is the upper bound for data * tranfer through scsi_ioctl interface. @@ -119,15 +116,182 @@ * Fixed the problem of unnecessary aborts in the abort entry point, which * also enables the driver to handle large amount of I/O requests for * long duration of time. - * + * Version 1.06 + * Intel Release * Version 1.07 * Removed the usage of uaccess.h file for kernel versions less than * 2.0.36, as this file is not present in those versions. * - * Version 1.07b - * The MegaRAID 466 cards with 3.00 firmware lockup and seem to very - * occasionally hang. We check such cards and report them. You can - * get firmware upgrades to flash the board to 3.10 for free. + * Version 108 + * Modified mega_ioctl so that 40LD megamanager would run + * Made some changes for 2.3.XX compilation , esp wait structures + * Code merge between 1.05 and 1.06 . + * Bug fixed problem with ioctl interface for concurrency between + * 8ld and 40ld firwmare + * Removed the flawed semaphore logic for handling new config command + * Added support for building own scatter / gather list for big user + * mode buffers + * Added /proc file system support ,so that information is available in + * human readable format + * + * Version 1a08 + * Changes for IA64 kernels. Checked for CONFIG_PROC_FS flag + * + * Version 1b08 + * Include file changes. + * Version 1b08b + * Change PCI ID value for the 471 card, use #defines when searching + * for megaraid cards. + * + * Version 1.10 + * + * I) Changes made to make following ioctl commands work in 0x81 interface + * a)DCMD_DELETE_LOGDRV + * b)DCMD_GET_DISK_CONFIG + * c)DCMD_DELETE_DRIVEGROUP + * d)NC_SUBOP_ENQUIRY3 + * e)DCMD_CHANGE_LDNO + * f)DCMD_CHANGE_LOOPID + * g)DCMD_FC_READ_NVRAM_CONFIG + * h)DCMD_WRITE_CONFIG + * II) Added mega_build_kernel_sg function + * III)Firmware flashing option added + * + * Version 1.10a + * + * I)Dell updates included in the source code. + * Note: This change is not tested due to the unavailability of IA64 kernel + * and it is in the #ifdef DELL_MODIFICATION macro which is not defined + * + * Version 1.10b + * + * I)In M_RD_IOCTL_CMD_NEW command the wrong way of copying the data + * to the user address corrected + * + * Version 1.10c + * + * I) DCMD_GET_DISK_CONFIG opcode updated for the firmware changes. + * + * Version 1.11 + * I) Version number changed from 1.10c to 1.11 + * II) DCMD_WRITE_CONFIG(0x0D) command in the driver changed from + * scatter/gather list mode to direct pointer mode.. + * Fixed bug of undesirably detecting HP onboard controllers which + * are disabled. + * + * Version 1.12 (Sep 21, 2000) + * + * I. Changes have been made for Dynamic DMA mapping in IA64 platform. + * To enable all these changes define M_RD_DYNAMIC_DMA_SUPPORT in megaraid.h + * II. Got rid of windows mode comments + * III. Removed unwanted code segments + * IV. Fixed bug of HP onboard controller information (commented with + * MEGA_HP_FIX) + * + * Version 1a12 + * I. reboot notifer and new ioctl changes ported from 1c09 + * + * Veriosn 1b12 + * I. Changes in new ioctl interface routines ( Nov 06, 2000 ) + * + * Veriosn 1c12 + * I. Changes in new ioctl interface routines ( Nov 07, 2000 ) + * + * Veriosn 1d12 + * I. Compilation error under kernel 2.4.0 for 32-bit machine in mega_ioctl + * + * Veriosn 1e12, 1f12 + * 1. Fixes for pci_map_single, pci_alloc_consistent along with mailbox + * alignment + * + * Version 1.13beta + * Added Support for Full 64bit address space support. If firmware + * supports 64bit, it goes to 64 bit mode even on x86 32bit + * systems. Data Corruption Issues while running on test9 kernel + * on IA64 systems. This issue not seen on test11 on x86 system + * + * Version 1.13c + * 1. Resolved Memory Leak when using M_RD_IOCTL_CMD interface + * 2. Resolved Queuing problem when MailBox Blocks + * 3. Added unregister_reboot_notifier support + * + * Version 1.13d + * Experimental changes in interfacing with the controller in ISR + * + * Version 1.13e + * Fixed Broken 2.2.XX compilation changes + misc changes + * + * Version 1.13f to 1.13i + * misc changes + code clean up + * Cleaned up the ioctl code and added set_mbox_xfer_addr() + * Support for START_DEV (6) + * + * Version 1.13j + * Moved some code to megaraid.h file, replaced some hard coded values + * with respective macros. Chaged some funtions to static + * + * Version 1.13k + * Only some idendation correction to 1.13j + * + * Version 1.13l , 1.13m, 1.13n, 1.13o + * Minor Identation changes + misc changes + * + * Version 1.13q + * Paded the new uioctl_t MIMD structure for maintaining alignment + * and size across 32 / 64 bit platforms + * Changed the way MIMD IOCTL interface used virt_to_bus() to use pci + * memory location + * + * Version 1.13r + * 2.4.xx SCSI Changes. + * + * Version 1.13s + * Stats counter fixes + * Temporary fix for some 64 bit firmwares in 2.4.XX kernels + * + * Version 1.13t + * Support for 64bit version of READ/WRITE/VIEW DISK CONFIG + * + * Version 1.14 + * Did away with MEGADEV_IOCTL flag. It is now standard part of driver + * without need for a special #define flag + * Disabled old scsi ioctl path for kernel versions > 2.3.xx. This is due + * to the nature in which the new scsi code queues a new scsi command to + * controller during SCSI IO Completion + * Driver now checks for sub-system vendor id before taking ownership of + * the controller + * + * Version 1.14a + * Added Host re-ordering + * + * Version 1.14b + * Corrected some issue which caused the older cards not to work + * + * Version 1.14c + * IOCTL changes for not handling the non-64bit firmwares under 2.4.XX + * kernel + * + * Version 1.14d + * Fixed Various MIMD Synchronization Issues + * + * Version 1.14e + * Fixed the error handling during card initialization + * + * Version 1.14f + * Multiple invocations of mimd phase I ioctl stalls the cpu. Replaced + * spinlock with semaphore(mutex) + * + * Version 1.14g + * Fixed running out of scbs issues while running MIMD apps under heavy IO + * + * Version 1.14g-ac - 02/03/01 + * Reformatted to Linux format so I could compare to old one and cross + * check bug fixes + * Re fixed the assorted missing 'static' cases + * Removed some unneeded version checks + * Cleaned up some of the VERSION checks in the code + * Left 2.0 support but removed 2.1.x support. + * Collected much of the compat glue into one spot * * BUGS: * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that @@ -135,31 +299,23 @@ * * Timeout period for upper scsi layer, i.e. SD_TIMEOUT in * /drivers/scsi/sd.c, is too short for this controller. SD_TIMEOUT - * value must be increased to (30 * HZ) otherwise false timeouts + * value must be increased to (30 * HZ) otherwise false timeouts * will occur in the upper layer. * + * Never set skip_id. The existing PCI code the megaraid uses fails + * to properly check the vendor subid in some cases. Setting this then + * makes it steal other i960's and crashes some boxes + * + * Far too many ifdefs for versions. + * *===================================================================*/ -#define CRLFSTR "\n" -#define IOCTL_CMD_NEW 0x81 - -#define MEGARAID_VERSION "v107 (December 22, 1999)" - - +#include #include - -#ifdef MODULE #include - -char kernel_version[] = UTS_RELEASE; - -MODULE_AUTHOR ("American Megatrends Inc."); -MODULE_DESCRIPTION ("AMI MegaRAID driver"); -#endif - -#include #include #include +#include #include #include #include @@ -170,83 +326,117 @@ #include #include #include +#include +#include +#include #include +#include /* for kmalloc() */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ +#include +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /* 0x20300 */ +#include +#else #include +#endif +#endif #include #include -#if LINUX_VERSION_CODE > 0x020024 + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24) /* 0x020024 */ #include #endif +/* + * These header files are required for Shutdown Notification routines + */ +#include +#include +#include + #include "sd.h" #include "scsi.h" #include "hosts.h" #include "megaraid.h" -/*================================================================ - * - * #Defines - * +/* + *================================================================ + * #Defines *================================================================ */ #define MAX_SERBUF 160 #define COM_BASE 0x2f8 - -u32 RDINDOOR (mega_host_config * megaCfg) +static ulong RDINDOOR (mega_host_config * megaCfg) { - return readl (megaCfg->base + 0x20); + return readl (megaCfg->base + 0x20); } -void WRINDOOR (mega_host_config * megaCfg, u32 value) +static void WRINDOOR (mega_host_config * megaCfg, ulong value) { - writel (value, megaCfg->base + 0x20); + writel (value, megaCfg->base + 0x20); } -u32 RDOUTDOOR (mega_host_config * megaCfg) +static ulong RDOUTDOOR (mega_host_config * megaCfg) { - return readl (megaCfg->base + 0x2C); + return readl (megaCfg->base + 0x2C); } -void WROUTDOOR (mega_host_config * megaCfg, u32 value) +static void WROUTDOOR (mega_host_config * megaCfg, ulong value) { - writel (value, megaCfg->base + 0x2C); + writel (value, megaCfg->base + 0x2C); } -/*================================================================ - * - * Function prototypes +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020100 */ + +/* + * Linux 2.4 and higher * - *================================================================ + * No driver private lock + * Use the io_request_lock not cli/sti + * queue task is a simple api without irq forms */ -static int __init megaraid_setup(char *); -static int megaIssueCmd (mega_host_config * megaCfg, - u_char * mboxData, - mega_scb * scb, - int intr); -static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb, - u32 * buffer, u32 * length); - -static int mega_busyWaitMbox(mega_host_config *); -static void mega_runpendq (mega_host_config *); -static void mega_rundoneq (mega_host_config *); -static void mega_cmd_done (mega_host_config *, mega_scb *, int); -static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt); -static inline void mega_freeSgList(mega_host_config *megaCfg); -static void mega_Convert8ldTo40ld( mega_RAIDINQ *inquiry, - mega_Enquiry3 *enquiry3, - megaRaidProductInfo *productInfo ); +#include +#define cpuid smp_processor_id() + +char kernel_version[] = UTS_RELEASE; +MODULE_AUTHOR ("American Megatrends Inc."); +MODULE_DESCRIPTION ("AMI MegaRAID driver"); +#define DRIVER_LOCK_T +#define DRIVER_LOCK_INIT(p) +#define DRIVER_LOCK(p) +#define DRIVER_UNLOCK(p) +#define IO_LOCK_T unsigned long io_flags = 0; +#define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags); +#define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags); -#include +#define queue_task_irq(a,b) queue_task(a,b) +#define queue_task_irq_off(a,b) queue_task(a,b) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */ +/* + * Linux 2.2 and higher + * + * No driver private lock + * Use the io_request_lock not cli/sti + * No pci region api + * queue_task is now a single simple API + */ + +#include #define cpuid smp_processor_id() + +char kernel_version[] = UTS_RELEASE; +MODULE_AUTHOR ("American Megatrends Inc."); +MODULE_DESCRIPTION ("AMI MegaRAID driver"); + #define DRIVER_LOCK_T #define DRIVER_LOCK_INIT(p) #define DRIVER_LOCK(p) @@ -255,95 +445,220 @@ #define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags); #define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags); +#define pci_free_consistent(a,b,c,d) +#define pci_unmap_single(a,b,c,d,e) + +#define init_MUTEX_LOCKED(x) ((x)=MUTEX_LOCKED) +#define init_MUTEX(x) ((x)=MUTEX) + +#define queue_task_irq(a,b) queue_task(a,b) +#define queue_task_irq_off(a,b) queue_task(a,b) + +#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL +#else + +/* + * Linux 2.0 macros. Here we have to provide some of our own + * functionality. We also only work little endian 32bit. + * Again no pci_alloc/free api + * IO_LOCK/IO_LOCK_T were never used in 2.0 so now are empty + */ + +#define cpuid 0 +#define DRIVER_LOCK_T long cpu_flags; +#define DRIVER_LOCK_INIT(p) +#define DRIVER_LOCK(p) \ + save_flags(cpu_flags); \ + cli(); +#define DRIVER_UNLOCK(p) \ + restore_flags(cpu_flags); +#define IO_LOCK_T +#define IO_LOCK(p) +#define IO_UNLOCK(p) +#define le32_to_cpu(x) (x) +#define cpu_to_le32(x) (x) + +#define pci_free_consistent(a,b,c,d) +#define pci_unmap_single(a,b,c,d,e) + +#define init_MUTEX_LOCKED(x) ((x)=MUTEX_LOCKED) +#define init_MUTEX(x) ((x)=MUTEX) + +/* + * 2.0 lacks spinlocks, iounmap/ioremap + */ + +#define ioremap vremap +#define iounmap vfree + + /* simulate spin locks */ +typedef struct { + volatile char lock; +} spinlock_t; + +#define spin_lock_init(x) { (x)->lock = 0;} +#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\ + (x)->lock=1; save_flags(flags);\ + cli();} +#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);} + +#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL + +#endif + + + /* set SERDEBUG to 1 to enable serial debugging */ #define SERDEBUG 0 #if SERDEBUG static void ser_init (void); static void ser_puts (char *str); static void ser_putc (char c); -static int ser_printk (const char *fmt,...); +static int ser_printk (const char *fmt, ...); #endif -/*================================================================ - * +#ifdef CONFIG_PROC_FS +#define COPY_BACK if (offset > megaCfg->procidx) { \ + *eof = TRUE; \ + megaCfg->procidx = 0; \ + megaCfg->procbuf[0] = 0; \ + return 0;} \ + if ((count + offset) > megaCfg->procidx) { \ + count = megaCfg->procidx - offset; \ + *eof = TRUE; } \ + memcpy(page, &megaCfg->procbuf[offset], count); \ + megaCfg->procidx = 0; \ + megaCfg->procbuf[0] = 0; +#endif + +/* + * ================================================================ * Global variables - * *================================================================ */ /* Use "megaraid=skipXX" as LILO option to prohibit driver from scanning XX scsi id on each channel. Used for Madrona motherboard, where SAF_TE processor id cannot be scanned */ + +static char *megaraid; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) /* 0x20100 */ #ifdef MODULE -static char *megaraid = NULL; -MODULE_PARM(megaraid, "s"); +MODULE_PARM (megaraid, "s"); #endif -static int skip_id; - +#endif +static int skip_id = -1; static int numCtlrs = 0; -static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = {0}; +static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = { 0 }; +static struct proc_dir_entry *mega_proc_dir_entry; #if DEBUG static u32 maxCmdTime = 0; #endif static mega_scb *pLastScb = NULL; +static struct notifier_block mega_notifier = { + megaraid_reboot_notify, + NULL, + 0 +}; + +/* For controller re-ordering */ +struct mega_hbas mega_hbas[MAX_CONTROLLERS]; + +/* + * The File Operations structure for the serial/ioctl interface of the driver + */ +/* For controller re-ordering */ + +static struct file_operations megadev_fops = { + ioctl:megadev_ioctl_entry, + open:megadev_open, + release:megadev_close, +}; + +/* + * Array to structures for storing the information about the controllers. This + * information is sent to the user level applications, when they do an ioctl + * for this information. + */ +static struct mcontroller mcontroller[MAX_CONTROLLERS]; + +/* The current driver version */ +static u32 driver_ver = 114; +/* major number used by the device for character interface */ +static int major; + +static struct semaphore mimd_ioctl_sem; +static struct semaphore mimd_entry_mtx; #if SERDEBUG -static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED; +volatile static spinlock_t serial_lock; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x20300 */ +static struct proc_dir_entry proc_scsi_megaraid = { + PROC_SCSI_MEGARAID, 8, "megaraid", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +#endif + +#ifdef CONFIG_PROC_FS +extern struct proc_dir_entry proc_root; #endif + #if SERDEBUG static char strbuf[MAX_SERBUF + 1]; -static void ser_init () +static void ser_init (void) { - unsigned port = COM_BASE; + unsigned port = COM_BASE; - outb (0x80, port + 3); - outb (0, port + 1); - /* 9600 Baud, if 19200: outb(6,port) */ - outb (12, port); - outb (3, port + 3); - outb (0, port + 1); + outb (0x80, port + 3); + outb (0, port + 1); + /* 9600 Baud, if 19200: outb(6,port) */ + outb (12, port); + outb (3, port + 3); + outb (0, port + 1); } static void ser_puts (char *str) { - char *ptr; + char *ptr; - ser_init (); - for (ptr = str; *ptr; ++ptr) - ser_putc (*ptr); + ser_init (); + for (ptr = str; *ptr; ++ptr) + ser_putc (*ptr); } static void ser_putc (char c) { - unsigned port = COM_BASE; + unsigned port = COM_BASE; - while ((inb (port + 5) & 0x20) == 0); - outb (c, port); - if (c == 0x0a) { - while ((inb (port + 5) & 0x20) == 0); - outb (0x0d, port); - } -} - -static int ser_printk (const char *fmt,...) -{ - va_list args; - int i; - long flags; - - spin_lock_irqsave(&serial_lock,flags); - va_start (args, fmt); - i = vsprintf (strbuf, fmt, args); - ser_puts (strbuf); - va_end (args); - spin_unlock_irqrestore(&serial_lock,flags); + while ((inb (port + 5) & 0x20) == 0) ; + outb (c, port); + if (c == 0x0a) { + while ((inb (port + 5) & 0x20) == 0) ; + outb (0x0d, port); + } +} + +static int ser_printk (const char *fmt, ...) +{ + va_list args; + int i; + long flags; + + spin_lock_irqsave (&serial_lock, flags); + va_start (args, fmt); + i = vsprintf (strbuf, fmt, args); + ser_puts (strbuf); + va_end (args); + spin_unlock_irqrestore (&serial_lock, flags); - return i; + return i; } #define TRACE(a) { ser_printk a;} @@ -352,14 +667,16 @@ #define TRACE(A) #endif +#define TRACE1(a) + static void callDone (Scsi_Cmnd * SCpnt) { - if (SCpnt->result) { - TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, - SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, - SCpnt->result)); - } - SCpnt->scsi_done (SCpnt); + if (SCpnt->result) { + TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, + SCpnt->target, SCpnt->lun, SCpnt->result)); + } + SCpnt->scsi_done (SCpnt); } /*------------------------------------------------------------------------- @@ -372,51 +689,92 @@ * Free a SCB structure *======================= */ -static void mega_freeSCB (mega_host_config *megaCfg, mega_scb * pScb) +static void mega_freeSCB (mega_host_config * megaCfg, mega_scb * pScb) { - mega_scb *pScbtmp; + mega_scb *pScbtmp; + + if ((pScb == NULL) || (pScb->idx >= 0xFE)) { + return; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + switch (pScb->dma_type) { + case M_RD_DMA_TYPE_NONE: + break; + case M_RD_PTHRU_WITH_BULK_DATA: + pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata, + pScb->pthru->dataxferlen, + pScb->dma_direction); + break; + case M_RD_PTHRU_WITH_SGLIST: + { + int count; + for (count = 0; count < pScb->sglist_count; count++) { + pci_unmap_single (megaCfg->dev, + pScb->dma_h_sglist[count], + pScb->sgList[count].length, + pScb->dma_direction); + + } + break; + } + case M_RD_BULK_DATA_ONLY: + pci_unmap_single (megaCfg->dev, + pScb->dma_h_bulkdata, + pScb->iDataSize, pScb->dma_direction); + + break; + case M_RD_SGLIST_ONLY: + pci_unmap_sg (megaCfg->dev, + pScb->SCpnt->request_buffer, + pScb->SCpnt->use_sg, pScb->dma_direction); + break; + default: + break; + } +#endif + + /* Unlink from pending queue */ + if (pScb == megaCfg->qPendingH) { + + if (megaCfg->qPendingH == megaCfg->qPendingT) + megaCfg->qPendingH = megaCfg->qPendingT = NULL; + else + megaCfg->qPendingH = megaCfg->qPendingH->next; + + megaCfg->qPcnt--; + + } else { + for (pScbtmp = megaCfg->qPendingH; pScbtmp; + pScbtmp = pScbtmp->next) { + + if (pScbtmp->next == pScb) { + + pScbtmp->next = pScb->next; + + if (pScb == megaCfg->qPendingT) { + megaCfg->qPendingT = pScbtmp; + } + + megaCfg->qPcnt--; + break; + } + } + } + + /* Link back into free list */ + pScb->state = SCB_FREE; + pScb->SCpnt = NULL; + + if (megaCfg->qFreeH == (mega_scb *) NULL) { + megaCfg->qFreeH = megaCfg->qFreeT = pScb; + } else { + megaCfg->qFreeT->next = pScb; + megaCfg->qFreeT = pScb; + } - if ((pScb == NULL) || (pScb->idx >= 0xFE)) { - return ; - } - - /* Unlink from pending queue */ - - if(pScb == megaCfg->qPendingH) { - if(megaCfg->qPendingH == megaCfg->qPendingT ) - megaCfg->qPendingH = megaCfg->qPendingT = NULL; - else { - megaCfg->qPendingH = megaCfg->qPendingH->next; - } - megaCfg->qPcnt--; - } - else { - for(pScbtmp=megaCfg->qPendingH; pScbtmp; pScbtmp=pScbtmp->next) { - if (pScbtmp->next == pScb) { - pScbtmp->next = pScb->next; - if(pScb == megaCfg->qPendingT) { - megaCfg->qPendingT = pScbtmp; - } - megaCfg->qPcnt--; - break; - } - } - } - - /* Link back into free list */ - pScb->state = SCB_FREE; - pScb->SCpnt = NULL; - - if(megaCfg->qFreeH == (mega_scb *) NULL ) { - megaCfg->qFreeH = megaCfg->qFreeT = pScb; - } - else { - megaCfg->qFreeT->next = pScb; - megaCfg->qFreeT = pScb; - } - megaCfg->qFreeT->next = NULL; - megaCfg->qFcnt++; + megaCfg->qFreeT->next = NULL; + megaCfg->qFcnt++; } @@ -424,186 +782,173 @@ * Allocate a SCB structure *=========================== */ -static mega_scb * mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) +static mega_scb *mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) { - mega_scb *pScb; + mega_scb *pScb; + + /* Unlink command from Free List */ + if ((pScb = megaCfg->qFreeH) != NULL) { + megaCfg->qFreeH = pScb->next; + megaCfg->qFcnt--; + + pScb->isrcount = jiffies; + pScb->next = NULL; + pScb->state = SCB_ACTIVE; + pScb->SCpnt = SCpnt; - /* Unlink command from Free List */ - if ((pScb = megaCfg->qFreeH) != NULL) { - megaCfg->qFreeH = pScb->next; - megaCfg->qFcnt--; - - pScb->isrcount = jiffies; - pScb->next = NULL; - pScb->state = SCB_ACTIVE; - pScb->SCpnt = SCpnt; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pScb->dma_type = M_RD_DMA_TYPE_NONE; +#endif - return pScb; - } + return pScb; + } - printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); + printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); - return NULL; + return NULL; } -/*================================================ - * Initialize SCB structures - *================================================ - */ -static int mega_initSCB (mega_host_config * megaCfg) +/* Run through the list of completed requests and finish it */ +static void mega_rundoneq (mega_host_config * megaCfg) { - int idx; + Scsi_Cmnd *SCpnt; - megaCfg->qFreeH = NULL; - megaCfg->qFcnt = 0; -#if DEBUG -if(megaCfg->max_cmds >= MAX_COMMANDS) { -printk("megaraid:ctlr max cmds = %x : MAX_CMDS = %x", megaCfg->max_cmds, MAX_COMMANDS); -} -#endif + while ((SCpnt = megaCfg->qCompletedH) != NULL) { + megaCfg->qCompletedH = (Scsi_Cmnd *) SCpnt->host_scribble; + megaCfg->qCcnt--; + + SCpnt->host_scribble = (unsigned char *) NULL; /* XC : sep 14 */ + /* Callback */ + callDone (SCpnt); + } - for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) { - megaCfg->scbList[idx].idx = idx; - megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST, - GFP_ATOMIC | GFP_DMA); - if (megaCfg->scbList[idx].sgList == NULL) { - printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx); - mega_freeSgList(megaCfg); - return -1; - } - - if (idx < MAX_COMMANDS) { - /* Link to free list */ - mega_freeSCB(megaCfg, &megaCfg->scbList[idx]); - } - } - return 0; -} - -/* Run through the list of completed requests */ -static void mega_rundoneq (mega_host_config *megaCfg) -{ - Scsi_Cmnd *SCpnt; - - while ((SCpnt = megaCfg->qCompletedH) != NULL) { - megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble; - megaCfg->qCcnt--; - - SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14 - /* Callback */ - callDone (SCpnt); - } - megaCfg->qCompletedH = megaCfg->qCompletedT = NULL; + megaCfg->qCompletedH = megaCfg->qCompletedT = NULL; } /* * Runs through the list of pending requests * Assumes that mega_lock spin_lock has been acquired. */ -static void mega_runpendq(mega_host_config *megaCfg) +static int mega_runpendq (mega_host_config * megaCfg) { - mega_scb *pScb; + mega_scb *pScb; + int rc; - /* Issue any pending commands to the card */ - for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) { - if (pScb->state == SCB_ACTIVE) { - if(megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) - return; - } - } + /* Issue any pending commands to the card */ + for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) { + if (pScb->state == SCB_ACTIVE) { + if ((rc = + megaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) == -1) + return rc; + } + } + return 0; } /* Add command to the list of completed requests */ -static void -mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, - int status) + +static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status) { - int islogical; - Scsi_Cmnd *SCpnt; - mega_passthru *pthru; - mega_mailbox *mbox; - - if (pScb == NULL) { - TRACE(("NULL pScb in mega_cmd_done!")); - printk("NULL pScb in mega_cmd_done!"); - } - - SCpnt = pScb->SCpnt; - pthru = &pScb->pthru; - mbox = (mega_mailbox *) &pScb->mboxData; - - if (SCpnt == NULL) { - TRACE(("NULL SCpnt in mega_cmd_done!")); - TRACE(("pScb->idx = ",pScb->idx)); - TRACE(("pScb->state = ",pScb->state)); - TRACE(("pScb->state = ",pScb->state)); - printk("megaraid:Problem...!\n"); - while(1); - } - - islogical = (SCpnt->channel == megaCfg->host->max_channel); - - if (SCpnt->cmnd[0] == INQUIRY && - ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && - !islogical) { - status = 0xF0; - } - -/* clear result; otherwise, success returns corrupt value */ - SCpnt->result = 0; - -if ((SCpnt->cmnd[0] & 0x80) ) {/* i.e. ioctl cmd such as 0x80, 0x81 of megamgr*/ - switch (status) { - case 0xF0: - case 0xF4: - SCpnt->result=(DID_BAD_TARGET<<16)|status; - break; - default: - SCpnt->result|=status; - }/*end of switch*/ -} -else{ - /* Convert MegaRAID status to Linux error code */ - switch (status) { - case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD*/ - SCpnt->result |= (DID_OK << 16); - break; - case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */ - /*set sense_buffer and result fields*/ - if( mbox->cmd==MEGA_MBOXCMD_PASSTHRU ){ - memcpy( SCpnt->sense_buffer , pthru->reqsensearea, 14); - SCpnt->result = (DRIVER_SENSE<<24)|(DID_ERROR << 16)|status; - } - else{ - SCpnt->sense_buffer[0]=0x70; - SCpnt->sense_buffer[2]=ABORTED_COMMAND; - SCpnt->result |= (CHECK_CONDITION << 1); - } - break; - case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */ - SCpnt->result |= (DID_BUS_BUSY << 16)|status; - break; - default: - SCpnt->result |= (DID_BAD_TARGET << 16)|status; - break; - } - } - if ( SCpnt->cmnd[0]!=IOCTL_CMD_NEW ) - /* not IOCTL_CMD_NEW SCB, freeSCB()*/ - /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue() - * after copy data back to user space*/ - mega_freeSCB(megaCfg, pScb); - - /* Add Scsi_Command to end of completed queue */ - if( megaCfg->qCompletedH == NULL ) { - megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; - } - else { - megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt; - megaCfg->qCompletedT = SCpnt; - } - megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; - megaCfg->qCcnt++; + int islogical; + Scsi_Cmnd *SCpnt; + mega_passthru *pthru; + mega_mailbox *mbox; + + if (pScb == NULL) { + TRACE (("NULL pScb in mega_cmd_done!")); + printk(KERN_CRIT "NULL pScb in mega_cmd_done!"); + } + + SCpnt = pScb->SCpnt; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pthru = pScb->pthru; +#else + pthru = &pScb->pthru; +#endif + + mbox = (mega_mailbox *) & pScb->mboxData; + + if (SCpnt == NULL) { + TRACE (("NULL SCpnt in mega_cmd_done!")); + TRACE (("pScb->idx = ", pScb->idx)); + TRACE (("pScb->state = ", pScb->state)); + TRACE (("pScb->state = ", pScb->state)); + panic(KERN_ERR "megaraid:Problem...!\n"); + } + + islogical = (SCpnt->channel == megaCfg->host->max_channel); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* Special Case to handle PassThrough->XferAddrress > 4GB */ + switch (SCpnt->cmnd[0]) { + case INQUIRY: + case READ_CAPACITY: + memcpy (SCpnt->request_buffer, + pScb->bounce_buffer, SCpnt->request_bufflen); + break; + } +#endif + + mega_freeSCB (megaCfg, pScb); + + if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) { + status = 0xF0; + } + + /* clear result; otherwise, success returns corrupt value */ + SCpnt->result = 0; + + if ((SCpnt->cmnd[0] & M_RD_IOCTL_CMD)) { /* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */ + switch (status) { + case 2: + case 0xF0: + case 0xF4: + SCpnt->result = (DID_BAD_TARGET << 16) | status; + break; + default: + SCpnt->result |= status; + } /*end of switch */ + } else { + /* Convert MegaRAID status to Linux error code */ + switch (status) { + case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD */ + SCpnt->result |= (DID_OK << 16); + break; + + case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */ + + /*set sense_buffer and result fields */ + if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) { + memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14); + SCpnt->result = (DRIVER_SENSE << 24) | (DID_ERROR << 16) | status; + } else { + SCpnt->sense_buffer[0] = 0x70; + SCpnt->sense_buffer[2] = ABORTED_COMMAND; + SCpnt->result |= (CHECK_CONDITION << 1); + } + break; + + case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */ + SCpnt->result |= (DID_BUS_BUSY << 16) | status; + break; + + default: + SCpnt->result |= (DID_BAD_TARGET << 16) | status; + break; + } + } + + /* Add Scsi_Command to end of completed queue */ + if (megaCfg->qCompletedH == NULL) { + megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; + } else { + megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt; + megaCfg->qCompletedT = SCpnt; + } + + megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; + megaCfg->qCcnt++; } /*------------------------------------------------------------------- @@ -614,491 +959,859 @@ * If NULL is returned, the scsi_done function MUST have been called * *-------------------------------------------------------------------*/ -static mega_scb * mega_build_cmd (mega_host_config * megaCfg, - Scsi_Cmnd * SCpnt) -{ - mega_scb *pScb; - mega_mailbox *mbox; - mega_passthru *pthru; - long seg; - char islogical; - char lun = SCpnt->lun; - if ((SCpnt->cmnd[0] == 0x80) || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) ) /* ioctl */ - return mega_ioctl (megaCfg, SCpnt); - - islogical = (SCpnt->channel == megaCfg->host->max_channel); +static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) +{ + mega_scb *pScb; + mega_mailbox *mbox; + mega_passthru *pthru; + long seg; + char islogical; + char lun = SCpnt->lun; + + if ((SCpnt->cmnd[0] == MEGADEVIOC)) + return megadev_doioctl (megaCfg, SCpnt); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + if ((SCpnt->cmnd[0] == M_RD_IOCTL_CMD) + || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW)) + return mega_ioctl (megaCfg, SCpnt); /* Handle IOCTL command */ +#endif - if (!islogical && lun != 0) { - SCpnt->result = (DID_BAD_TARGET << 16); - callDone (SCpnt); - return NULL; - } + islogical = (SCpnt->channel == megaCfg->host->max_channel); - if (!islogical && SCpnt->target == skip_id) { - SCpnt->result = (DID_BAD_TARGET << 16); - callDone (SCpnt); - return NULL; - } + if (!islogical && lun != 0) { + SCpnt->result = (DID_BAD_TARGET << 16); + callDone (SCpnt); + return NULL; + } - if ( islogical ) { - lun = (SCpnt->target * 8) + lun; - if ( lun > FC_MAX_LOGICAL_DRIVES ){ - SCpnt->result = (DID_BAD_TARGET << 16); - callDone (SCpnt); - return NULL; - } - } - /*----------------------------------------------------- - * - * Logical drive commands - * - *-----------------------------------------------------*/ - if (islogical) { - switch (SCpnt->cmnd[0]) { - case TEST_UNIT_READY: - memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen); - SCpnt->result = (DID_OK << 16); - callDone (SCpnt); - return NULL; - - case MODE_SENSE: - memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]); - SCpnt->result = (DID_OK << 16); - callDone (SCpnt); - return NULL; - - case READ_CAPACITY: - case INQUIRY: - /* Allocate a SCB and initialize passthru */ - if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - pthru = &pScb->pthru; - mbox = (mega_mailbox *) & pScb->mboxData; - - memset (mbox, 0, sizeof (pScb->mboxData)); - memset (pthru, 0, sizeof (mega_passthru)); - pthru->timeout = 0; - pthru->ars = 1; - pthru->reqsenselen = 14; - pthru->islogical = 1; - pthru->logdrv = lun; - pthru->cdblen = SCpnt->cmd_len; - pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer); - pthru->dataxferlen = SCpnt->request_bufflen; - memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - /* Initialize mailbox area */ - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; - mbox->xferaddr = virt_to_bus (pthru); - - return pScb; - - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - /* Allocate a SCB and initialize mailbox */ - if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - mbox = (mega_mailbox *) & pScb->mboxData; + if (!islogical && SCpnt->target == skip_id) { + SCpnt->result = (DID_BAD_TARGET << 16); + callDone (SCpnt); + return NULL; + } - memset (mbox, 0, sizeof (pScb->mboxData)); - mbox->logdrv = lun; - mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ? - MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE; - - /* 6-byte */ - if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) { - mbox->numsectors = - (u32) SCpnt->cmnd[4]; - mbox->lba = - ((u32) SCpnt->cmnd[1] << 16) | - ((u32) SCpnt->cmnd[2] << 8) | - (u32) SCpnt->cmnd[3]; - mbox->lba &= 0x1FFFFF; - } - - /* 10-byte */ - if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) { - mbox->numsectors = - (u32) SCpnt->cmnd[8] | - ((u32) SCpnt->cmnd[7] << 8); - mbox->lba = - ((u32) SCpnt->cmnd[2] << 24) | - ((u32) SCpnt->cmnd[3] << 16) | - ((u32) SCpnt->cmnd[4] << 8) | - (u32) SCpnt->cmnd[5]; - } - - /* Calculate Scatter-Gather info */ - mbox->numsgelements = mega_build_sglist (megaCfg, pScb, - (u32 *) & mbox->xferaddr, - (u32 *) & seg); - - return pScb; - - default: - SCpnt->result = (DID_BAD_TARGET << 16); - callDone (SCpnt); - return NULL; - } - } - /*----------------------------------------------------- - * - * Passthru drive commands - * - *-----------------------------------------------------*/ - else { - /* Allocate a SCB and initialize passthru */ - if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - pthru = &pScb->pthru; - mbox = (mega_mailbox *) pScb->mboxData; - - memset (mbox, 0, sizeof (pScb->mboxData)); - memset (pthru, 0, sizeof (mega_passthru)); - pthru->timeout = 2; /*set adapter timeout value to 10 min. for tape drive*/ - /* 0=6sec/1=60sec/2=10min/3=3hrs */ - pthru->ars = 1; - pthru->reqsenselen = 14; - pthru->islogical = 0; - pthru->channel = (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel; - pthru->target = (megaCfg->flag & BOARD_40LD) ? /*BOARD_40LD*/ - (SCpnt->channel<<4)|SCpnt->target : SCpnt->target; - pthru->cdblen = SCpnt->cmd_len; - memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - pthru->numsgelements = mega_build_sglist (megaCfg, pScb, - (u32 *) & pthru->dataxferaddr, - (u32 *) & pthru->dataxferlen); - - /* Initialize mailbox */ - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; - mbox->xferaddr = virt_to_bus (pthru); - - return pScb; - } - return NULL; -} + if (islogical) { + lun = (SCpnt->target * 8) + lun; + if (lun > FC_MAX_LOGICAL_DRIVES) { + SCpnt->result = (DID_BAD_TARGET << 16); + callDone (SCpnt); + return NULL; + } + } + /*----------------------------------------------------- + * + * Logical drive commands + * + *-----------------------------------------------------*/ + if (islogical) { + switch (SCpnt->cmnd[0]) { + case TEST_UNIT_READY: + memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen); + SCpnt->result = (DID_OK << 16); + callDone (SCpnt); + return NULL; + + case MODE_SENSE: + memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]); + SCpnt->result = (DID_OK << 16); + callDone (SCpnt); + return NULL; + + case READ_CAPACITY: + case INQUIRY: + /* Allocate a SCB and initialize passthru */ + if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pthru = pScb->pthru; +#else + pthru = &pScb->pthru; +#endif -/*-------------------------------------------------------------------- - * build RAID commands for controller, passed down through ioctl() - *--------------------------------------------------------------------*/ -static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) -{ - mega_scb *pScb; - mega_ioctl_mbox *mbox; - mega_mailbox *mailbox; - mega_passthru *pthru; - u8 *mboxdata; - long seg; - unsigned char *data = (unsigned char *)SCpnt->request_buffer; - int i; - - if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - - mboxdata = (u8 *) & pScb->mboxData; - mbox = (mega_ioctl_mbox *) & pScb->mboxData; - mailbox = (mega_mailbox *) & pScb->mboxData; - memset (mailbox, 0, sizeof (pScb->mboxData)); - - if (data[0] == 0x03) { /* passthrough command */ - unsigned char cdblen = data[2]; - pthru = &pScb->pthru; - memset (pthru, 0, sizeof (mega_passthru)); - pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0; - pthru->timeout = data[cdblen+3] & 0x07; - pthru->reqsenselen = 14; - pthru->ars = (data[cdblen+3] & 0x08) ? 1:0; - pthru->logdrv = data[cdblen+4]; - pthru->channel = data[cdblen+5]; - pthru->target = data[cdblen+6]; - pthru->cdblen = cdblen; - memcpy (pthru->cdb, &data[3], cdblen); - - mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; - mailbox->xferaddr = virt_to_bus (pthru); - - pthru->numsgelements = mega_build_sglist (megaCfg, pScb, - (u32 *) & pthru->dataxferaddr, - (u32 *) & pthru->dataxferlen); - - for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) { - data[i] = data[i+cdblen+7]; - } - - return pScb; - } - /* else normal (nonpassthru) command */ + mbox = (mega_mailbox *) & pScb->mboxData; + memset (mbox, 0, sizeof (pScb->mboxData)); + memset (pthru, 0, sizeof (mega_passthru)); + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; + pthru->islogical = 1; + pthru->logdrv = lun; + pthru->cdblen = SCpnt->cmd_len; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /*Not sure about the direction */ + pScb->dma_direction = PCI_DMA_BIDIRECTIONAL; + pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA; + +#if 0 +/* Normal Code w/o the need for bounce buffer */ + pScb->dma_h_bulkdata + = pci_map_single (megaCfg->dev, + SCpnt->request_buffer, + SCpnt->request_bufflen, + pScb->dma_direction); -#if LINUX_VERSION_CODE > 0x020024 -/* - * usage of the function copy from user is used in case of data more than - * 4KB. This is used only with adapters which supports more than 8 logical - * drives. This feature is disabled on kernels earlier or same as 2.0.36 - * as the uaccess.h file is not available with those kernels. - */ + pthru->dataxferaddr = pScb->dma_h_bulkdata; +#else +/* Special Code to use bounce buffer for READ_CAPA/INQ */ + pthru->dataxferaddr = pScb->dma_bounce_buffer; + pScb->dma_type = M_RD_DMA_TYPE_NONE; +#endif - if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) { - /* use external data area for large xfers */ - /* If cmnd[0] is set to IOCTL_CMD_NEW then * - * cmnd[4..7] = external user buffer * - * cmnd[8..11] = length of buffer * - * */ - char *kern_area; - char *user_area = *((char **)&SCpnt->cmnd[4]); - u32 xfer_size = *((u32 *)&SCpnt->cmnd[8]); - if (verify_area(VERIFY_READ, user_area, xfer_size)) { - printk("megaraid: Got bad user address.\n"); - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA); - if (kern_area == NULL) { - printk("megaraid: Couldn't allocate kernel mem.\n"); - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - copy_from_user(kern_area,user_area,xfer_size); - pScb->kern_area = kern_area; - } -#endif - - mbox->cmd = data[0]; - mbox->channel = data[1]; - mbox->param = data[2]; - mbox->pad[0] = data[3]; - mbox->logdrv = data[4]; - - if(SCpnt->cmnd[0] == IOCTL_CMD_NEW) { - if(data[0]==DCMD_FC_CMD){ /*i.e. 0xA1, then override some mbox data */ - *(mboxdata+0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD*/ - *(mboxdata+2) = data[2]; /*sub command*/ - *(mboxdata+3) = 0; /*number of elements in SG list*/ - mbox->xferaddr /*i.e. mboxdata byte 0x8 to 0xb*/ - = virt_to_bus(pScb->kern_area); - } - else{ - mbox->xferaddr = virt_to_bus(pScb->kern_area); - mbox->numsgelements = 0; - } - } - else { - - mbox->numsgelements = mega_build_sglist (megaCfg, pScb, - (u32 *) & mbox->xferaddr, - (u32 *) & seg); - - for (i=0;i<(SCpnt->request_bufflen-6);i++) { - data[i] = data[i+6]; - } - } +#else + pthru->dataxferaddr = + virt_to_bus (SCpnt->request_buffer); +#endif - return (pScb); -} + pthru->dataxferlen = SCpnt->request_bufflen; + memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); -#if DEBUG -static void showMbox(mega_scb *pScb) -{ - mega_mailbox *mbox; + /* Initialize mailbox area */ + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; - if (pScb == NULL) return; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + mbox->xferaddr = pScb->dma_passthruhandle64; + TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n")); +#else + mbox->xferaddr = virt_to_bus (pthru); +#endif + return pScb; - mbox = (mega_mailbox *)pScb->mboxData; - printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", - pScb->SCpnt->pid, - mbox->cmd, mbox->cmdid, mbox->numsectors, - mbox->lba, mbox->xferaddr, mbox->logdrv, - mbox->numsgelements); -} + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + /* Allocate a SCB and initialize mailbox */ + if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + mbox = (mega_mailbox *) & pScb->mboxData; + + memset (mbox, 0, sizeof (pScb->mboxData)); + mbox->logdrv = lun; + + if (megaCfg->flag & BOARD_64BIT) { + mbox->cmd = (*SCpnt->cmnd == READ_6 + || *SCpnt->cmnd == + READ_10) ? MEGA_MBOXCMD_LREAD64 : + MEGA_MBOXCMD_LWRITE64; + } else { + mbox->cmd = (*SCpnt->cmnd == READ_6 + || *SCpnt->cmnd == + READ_10) ? MEGA_MBOXCMD_LREAD : + MEGA_MBOXCMD_LWRITE; + } + + /* 6-byte */ + if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) { + mbox->numsectors = (u32) SCpnt->cmnd[4]; + mbox->lba = + ((u32) SCpnt->cmnd[1] << 16) | + ((u32) SCpnt->cmnd[2] << 8) | + (u32) SCpnt->cmnd[3]; + mbox->lba &= 0x1FFFFF; + + if (*SCpnt->cmnd == READ_6) { + megaCfg->nReads[(int) lun]++; + megaCfg->nReadBlocks[(int) lun] += + mbox->numsectors; + } else { + megaCfg->nWrites[(int) lun]++; + megaCfg->nWriteBlocks[(int) lun] += + mbox->numsectors; + } + } + + /* 10-byte */ + if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) { + mbox->numsectors = + (u32) SCpnt->cmnd[8] | + ((u32) SCpnt->cmnd[7] << 8); + mbox->lba = + ((u32) SCpnt->cmnd[2] << 24) | + ((u32) SCpnt->cmnd[3] << 16) | + ((u32) SCpnt->cmnd[4] << 8) | + (u32) SCpnt->cmnd[5]; + + if (*SCpnt->cmnd == READ_10) { + megaCfg->nReads[(int) lun]++; + megaCfg->nReadBlocks[(int) lun] += + mbox->numsectors; + } else { + megaCfg->nWrites[(int) lun]++; + megaCfg->nWriteBlocks[(int) lun] += + mbox->numsectors; + } + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) { + pScb->dma_direction = PCI_DMA_FROMDEVICE; + } else { /*WRITE_6 or WRITE_10 */ + pScb->dma_direction = PCI_DMA_TODEVICE; + } #endif -#if DEBUG -static unsigned int cum_time = 0; -static unsigned int cum_time_cnt = 0; + /* Calculate Scatter-Gather info */ + mbox->numsgelements = mega_build_sglist (megaCfg, pScb, + (u32 *) & + mbox->xferaddr, + (u32 *) & seg); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pScb->iDataSize = seg; + + if (mbox->numsgelements) { + pScb->dma_type = M_RD_SGLIST_ONLY; + TRACE1 (("M_RD_SGLIST_ONLY Enabled \n")); + } else { + pScb->dma_type = M_RD_BULK_DATA_ONLY; + TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n")); + } #endif -/*-------------------------------------------------------------------- - * Interrupt service routine - *--------------------------------------------------------------------*/ -static void megaraid_isr (int irq, void *devp, struct pt_regs *regs) -{ -#if LINUX_VERSION_CODE >= 0x20100 - IO_LOCK_T + return pScb; + default: + SCpnt->result = (DID_BAD_TARGET << 16); + callDone (SCpnt); + return NULL; + } + } + /*----------------------------------------------------- + * + * Passthru drive commands + * + *-----------------------------------------------------*/ + else { + /* Allocate a SCB and initialize passthru */ + if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pthru = pScb->pthru; +#else + pthru = &pScb->pthru; #endif - mega_host_config *megaCfg; - u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE]; - u32 dword=0; - mega_mailbox *mbox; - mega_scb *pScb; - u_char qCnt, qStatus; - u_char completed[MAX_FIRMWARE_STATUS]; - Scsi_Cmnd *SCpnt; - - megaCfg = (mega_host_config *) devp; - mbox = (mega_mailbox *)tmpBox; - - if (megaCfg->host->irq == irq) { - if (megaCfg->flag & IN_ISR) { - printk(KERN_ERR "ISR called reentrantly!!\n"); - } - - megaCfg->flag |= IN_ISR; - - if (mega_busyWaitMbox(megaCfg)) { - printk(KERN_WARNING "Error: mailbox busy in isr!\n"); - } - - /* Check if a valid interrupt is pending */ - if (megaCfg->flag & BOARD_QUARTZ) { - dword = RDOUTDOOR (megaCfg); - if (dword != 0x10001234) { - /* Spurious interrupt */ - megaCfg->flag &= ~IN_ISR; - return; - } - } - else { - byte = READ_PORT (megaCfg->host->io_port, INTR_PORT); - if ((byte & VALID_INTR_BYTE) == 0) { - /* Spurious interrupt */ - megaCfg->flag &= ~IN_ISR; - return; - } - WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); - } - - for(idx=0;idxmbox->numstatus) == 0xFF) - ; - - qStatus = 0xff; - while ((qStatus = megaCfg->mbox->status) == 0xFF) - ; - - /* Get list of completed requests */ - for (idx = 0; idxmbox->completed[idx]) == 0xFF) { - printk("p"); - } - completed[idx] = sIdx; - sIdx = 0xFF; - } - - if (megaCfg->flag & BOARD_QUARTZ) { - WROUTDOOR (megaCfg, dword); - /* Acknowledge interrupt */ - WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); - while (RDINDOOR (megaCfg) & 0x02); - } - else { - CLEAR_INTR (megaCfg->host->io_port); - } + mbox = (mega_mailbox *) pScb->mboxData; -#if DEBUG - if(qCnt >= MAX_FIRMWARE_STATUS) { - printk("megaraid_isr: cmplt=%d ", qCnt); - } + memset (mbox, 0, sizeof (pScb->mboxData)); + memset (pthru, 0, sizeof (mega_passthru)); + + /* set adapter timeout value to 10 min. for tape drive */ + /* 0=6sec/1=60sec/2=10min/3=3hrs */ + pthru->timeout = 2; + pthru->ars = 1; + pthru->reqsenselen = 14; + pthru->islogical = 0; + pthru->channel = + (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel; + pthru->target = (megaCfg->flag & BOARD_40LD) ? /*BOARD_40LD */ + (SCpnt->channel << 4) | SCpnt->target : SCpnt->target; + pthru->cdblen = SCpnt->cmd_len; + + memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* Not sure about the direction */ + pScb->dma_direction = PCI_DMA_BIDIRECTIONAL; + + /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */ + switch (SCpnt->cmnd[0]) { + case INQUIRY: + case READ_CAPACITY: + pthru->numsgelements = 0; + pthru->dataxferaddr = pScb->dma_bounce_buffer; + pthru->dataxferlen = SCpnt->request_bufflen; + break; + default: + pthru->numsgelements = mega_build_sglist (megaCfg, pScb, + (u32 *) & + pthru-> + dataxferaddr, + (u32 *) & + pthru-> + dataxferlen); + break; + } +#else + pthru->numsgelements = mega_build_sglist (megaCfg, pScb, + (u32 *) & pthru-> + dataxferaddr, + (u32 *) & pthru-> + dataxferlen); #endif - for (idx = 0; idx < qCnt; idx++) { - sIdx = completed[idx]; - if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) { - pScb = &megaCfg->scbList[sIdx - 1]; + /* Initialize mailbox */ + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; - /* ASSERT(pScb->state == SCB_ISSUED); */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + mbox->xferaddr = pScb->dma_passthruhandle64; -#if DEBUG - if (((jiffies) - pScb->isrcount) > maxCmdTime) { - maxCmdTime = (jiffies) - pScb->isrcount; - printk("megaraid_isr : cmd time = %u\n", maxCmdTime); - } + if (pthru->numsgelements) { + pScb->dma_type = M_RD_PTHRU_WITH_SGLIST; + TRACE1 (("M_RD_PTHRU_WITH_SGLIST Enabled \n")); + } else { + pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA + TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n")); + } +#else + mbox->xferaddr = virt_to_bus (pthru); #endif -/* - * Assuming that the scsi command, for which an abort request was received - * earlier has completed. - */ - if (pScb->state == SCB_ABORTED) { - SCpnt = pScb->SCpnt; + + return pScb; + } + return NULL; +} + +/* Handle Driver Level IOCTLs + * Return value of 0 indicates this function could not handle , so continue + * processing +*/ + +static int mega_driver_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) +{ + unsigned char *data = (unsigned char *) SCpnt->request_buffer; + mega_driver_info driver_info; + + /* If this is not our command dont do anything */ + if (SCpnt->cmnd[0] != M_RD_DRIVER_IOCTL_INTERFACE) + return 0; + + switch (SCpnt->cmnd[1]) { + case GET_DRIVER_INFO: + if (SCpnt->request_bufflen < sizeof (driver_info)) { + SCpnt->result = DID_BAD_TARGET << 16; + callDone (SCpnt); + return 1; + } + + driver_info.size = sizeof (driver_info) - sizeof (int); + driver_info.version = MEGARAID_IOCTL_VERSION; + memcpy (data, &driver_info, sizeof (driver_info)); + break; + default: + SCpnt->result = DID_BAD_TARGET << 16; + } + + callDone (SCpnt); + return 1; +} + +static void inline set_mbox_xfer_addr (mega_host_config * megaCfg, mega_scb * pScb, + mega_ioctl_mbox * mbox, u32 direction) +{ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + switch (direction) { + case TO_DEVICE: + pScb->dma_direction = PCI_DMA_TODEVICE; + break; + case FROM_DEVICE: + pScb->dma_direction = PCI_DMA_FROMDEVICE; + break; + case FROMTO_DEVICE: + pScb->dma_direction = PCI_DMA_BIDIRECTIONAL; + break; + } + + pScb->dma_h_bulkdata + = pci_map_single (megaCfg->dev, + pScb->buff_ptr, + pScb->iDataSize, pScb->dma_direction); + mbox->xferaddr = pScb->dma_h_bulkdata; + pScb->dma_type = M_RD_BULK_DATA_ONLY; + TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n")); +#else + mbox->xferaddr = virt_to_bus (pScb->buff_ptr); +#endif +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + +/*-------------------------------------------------------------------- + * build RAID commands for controller, passed down through ioctl() + *--------------------------------------------------------------------*/ +static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) +{ + mega_scb *pScb; + mega_ioctl_mbox *mbox; + mega_mailbox *mailbox; + mega_passthru *pthru; + u8 *mboxdata; + long seg, i = 0; + unsigned char *data = (unsigned char *) SCpnt->request_buffer; + + if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; } - if (pScb->state == SCB_RESET) { - SCpnt = pScb->SCpnt; - mega_freeSCB (megaCfg, pScb); - SCpnt->result = (DID_RESET << 16) ; - if( megaCfg->qCompletedH == NULL ) { - megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; - } - else { - megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt; - megaCfg->qCompletedT = SCpnt; - } - megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; - megaCfg->qCcnt++; - continue; - } - - if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW) - { /* external user buffer */ - up(&pScb->sem); - } - /* Mark command as completed */ - mega_cmd_done(megaCfg, pScb, qStatus); - - } - else { - printk(KERN_ERR "megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx); - } - } - - mega_rundoneq(megaCfg); - - megaCfg->flag &= ~IN_ISR; - - /* Loop through any pending requests */ - mega_runpendq(megaCfg); -#if LINUX_VERSION_CODE >= 0x20100 - IO_UNLOCK; + pthru = &pScb->pthru; + + mboxdata = (u8 *) & pScb->mboxData; + mbox = (mega_ioctl_mbox *) & pScb->mboxData; + mailbox = (mega_mailbox *) & pScb->mboxData; + memset (mailbox, 0, sizeof (pScb->mboxData)); + + if (data[0] == 0x03) { /* passthrough command */ + unsigned char cdblen = data[2]; + memset (pthru, 0, sizeof (mega_passthru)); + pthru->islogical = (data[cdblen + 3] & 0x80) ? 1 : 0; + pthru->timeout = data[cdblen + 3] & 0x07; + pthru->reqsenselen = 14; + pthru->ars = (data[cdblen + 3] & 0x08) ? 1 : 0; + pthru->logdrv = data[cdblen + 4]; + pthru->channel = data[cdblen + 5]; + pthru->target = data[cdblen + 6]; + pthru->cdblen = cdblen; + memcpy (pthru->cdb, &data[3], cdblen); + + mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; + + + pthru->numsgelements = mega_build_sglist (megaCfg, pScb, + (u32 *) & pthru-> + dataxferaddr, + (u32 *) & pthru-> + dataxferlen); + + mailbox->xferaddr = virt_to_bus (pthru); + + for (i = 0; i < (SCpnt->request_bufflen - cdblen - 7); i++) { + data[i] = data[i + cdblen + 7]; + } + return pScb; + } + /* else normal (nonpassthru) command */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24) /*0x020024 */ + /* + *usage of the function copy from user is used in case of data more than + *4KB.This is used only with adapters which supports more than 8 logical + * drives.This feature is disabled on kernels earlier or same as 2.0.36 + * as the uaccess.h file is not available with those kernels. + */ + + if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { + /* use external data area for large xfers */ + /* If cmnd[0] is set to M_RD_IOCTL_CMD_NEW then * + * cmnd[4..7] = external user buffer * + * cmnd[8..11] = length of buffer * + * */ + char *user_area = *((char **) &SCpnt->cmnd[4]); + u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]); + switch (data[0]) { + case FW_FIRE_WRITE: + case FW_FIRE_FLASH: + if ((ulong) user_area & (PAGE_SIZE - 1)) { + printk + ("megaraid:user address not aligned on 4K boundary.Error.\n"); + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + break; + default: + break; + } + + if (!(pScb->buff_ptr = kmalloc (xfer_size, GFP_KERNEL))) { + printk + ("megaraid: Insufficient mem for M_RD_IOCTL_CMD_NEW.\n"); + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + + copy_from_user (pScb->buff_ptr, user_area, xfer_size); + pScb->iDataSize = xfer_size; + + switch (data[0]) { + case DCMD_FC_CMD: + switch (data[1]) { + case DCMD_FC_READ_NVRAM_CONFIG: + case DCMD_GET_DISK_CONFIG: + { + if ((ulong) pScb-> + buff_ptr & (PAGE_SIZE - 1)) { + printk + ("megaraid:user address not sufficient Error.\n"); + SCpnt->result = + (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + + /*building SG list */ + mega_build_kernel_sg (pScb->buff_ptr, + xfer_size, + pScb, mbox); + break; + } + default: + break; + } /*switch (data[1]) */ + break; + } + + } +#endif + + mbox->cmd = data[0]; + mbox->channel = data[1]; + mbox->param = data[2]; + mbox->pad[0] = data[3]; + mbox->logdrv = data[4]; + + if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { + switch (data[0]) { + case FW_FIRE_WRITE: + mbox->cmd = FW_FIRE_WRITE; + mbox->channel = data[1]; /* Current Block Number */ + set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE); + mbox->numsgelements = 0; + break; + case FW_FIRE_FLASH: + mbox->cmd = FW_FIRE_FLASH; + mbox->channel = data[1] | 0x80; /* Origin */ + set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE); + mbox->numsgelements = 0; + break; + case DCMD_FC_CMD: + *(mboxdata + 0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD */ + *(mboxdata + 2) = data[1]; /*sub command */ + switch (data[1]) { + case DCMD_FC_READ_NVRAM_CONFIG: + case DCMD_FC_READ_NVRAM_CONFIG_64: + /* number of elements in SG list */ + *(mboxdata + 3) = mbox->numsgelements; + if (megaCfg->flag & BOARD_64BIT) + *(mboxdata + 2) = + DCMD_FC_READ_NVRAM_CONFIG_64; + break; + case DCMD_WRITE_CONFIG: + case DCMD_WRITE_CONFIG_64: + if (megaCfg->flag & BOARD_64BIT) + *(mboxdata + 2) = DCMD_WRITE_CONFIG_64; + set_mbox_xfer_addr (megaCfg, pScb, mbox, + TO_DEVICE); + mbox->numsgelements = 0; + break; + case DCMD_GET_DISK_CONFIG: + case DCMD_GET_DISK_CONFIG_64: + if (megaCfg->flag & BOARD_64BIT) + *(mboxdata + 2) = + DCMD_GET_DISK_CONFIG_64; + *(mboxdata + 3) = data[2]; /*number of elements in SG list */ + /*nr of elements in SG list */ + *(mboxdata + 4) = mbox->numsgelements; + break; + case DCMD_DELETE_LOGDRV: + case DCMD_DELETE_DRIVEGROUP: + case NC_SUBOP_ENQUIRY3: + *(mboxdata + 3) = data[2]; + set_mbox_xfer_addr (megaCfg, pScb, mbox, + FROMTO_DEVICE); + mbox->numsgelements = 0; + break; + case DCMD_CHANGE_LDNO: + case DCMD_CHANGE_LOOPID: + *(mboxdata + 3) = data[2]; + *(mboxdata + 4) = data[3]; + set_mbox_xfer_addr (megaCfg, pScb, mbox, + TO_DEVICE); + mbox->numsgelements = 0; + break; + default: + set_mbox_xfer_addr (megaCfg, pScb, mbox, + FROMTO_DEVICE); + mbox->numsgelements = 0; + break; + } /*switch */ + break; + default: + set_mbox_xfer_addr (megaCfg, pScb, mbox, FROMTO_DEVICE); + mbox->numsgelements = 0; + break; + } + } else { + + mbox->numsgelements = mega_build_sglist (megaCfg, pScb, + (u32 *) & mbox-> + xferaddr, + (u32 *) & seg); + + /* Handling some of the fw special commands */ + switch (data[0]) { + case 6: /* START_DEV */ + mbox->xferaddr = *((u32 *) & data[i + 6]); + break; + default: + break; + } + + for (i = 0; i < (SCpnt->request_bufflen - 6); i++) { + data[i] = data[i + 6]; + } + } + + return (pScb); +} + + +static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, mega_ioctl_mbox * mbox) +{ + ulong i, buffer_area, len, end, end_page, x, idx = 0; + + buffer_area = (ulong) barea; + i = buffer_area; + end = buffer_area + xfersize; + end_page = (end) & ~(PAGE_SIZE - 1); + + do { + len = PAGE_SIZE - (i % PAGE_SIZE); + x = pScb->sgList[idx].address = + virt_to_bus ((volatile void *) i); + pScb->sgList[idx].length = len; + i += len; + idx++; + } while (i < end_page); + + if ((end - i) < 0) { + printk ("megaraid:Error in user address\n"); + } + + if (end - i) { + pScb->sgList[idx].address = virt_to_bus ((volatile void *) i); + pScb->sgList[idx].length = end - i; + idx++; + } + mbox->xferaddr = virt_to_bus (pScb->sgList); + mbox->numsgelements = idx; +} + +#endif /* KERNEL_VERSION(2,3,0) */ + +#if DEBUG +static unsigned int cum_time = 0; +static unsigned int cum_time_cnt = 0; + +static void showMbox (mega_scb * pScb) +{ + mega_mailbox *mbox; + + if (pScb == NULL) + return; + + mbox = (mega_mailbox *) pScb->mboxData; + printk ("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", + pScb->SCpnt->pid, + mbox->cmd, mbox->cmdid, mbox->numsectors, + mbox->lba, mbox->xferaddr, mbox->logdrv, mbox->numsgelements); +} + +#endif + +/*-------------------------------------------------------------------- + * Interrupt service routine + *--------------------------------------------------------------------*/ +static void megaraid_isr (int irq, void *devp, struct pt_regs *regs) +{ + IO_LOCK_T + mega_host_config * megaCfg; + u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE]; + u32 dword = 0; + mega_mailbox *mbox; + mega_scb *pScb; + u_char qCnt, qStatus; + u_char completed[MAX_FIRMWARE_STATUS]; + Scsi_Cmnd *SCpnt; + + megaCfg = (mega_host_config *) devp; + mbox = (mega_mailbox *) tmpBox; + + if (megaCfg->host->irq == irq) { + if (megaCfg->flag & IN_ISR) { + TRACE (("ISR called reentrantly!!\n")); + printk ("ISR called reentrantly!!\n"); + } + megaCfg->flag |= IN_ISR; + + if (mega_busyWaitMbox (megaCfg)) { + printk (KERN_WARNING "Error: mailbox busy in isr!\n"); + } + + /* Check if a valid interrupt is pending */ + if (megaCfg->flag & BOARD_QUARTZ) { + dword = RDOUTDOOR (megaCfg); + if (dword != 0x10001234) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + return; + } + } else { + byte = READ_PORT (megaCfg->host->io_port, INTR_PORT); + if ((byte & VALID_INTR_BYTE) == 0) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + return; + } + WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); + } + + for (idx = 0; idx < MAX_FIRMWARE_STATUS; idx++) + completed[idx] = 0; + + IO_LOCK; + + megaCfg->nInterrupts++; + qCnt = 0xff; + while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) ; + + qStatus = 0xff; + while ((qStatus = megaCfg->mbox->status) == 0xFF) ; + + /* Get list of completed requests */ + for (idx = 0; idx < qCnt; idx++) { + while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) { + printk ("p"); + } + completed[idx] = sIdx; + sIdx = 0xFF; + } + + if (megaCfg->flag & BOARD_QUARTZ) { + WROUTDOOR (megaCfg, dword); + /* Acknowledge interrupt */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* In this case mbox contains physical address */ +#if 0 + WRINDOOR (megaCfg, megaCfg->adjdmahandle64 | 0x2); +#else + WRINDOOR (megaCfg, 0x2); +#endif + +#else + +#if 0 + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); +#else + WRINDOOR (megaCfg, 0x2); #endif - } +#endif + +#if 0 + while (RDINDOOR (megaCfg) & 0x02) ; +#endif + } else { + CLEAR_INTR (megaCfg->host->io_port); + } + +#if DEBUG + if (qCnt >= MAX_FIRMWARE_STATUS) { + printk ("megaraid_isr: cmplt=%d ", qCnt); + } +#endif + + for (idx = 0; idx < qCnt; idx++) { + sIdx = completed[idx]; + if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) { + pScb = &megaCfg->scbList[sIdx - 1]; + + /* ASSERT(pScb->state == SCB_ISSUED); */ + +#if DEBUG + if (((jiffies) - pScb->isrcount) > maxCmdTime) { + maxCmdTime = (jiffies) - pScb->isrcount; + printk + ("megaraid_isr : cmd time = %u\n", + maxCmdTime); + } +#endif + /* + * Assuming that the scsi command, for which + * an abort request was received earlier, has + * completed. + */ + if (pScb->state == SCB_ABORTED) { + SCpnt = pScb->SCpnt; + } + if (pScb->state == SCB_RESET) { + SCpnt = pScb->SCpnt; + mega_freeSCB (megaCfg, pScb); + SCpnt->result = (DID_RESET << 16); + if (megaCfg->qCompletedH == NULL) { + megaCfg->qCompletedH = + megaCfg->qCompletedT = + SCpnt; + } else { + megaCfg->qCompletedT-> + host_scribble = + (unsigned char *) SCpnt; + megaCfg->qCompletedT = SCpnt; + } + megaCfg->qCompletedT->host_scribble = + (unsigned char *) NULL; + megaCfg->qCcnt++; + continue; + } + + /* We don't want the ISR routine to touch M_RD_IOCTL_CMD_NEW commands, so + * don't mark them as complete, instead we pop their semaphore so + * that the queue routine can finish them off + */ + if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { + /* save the status byte for the queue routine to use */ + pScb->SCpnt->result = qStatus; + up (&pScb->ioctl_sem); + } else { + /* Mark command as completed */ + mega_cmd_done (megaCfg, pScb, qStatus); + } + } else { + printk + ("megaraid: wrong cmd id completed from firmware:id=%x\n", + sIdx); + } + } + + mega_rundoneq (megaCfg); + + megaCfg->flag &= ~IN_ISR; + /* Loop through any pending requests */ + mega_runpendq (megaCfg); + IO_UNLOCK; + + } + } /*==================================================*/ /* Wait until the controller's mailbox is available */ /*==================================================*/ + static int mega_busyWaitMbox (mega_host_config * megaCfg) { - mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; - long counter; + mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; + long counter; - for (counter = 0; counter < 10000; counter++) { - if (!mbox->busy) { - return 0; - } - udelay (100); - barrier(); - } - return -1; /* give up after 1 second */ + for (counter = 0; counter < 10000; counter++) { + if (!mbox->busy) { + return 0; + } + udelay (100); + barrier (); + } + return -1; /* give up after 1 second */ } /*===================================================== @@ -1113,153 +1826,278 @@ * -1: the command was not actually issued out * othercases: * intr==0, return ScsiStatus, i.e. mbox->status - * intr==1, return 0 + * intr==1, return 0 *===================================================== */ -static int megaIssueCmd (mega_host_config * megaCfg, - u_char * mboxData, - mega_scb * pScb, - int intr) -{ - mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; - u_char byte; - u32 cmdDone; - u32 phys_mbox; - u8 retval=-1; +static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, + mega_scb * pScb, int intr) +{ + volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + volatile mega_mailbox64 *mbox64 = (mega_mailbox64 *) megaCfg->mbox64; +#endif + + u_char byte; + +#ifdef __LP64__ + u64 phys_mbox; +#else + u32 phys_mbox; +#endif + u8 retval = -1; - mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0); /* Set cmdid */ - mboxData[0xF] = 1; /* Set busy */ + mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE); /* Set cmdid */ + mboxData[0xF] = 1; /* Set busy */ - phys_mbox = virt_to_bus (megaCfg->mbox); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* In this case mbox contains physical address */ + phys_mbox = megaCfg->adjdmahandle64; +#else + phys_mbox = virt_to_bus (megaCfg->mbox); +#endif #if DEBUG - showMbox(pScb); + ShowMbox (pScb); #endif - /* Wait until mailbox is free */ - if (mega_busyWaitMbox (megaCfg)) { - printk("Blocked mailbox......!!\n"); - udelay(1000); + /* Wait until mailbox is free */ + if (mega_busyWaitMbox (megaCfg)) { + printk ("Blocked mailbox......!!\n"); + udelay (1000); #if DEBUG - showMbox(pLastScb); + showMbox (pLastScb); +#endif + + /* Abort command */ + if (pScb == NULL) { + TRACE (("NULL pScb in megaIssue\n")); + printk ("NULL pScb in megaIssue\n"); + } + mega_cmd_done (megaCfg, pScb, 0x08); + return -1; + } + + pLastScb = pScb; + + /* Copy mailbox data into host structure */ + megaCfg->mbox64->xferSegment_lo = 0; + megaCfg->mbox64->xferSegment_hi = 0; + + memcpy ((char *) mbox, mboxData, 16); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + switch (mboxData[0]) { + case MEGA_MBOXCMD_LREAD64: + case MEGA_MBOXCMD_LWRITE64: + mbox64->xferSegment_lo = mbox->xferaddr; + mbox64->xferSegment_hi = 0; + mbox->xferaddr = 0xFFFFFFFF; + break; + } #endif - - /* Abort command */ - if (pScb == NULL) { - TRACE(("NULL pScb in megaIssue\n")); - printk("NULL pScb in megaIssue\n"); - } - mega_cmd_done (megaCfg, pScb, 0x08); - return -1; - } - - pLastScb = pScb; - - /* Copy mailbox data into host structure */ - megaCfg->mbox64->xferSegment = 0; - memcpy (mbox, mboxData, 16); - - /* Kick IO */ - if (intr) { - - /* Issue interrupt (non-blocking) command */ - if (megaCfg->flag & BOARD_QUARTZ) { - mbox->mraid_poll = 0; - mbox->mraid_ack = 0; - WRINDOOR (megaCfg, phys_mbox | 0x1); - } - else { - ENABLE_INTR (megaCfg->host->io_port); - ISSUE_COMMAND (megaCfg->host->io_port); - } - pScb->state = SCB_ISSUED; - - retval=0; - } - else { /* Issue non-ISR (blocking) command */ - disable_irq(megaCfg->host->irq); - if (megaCfg->flag & BOARD_QUARTZ) { - mbox->mraid_poll = 0; - mbox->mraid_ack = 0; - WRINDOOR (megaCfg, phys_mbox | 0x1); - - while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234); - WROUTDOOR (megaCfg, cmdDone); - - if (pScb) { - mega_cmd_done (megaCfg, pScb, mbox->status); - } - - WRINDOOR (megaCfg, phys_mbox | 0x2); - while (RDINDOOR (megaCfg) & 0x2); - - } - else { - DISABLE_INTR (megaCfg->host->io_port); - ISSUE_COMMAND (megaCfg->host->io_port); - - while (!((byte = READ_PORT (megaCfg->host->io_port, INTR_PORT)) & INTR_VALID)); - WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); - - ENABLE_INTR (megaCfg->host->io_port); - CLEAR_INTR (megaCfg->host->io_port); - - if (pScb) { - mega_cmd_done (megaCfg, pScb, mbox->status); - } - else { - TRACE (("Error: NULL pScb!\n")); - } - } - enable_irq(megaCfg->host->irq); - retval=mbox->status; - } + + /* Kick IO */ + if (intr) { + /* Issue interrupt (non-blocking) command */ + if (megaCfg->flag & BOARD_QUARTZ) { + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + + WRINDOOR (megaCfg, phys_mbox | 0x1); + } else { + ENABLE_INTR (megaCfg->host->io_port); + ISSUE_COMMAND (megaCfg->host->io_port); + } + pScb->state = SCB_ISSUED; + + retval = 0; + } else { /* Issue non-ISR (blocking) command */ + disable_irq (megaCfg->host->irq); + if (megaCfg->flag & BOARD_QUARTZ) { + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + mbox->numstatus = 0xFF; + mbox->status = 0xFF; + WRINDOOR (megaCfg, phys_mbox | 0x1); + + while (mbox->numstatus == 0xFF) ; + while (mbox->status == 0xFF) ; + while (mbox->mraid_poll != 0x77) ; + mbox->mraid_poll = 0; + mbox->mraid_ack = 0x77; + + /* while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234); + WROUTDOOR (megaCfg, cmdDone); */ + + if (pScb) { + mega_cmd_done (megaCfg, pScb, mbox->status); + } + + WRINDOOR (megaCfg, phys_mbox | 0x2); + while (RDINDOOR (megaCfg) & 0x2) ; + + } else { + DISABLE_INTR (megaCfg->host->io_port); + ISSUE_COMMAND (megaCfg->host->io_port); + + while (! + ((byte = + READ_PORT (megaCfg->host->io_port, + INTR_PORT)) & INTR_VALID)) ; + WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); + + ENABLE_INTR (megaCfg->host->io_port); + CLEAR_INTR (megaCfg->host->io_port); + + if (pScb) { + mega_cmd_done (megaCfg, pScb, mbox->status); + } else { + TRACE (("Error: NULL pScb!\n")); + } + } + enable_irq (megaCfg->host->irq); + retval = mbox->status; + } #if DEBUG - while (mega_busyWaitMbox (megaCfg)) { - printk("Blocked mailbox on exit......!\n"); - udelay(1000); - } + while (mega_busyWaitMbox (megaCfg)) { + printk(KERN_ERR "Blocked mailbox on exit......!\n"); + udelay (1000); + } #endif - return retval; + return retval; } /*------------------------------------------------------------------- * Copies data to SGLIST *-------------------------------------------------------------------*/ -static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb, - u32 * buffer, u32 * length) +/* Note: + For 64 bit cards, we need a minimum of one SG element for read/write +*/ + +static int +mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb, + u32 * buffer, u32 * length) { - struct scatterlist *sgList; - int idx; + struct scatterlist *sgList; + int idx; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + int sgcnt; +#endif + + mega_mailbox *mbox = NULL; + + mbox = (mega_mailbox *) scb->mboxData; + /* Scatter-gather not used */ + if (scb->SCpnt->use_sg == 0) { + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scb->dma_h_bulkdata = pci_map_single (megaCfg->dev, + scb->SCpnt->request_buffer, + scb->SCpnt->request_bufflen, + scb->dma_direction); + /* We need to handle special commands like READ64, WRITE64 + as they need a minimum of 1 SG irrespective of actaully SG + */ + if ((megaCfg->flag & BOARD_64BIT) && + ((mbox->cmd == MEGA_MBOXCMD_LREAD64) || + (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) { + scb->sg64List[0].address = scb->dma_h_bulkdata; + scb->sg64List[0].length = scb->SCpnt->request_bufflen; + *buffer = scb->dma_sghandle64; + *length = 0; + scb->sglist_count = 1; + return 1; + } else { + *buffer = scb->dma_h_bulkdata; + *length = (u32) scb->SCpnt->request_bufflen; + } +#else + *buffer = virt_to_bus (scb->SCpnt->request_buffer); + *length = (u32) scb->SCpnt->request_bufflen; +#endif + return 0; + } + + sgList = (struct scatterlist *) scb->SCpnt->request_buffer; - /* Scatter-gather not used */ - if (scb->SCpnt->use_sg == 0) { - *buffer = virt_to_bus (scb->SCpnt->request_buffer); - *length = (u32) scb->SCpnt->request_bufflen; - return 0; - } - - sgList = (struct scatterlist *) scb->SCpnt->request_buffer; - if (scb->SCpnt->use_sg == 1) { - *buffer = virt_to_bus (sgList[0].address); - *length = (u32) sgList[0].length; - return 0; - } - - /* Copy Scatter-Gather list info into controller structure */ - for (idx = 0; idx < scb->SCpnt->use_sg; idx++) { - scb->sgList[idx].address = virt_to_bus (sgList[idx].address); - scb->sgList[idx].length = (u32) sgList[idx].length; - } - - /* Reset pointer and length fields */ - *buffer = virt_to_bus (scb->sgList); - *length = 0; + if (scb->SCpnt->use_sg == 1) { - /* Return count of SG requests */ - return scb->SCpnt->use_sg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scb->dma_h_bulkdata = pci_map_single (megaCfg->dev, + sgList[0].address, + sgList[0].length, scb->dma_direction); + + if ((megaCfg->flag & BOARD_64BIT) && + ((mbox->cmd == MEGA_MBOXCMD_LREAD64) || + (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) { + scb->sg64List[0].address = scb->dma_h_bulkdata; + scb->sg64List[0].length = scb->SCpnt->request_bufflen; + *buffer = scb->dma_sghandle64; + *length = 0; + scb->sglist_count = 1; + return 1; + } else { + *buffer = scb->dma_h_bulkdata; + *length = (u32) sgList[0].length; + } +#else + *buffer = virt_to_bus (sgList[0].address); + *length = (u32) sgList[0].length; +#endif + + return 0; + } + + /* Copy Scatter-Gather list info into controller structure */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + sgcnt = pci_map_sg (megaCfg->dev, + sgList, scb->SCpnt->use_sg, scb->dma_direction); + + /* Determine the validity of the new count */ + if (sgcnt == 0) + printk ("pci_map_sg returned zero!!! "); + + for (idx = 0; idx < sgcnt; idx++, sgList++) { + + if ((megaCfg->flag & BOARD_64BIT) && + ((mbox->cmd == MEGA_MBOXCMD_LREAD64) || + (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) { + scb->sg64List[idx].address = sg_dma_address (sgList); + scb->sg64List[idx].length = sg_dma_len (sgList); + } else { + scb->sgList[idx].address = sg_dma_address (sgList); + scb->sgList[idx].length = sg_dma_len (sgList); + } + + } + +#else + for (idx = 0; idx < scb->SCpnt->use_sg; idx++) { + scb->sgList[idx].address = virt_to_bus (sgList[idx].address); + scb->sgList[idx].length = (u32) sgList[idx].length; + } +#endif + + /* Reset pointer and length fields */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + *buffer = scb->dma_sghandle64; + scb->sglist_count = scb->SCpnt->use_sg; +#else + *buffer = virt_to_bus (scb->sgList); +#endif + *length = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* Return count of SG requests */ + return sgcnt; +#else + /* Return count of SG requests */ + return scb->SCpnt->use_sg; +#endif } /*-------------------------------------------------------------------- @@ -1278,169 +2116,243 @@ * 10 01 numstatus byte * 11 01 status byte *--------------------------------------------------------------------*/ -static int mega_register_mailbox (mega_host_config * megaCfg, u32 paddr) +static int +mega_register_mailbox (mega_host_config * megaCfg, u32 paddr) { - /* align on 16-byte boundry */ - megaCfg->mbox = &megaCfg->mailbox64.mailbox; - megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xfffffff0); - megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4); - paddr = (paddr + 4 + 16) & 0xfffffff0; - - /* Register mailbox area with the firmware */ - if (!(megaCfg->flag & BOARD_QUARTZ)) { - WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF); - WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF); - WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF); - WRITE_PORT (megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF); - WRITE_PORT (megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE); - - CLEAR_INTR (megaCfg->host->io_port); - ENABLE_INTR (megaCfg->host->io_port); - } - return 0; -} + /* align on 16-byte boundry */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox; +#else + megaCfg->mbox = &megaCfg->mailbox64.mailbox; +#endif + +#ifdef __LP64__ + megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ((u64) (-1) ^ 0x0F)); + megaCfg->adjdmahandle64 = (megaCfg->dma_handle64 + 16) & ((u64) (-1) ^ 0x0F); + megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - sizeof (u64)); + paddr = (paddr + 4 + 16) & ((u64) (-1) ^ 0x0F); +#else + megaCfg->mbox + = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xFFFFFFF0); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + megaCfg->adjdmahandle64 = ((megaCfg->dma_handle64 + 16) & 0xFFFFFFF0); +#endif + + megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - 8); + paddr = (paddr + 4 + 16) & 0xFFFFFFF0; +#endif + + /* Register mailbox area with the firmware */ + if (!(megaCfg->flag & BOARD_QUARTZ)) { + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1, + (paddr >> 8) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2, + (paddr >> 16) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, MBOX_PORT3, + (paddr >> 24) & 0xFF); + WRITE_PORT (megaCfg->host->io_port, ENABLE_MBOX_REGION, + ENABLE_MBOX_BYTE); + + CLEAR_INTR (megaCfg->host->io_port); + ENABLE_INTR (megaCfg->host->io_port); + } + return 0; +} /*--------------------------------------------------------------------------- * mega_Convert8ldTo40ld() -- takes all info in AdapterInquiry structure and * puts it into ProductInfo and Enquiry3 structures for later use *---------------------------------------------------------------------------*/ -static void mega_Convert8ldTo40ld( mega_RAIDINQ *inquiry, - mega_Enquiry3 *enquiry3, - megaRaidProductInfo *productInfo ) -{ - int i; - - productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds; - enquiry3->rbldRate = inquiry->AdpInfo.RbldRate; - productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent; - for (i=0;i<4;i++) { - productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i]; - productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i]; - } - enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval; - productInfo->DramSize = inquiry->AdpInfo.DramSize; - - enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv; - for (i=0;ilDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i]; - enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i]; - enquiry3->lDrvState[i] = inquiry->LogdrvInfo.LDrvState[i]; - } - - for (i=0;i<(MAX_PHYSICAL_DRIVES);i++) { - enquiry3->pDrvState[i] = inquiry->PhysdrvInfo.PDrvState[i]; - } -} +static void mega_Convert8ldTo40ld (mega_RAIDINQ * inquiry, + mega_Enquiry3 * enquiry3, + megaRaidProductInfo * productInfo) +{ + int i; + + productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds; + enquiry3->rbldRate = inquiry->AdpInfo.RbldRate; + productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent; + + for (i = 0; i < 4; i++) { + productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i]; + productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i]; + } + enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval; + productInfo->DramSize = inquiry->AdpInfo.DramSize; + + enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv; + + for (i = 0; i < MAX_LOGICAL_DRIVES; i++) { + enquiry3->lDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i]; + enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i]; + enquiry3->lDrvState[i] + = inquiry->LogdrvInfo.LDrvState[i]; + } + for (i = 0; i < (MAX_PHYSICAL_DRIVES); i++) { + enquiry3->pDrvState[i] + = inquiry->PhysdrvInfo.PDrvState[i]; + } +} /*------------------------------------------------------------------- * Issue an adapter info query to the controller *-------------------------------------------------------------------*/ static int mega_i_query_adapter (mega_host_config * megaCfg) { - mega_Enquiry3 *enquiry3Pnt; - mega_mailbox *mbox; - u_char mboxData[16]; - u32 paddr; - u8 retval; - - /* Initialize adapter inquiry mailbox*/ - paddr = virt_to_bus (megaCfg->mega_buffer); - mbox = (mega_mailbox *) mboxData; + mega_Enquiry3 *enquiry3Pnt; + mega_mailbox *mbox; + u_char mboxData[16]; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + dma_addr_t raid_inq_dma_handle = 0, prod_info_dma_handle = 0, enquiry3_dma_handle = 0; +#endif + u8 retval; + + /* Initialize adapter inquiry mailbox */ + + mbox = (mega_mailbox *) mboxData; - memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer)); - memset (mbox, 0, 16); + memset ((void *) megaCfg->mega_buffer, 0, + sizeof (megaCfg->mega_buffer)); + memset (mbox, 0, 16); /* - * Try to issue Enquiry3 command - * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and + * Try to issue Enquiry3 command + * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and * update enquiry3 structure */ - mbox->xferaddr = virt_to_bus ( (void*) megaCfg->mega_buffer); - /* Initialize mailbox databuffer addr */ - enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer; - /* point mega_Enguiry3 to the data buf */ - - mboxData[0]=FC_NEW_CONFIG ; /* i.e. mbox->cmd=0xA1 */ - mboxData[2]=NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */ - mboxData[3]=ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */ - - /* Issue a blocking command to the card */ - if ( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0 ) - { /* the adapter does not support 40ld*/ - - mega_RAIDINQ adapterInquiryData; - mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData; - - mbox->xferaddr = virt_to_bus ( (void*) adapterInquiryPnt); - - mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; /*issue old 0x05 command to adapter*/ - /* Issue a blocking command to the card */; - retval=megaIssueCmd (megaCfg, mboxData, NULL, 0); - - /*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/ - mega_Convert8ldTo40ld( adapterInquiryPnt, - enquiry3Pnt, - (megaRaidProductInfo * ) &megaCfg->productInfo ); - - } - else{ /* adapter supports 40ld */ - megaCfg->flag |= BOARD_40LD; - - /*get productInfo, which is static information and will be unchanged*/ - mbox->xferaddr = virt_to_bus ( (void*) &megaCfg->productInfo ); - - mboxData[0]=FC_NEW_CONFIG ; /* i.e. mbox->cmd=0xA1 */ - mboxData[2]=NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ - - if( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0 ) - printk("ami:Product_info (0x0E) cmd failed with error: %d\n", retval); - - } - - megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent; - megaCfg->host->max_id = 16; /* max targets per channel */ - /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1;*/ - megaCfg->host->max_lun = /* max lun */ - (megaCfg->flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES; - megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN; - - megaCfg->numldrv = enquiry3Pnt->numLDrv; - megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds; - if(megaCfg->max_cmds > MAX_COMMANDS) megaCfg->max_cmds = MAX_COMMANDS - 1; - - megaCfg->host->can_queue = megaCfg->max_cmds; - - if (megaCfg->host->can_queue >= MAX_COMMANDS) { - megaCfg->host->can_queue = MAX_COMMANDS-1; - } - -#ifdef HP /* use HP firmware and bios version encoding */ - sprintf (megaCfg->fwVer, "%c%d%d.%d%d", - megaCfg->productInfo.FwVer[2], - megaCfg->productInfo.FwVer[1] >> 8, - megaCfg->productInfo.FwVer[1] & 0x0f, - megaCfg->productInfo.FwVer[2] >> 8, - megaCfg->productInfo.FwVer[2] & 0x0f); - sprintf (megaCfg->biosVer, "%c%d%d.%d%d", - megaCfg->productInfo.BiosVer[2], - megaCfg->productInfo.BiosVer[1] >> 8, - megaCfg->productInfo.BiosVer[1] & 0x0f, - megaCfg->productInfo.BiosVer[2] >> 8, - megaCfg->productInfo.BiosVer[2] & 0x0f); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + enquiry3_dma_handle = pci_map_single (megaCfg->dev, + (void *) megaCfg->mega_buffer, + (2 * 1024L), PCI_DMA_FROMDEVICE); + + mbox->xferaddr = enquiry3_dma_handle; +#else + /*Taken care */ + mbox->xferaddr = virt_to_bus ((void *) megaCfg->mega_buffer); +#endif + + /* Initialize mailbox databuffer addr */ + enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer; + /* point mega_Enguiry3 to the data buf */ + + mboxData[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ + mboxData[2] = NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */ + mboxData[3] = ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */ + + /* Issue a blocking command to the card */ + if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0) { /* the adapter does not support 40ld */ + mega_RAIDINQ adapterInquiryData; + mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + raid_inq_dma_handle = pci_map_single (megaCfg->dev, + (void *) adapterInquiryPnt, + sizeof (mega_RAIDINQ), + PCI_DMA_FROMDEVICE); + mbox->xferaddr = raid_inq_dma_handle; +#else + /*taken care */ + mbox->xferaddr = virt_to_bus ((void *) adapterInquiryPnt); +#endif + + mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; /*issue old 0x05 command to adapter */ + /* Issue a blocking command to the card */ ; + retval = megaIssueCmd (megaCfg, mboxData, NULL, 0); + + pci_unmap_single (megaCfg->dev, + raid_inq_dma_handle, + sizeof (mega_RAIDINQ), PCI_DMA_FROMDEVICE); + + /*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/ + mega_Convert8ldTo40ld (adapterInquiryPnt, + enquiry3Pnt, + (megaRaidProductInfo *) & megaCfg-> + productInfo); + + } else { /* adapter supports 40ld */ + megaCfg->flag |= BOARD_40LD; + + pci_unmap_single (megaCfg->dev, + enquiry3_dma_handle, + (2 * 1024L), PCI_DMA_FROMDEVICE); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +/*get productInfo, which is static information and will be unchanged*/ + prod_info_dma_handle + = pci_map_single (megaCfg->dev, + (void *) &megaCfg->productInfo, + sizeof (megaRaidProductInfo), + PCI_DMA_FROMDEVICE); + mbox->xferaddr = prod_info_dma_handle; +#else + /*taken care */ + mbox->xferaddr = virt_to_bus ((void *) &megaCfg->productInfo); +#endif + + mboxData[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ + mboxData[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ + + if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0) + printk ("ami:Product_info cmd failed with error: %d\n", + retval); + + pci_unmap_single (megaCfg->dev, + prod_info_dma_handle, + sizeof (megaRaidProductInfo), + PCI_DMA_FROMDEVICE); + } + + megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent; + megaCfg->host->max_id = 16; /* max targets per channel */ + /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1; */ + megaCfg->host->max_lun = /* max lun */ + (megaCfg-> + flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES; + megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN; + + megaCfg->numldrv = enquiry3Pnt->numLDrv; + megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds; + if (megaCfg->max_cmds > MAX_COMMANDS) + megaCfg->max_cmds = MAX_COMMANDS - 1; + + megaCfg->host->can_queue = megaCfg->max_cmds - 1; + +#if 0 + if (megaCfg->host->can_queue >= MAX_COMMANDS) { + megaCfg->host->can_queue = MAX_COMMANDS - 16; + } +#endif + +#ifdef MEGA_HP_FIX /* use HP firmware and bios version encoding */ + sprintf (megaCfg->fwVer, "%c%d%d.%d%d", + megaCfg->productInfo.FwVer[2], + megaCfg->productInfo.FwVer[1] >> 8, + megaCfg->productInfo.FwVer[1] & 0x0f, + megaCfg->productInfo.FwVer[2] >> 8, + megaCfg->productInfo.FwVer[2] & 0x0f); + sprintf (megaCfg->biosVer, "%c%d%d.%d%d", + megaCfg->productInfo.BiosVer[2], + megaCfg->productInfo.BiosVer[1] >> 8, + megaCfg->productInfo.BiosVer[1] & 0x0f, + megaCfg->productInfo.BiosVer[2] >> 8, + megaCfg->productInfo.BiosVer[2] & 0x0f); #else - memcpy (megaCfg->fwVer, (void *)megaCfg->productInfo.FwVer, 4); + memcpy (megaCfg->fwVer, (char *) megaCfg->productInfo.FwVer, 4); megaCfg->fwVer[4] = 0; - memcpy (megaCfg->biosVer, (void *)megaCfg->productInfo.BiosVer, 4); + memcpy (megaCfg->biosVer, (char *) megaCfg->productInfo.BiosVer, 4); megaCfg->biosVer[4] = 0; #endif - printk ("megaraid: [%s:%s] detected %d logical drives" CRLFSTR, - megaCfg->fwVer, - megaCfg->biosVer, - megaCfg->numldrv); + printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR, + megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv); + /* + * I hope that I can unmap here, reason DMA transaction is not required any more + * after this + */ return 0; } @@ -1454,227 +2366,665 @@ /*---------------------------------------------------------- * Returns data to be displayed in /proc/scsi/megaraid/X *----------------------------------------------------------*/ -int megaraid_proc_info (char *buffer, char **start, off_t offset, + +static int megaraid_proc_info (char *buffer, char **start, off_t offset, int length, int host_no, int inout) { - *start = buffer; - return 0; + *start = buffer; + return 0; } -int mega_findCard (Scsi_Host_Template * pHostTmpl, - u16 pciVendor, u16 pciDev, - long flag) -{ - mega_host_config *megaCfg; - struct Scsi_Host *host; - u_char megaIrq; - u32 megaBase; - u16 numFound = 0; - - struct pci_dev *pdev = NULL; - - while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) { - if (pci_enable_device(pdev)) - continue; - if ((flag & BOARD_QUARTZ) && (skip_id == -1)) { - u16 magic; - pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic); - if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471)) - continue; /* not an AMI board */ - } - printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x: in %s\n", - pciVendor, - pciDev, - pdev->slot_name); - - /* Read the base port and IRQ from PCI */ - megaBase = pci_resource_start (pdev, 0); - megaIrq = pdev->irq; - - if (flag & BOARD_QUARTZ) - megaBase = (long) ioremap (megaBase, 128); - else - megaBase += 0x10; - - /* Initialize SCSI Host structure */ - host = scsi_register (pHostTmpl, sizeof (mega_host_config)); - if(host == NULL) - continue; - megaCfg = (mega_host_config *) host->hostdata; - memset (megaCfg, 0, sizeof (mega_host_config)); - - printk ("scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, - host->host_no, (u_int) megaBase, megaIrq); - - /* Copy resource info into structure */ - megaCfg->qCompletedH = NULL; - megaCfg->qCompletedT = NULL; - megaCfg->qPendingH = NULL; - megaCfg->qPendingT = NULL; - megaCfg->qFreeH = NULL; - megaCfg->qFreeT = NULL; - megaCfg->qFcnt = 0; - megaCfg->qPcnt = 0; - megaCfg->qCcnt = 0; - megaCfg->flag = flag; - megaCfg->host = host; - megaCfg->base = megaBase; - megaCfg->host->irq = megaIrq; - megaCfg->host->io_port = megaBase; - megaCfg->host->n_io_port = 16; - megaCfg->host->unique_id = (pdev->bus->number << 8) | pdev->devfn; - megaCtlrs[numCtlrs++] = megaCfg; - if (flag != BOARD_QUARTZ) { - /* Request our IO Range */ - if (request_region (megaBase, 16, "megaraid")) { - printk (KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR); - scsi_unregister (host); - continue; - } - } - - /* Request our IRQ */ - if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ, - "megaraid", megaCfg)) { - printk (KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR, - megaIrq); - scsi_unregister (host); - continue; - } - - mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64)); - mega_i_query_adapter (megaCfg); - - if (flag == BOARD_QUARTZ) { - /* Check to see if this is a Dell PERC RAID controller model 466 */ - u16 subsysid, subsysvid; -#if LINUX_VERSION_CODE < 0x20100 - pcibios_read_config_word (pciBus, pciDevFun, - PCI_SUBSYSTEM_VENDOR_ID, - &subsysvid); - pcibios_read_config_word (pciBus, pciDevFun, - PCI_SUBSYSTEM_ID, - &subsysid); -#else - pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid); - pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid); -#endif - if ( (subsysid == 0x1111) && (subsysvid == 0x1111) && - (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) { - printk(KERN_WARNING -"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n" -"megaraid: 3.00 or 3.01. This driver is known to have corruption issues\n" -"megaraid: with those firmware versions on this specific card. In order\n" -"megaraid: to protect your data, please upgrade your firmware to version\n" -"megaraid: 3.10 or later, available from the Dell Technical Support web\n" -"megaraid: site at\n" -"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n"); - megaraid_release (host); -#ifdef MODULE - continue; -#else - while(1) schedule_timeout(1 * HZ); -#endif - } - } - - /* Initialize SCBs */ - if (mega_initSCB (megaCfg)) { - megaraid_release (host); - continue; - } - - numFound++; - } - return numFound; +static int mega_findCard (Scsi_Host_Template * pHostTmpl, + u16 pciVendor, u16 pciDev, long flag) +{ + mega_host_config *megaCfg = NULL; + struct Scsi_Host *host = NULL; + u_char pciBus, pciDevFun, megaIrq; + + u16 magic; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + u32 magic64; +#endif + + int i; + +#ifdef __LP64__ + u64 megaBase; +#else + u32 megaBase; +#endif + + u16 pciIdx = 0; + u16 numFound = 0; + u16 subsysid, subsysvid; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ + while (!pcibios_find_device + (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) { +#else + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */ + struct pci_dev *pdev = NULL; +#else + struct pci_dev *pdev = pci_devices; +#endif + + while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) { + if (pci_enable_device (pdev)) + continue; + pciBus = pdev->bus->number; + pciDevFun = pdev->devfn; +#endif + if ((flag & BOARD_QUARTZ) && (skip_id == -1)) { + pcibios_read_config_word (pciBus, pciDevFun, + PCI_CONF_AMISIG, &magic); + if ((magic != AMI_SIGNATURE) + && (magic != AMI_SIGNATURE_471)) { + pciIdx++; + continue; /* not an AMI board */ + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pcibios_read_config_dword (pciBus, pciDevFun, + PCI_CONF_AMISIG64, &magic64); + + if (magic64 == AMI_64BIT_SIGNATURE) + flag |= BOARD_64BIT; +#endif + } + + /* Hmmm...Should we not make this more modularized so that in future we dont add + for each firmware */ + + if (flag & BOARD_QUARTZ) { + /* Check to see if this is a Dell PERC RAID controller model 466 */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ + pcibios_read_config_word (pciBus, pciDevFun, + PCI_SUBSYSTEM_VENDOR_ID, + &subsysvid); + pcibios_read_config_word (pciBus, pciDevFun, + PCI_SUBSYSTEM_ID, &subsysid); +#else + pci_read_config_word (pdev, + PCI_SUBSYSTEM_VENDOR_ID, + &subsysvid); + pci_read_config_word (pdev, + PCI_SUBSYSTEM_ID, &subsysid); +#endif + if ((subsysid == 0x1111) && (subsysvid == 0x1111) && + (!strcmp (megaCfg->fwVer, "3.00") + || !strcmp (megaCfg->fwVer, "3.01"))) { + printk (KERN_WARNING + "megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n" + "megaraid: 3.00 or 3.01. This driver is known to have corruption issues\n" + "megaraid: with those firmware versions on this specific card. In order\n" + "megaraid: to protect your data, please upgrade your firmware to version\n" + "megaraid: 3.10 or later, available from the Dell Technical Support web\n" + "megaraid: site at\n" + "http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n"); + continue; + } + + /* If we dont detect this valid subsystem vendor id's + we refuse to load the driver + PART of PC200X compliance + */ + + if ((subsysvid != AMI_SUBSYS_ID) + && (subsysvid != DELL_SUBSYS_ID) + && (subsysvid != HP_SUBSYS_ID)) + continue; + } + + printk (KERN_INFO + "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n", + pciVendor, pciDev, pciIdx, pciBus, PCI_SLOT (pciDevFun), + PCI_FUNC (pciDevFun)); + /* Read the base port and IRQ from PCI */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ + pcibios_read_config_dword (pciBus, pciDevFun, + PCI_BASE_ADDRESS_0, + (u_int *) & megaBase); + pcibios_read_config_byte (pciBus, pciDevFun, + PCI_INTERRUPT_LINE, &megaIrq); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */ + megaBase = pdev->base_address[0]; + megaIrq = pdev->irq; +#else + + megaBase = pci_resource_start (pdev, 0); + megaIrq = pdev->irq; +#endif + + pciIdx++; + + if (flag & BOARD_QUARTZ) { + megaBase = (long) ioremap (megaBase, 128); + if (!megaBase) + continue; + } else + megaBase += 0x10; + + /* Initialize SCSI Host structure */ + host = scsi_register (pHostTmpl, sizeof (mega_host_config)); + if (!host) + goto err_unmap; + + megaCfg = (mega_host_config *) host->hostdata; + memset (megaCfg, 0, sizeof (mega_host_config)); + + printk (KERN_INFO "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d" + M_RD_CRLFSTR, host->host_no, (u_int) megaBase, megaIrq); + + if (flag & BOARD_64BIT) + printk (KERN_INFO "scsi%d : Enabling 64 bit support\n", + host->host_no); + + /* Copy resource info into structure */ + megaCfg->qCompletedH = NULL; + megaCfg->qCompletedT = NULL; + megaCfg->qPendingH = NULL; + megaCfg->qPendingT = NULL; + megaCfg->qFreeH = NULL; + megaCfg->qFreeT = NULL; + megaCfg->qFcnt = 0; + megaCfg->qPcnt = 0; + megaCfg->qCcnt = 0; + megaCfg->lock_free = SPIN_LOCK_UNLOCKED; + megaCfg->lock_pend = SPIN_LOCK_UNLOCKED; + megaCfg->lock_scsicmd = SPIN_LOCK_UNLOCKED; + megaCfg->flag = flag; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + megaCfg->dev = pdev; +#endif + megaCfg->host = host; + megaCfg->base = megaBase; + megaCfg->host->irq = megaIrq; + megaCfg->host->io_port = megaBase; + megaCfg->host->n_io_port = 16; + megaCfg->host->unique_id = (pciBus << 8) | pciDevFun; + megaCtlrs[numCtlrs] = megaCfg; + + if (!(flag & BOARD_QUARTZ)) { + /* Request our IO Range */ + if (!request_region(megaBase, 16, "megaraid")) { + printk (KERN_WARNING "megaraid: Couldn't register I/O range!" M_RD_CRLFSTR); + goto err_unregister; + } + } + + /* Request our IRQ */ + if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ, + "megaraid", megaCfg)) { + printk (KERN_WARNING + "megaraid: Couldn't register IRQ %d!\n", + megaIrq); + goto err_release; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* + * unmap while releasing the driver, Is it required to be + * PCI_DMA_BIDIRECTIONAL + */ + + megaCfg->mailbox64ptr + = pci_alloc_consistent (megaCfg->dev, + sizeof (mega_mailbox64), + &(megaCfg->dma_handle64)); + + mega_register_mailbox (megaCfg, + virt_to_bus ((void *) megaCfg-> + mailbox64ptr)); +#else + /*Taken care */ + mega_register_mailbox (megaCfg, + virt_to_bus ((void *) &megaCfg-> + mailbox64)); +#endif + + mega_i_query_adapter (megaCfg); + + if (mega_is_bios_enabled (megaCfg)) { + mega_hbas[numCtlrs].is_bios_enabled = 1; + } + mega_hbas[numCtlrs].hostdata_addr = megaCfg; + + /* Initialize SCBs */ + if (mega_init_scb (megaCfg)) { + pci_free_consistent (megaCfg->dev, + sizeof (mega_mailbox64), + (void *) megaCfg->mailbox64ptr, + megaCfg->dma_handle64); + scsi_unregister (host); + continue; + } + + /* + * Fill in the structure which needs to be passed back to the + * application when it does an ioctl() for controller related + * information. + */ + + i = numCtlrs; + numCtlrs++; + + mcontroller[i].base = megaBase; + mcontroller[i].irq = megaIrq; + mcontroller[i].numldrv = megaCfg->numldrv; + mcontroller[i].pcibus = pciBus; + mcontroller[i].pcidev = pciDev; + mcontroller[i].pcifun = PCI_FUNC (pciDevFun); + mcontroller[i].pciid = pciIdx; + mcontroller[i].pcivendor = pciVendor; + mcontroller[i].pcislot = PCI_SLOT (pciDevFun); + mcontroller[i].uid = (pciBus << 8) | pciDevFun; + + numFound++; + + /* Set the Mode of addressing to 64 bit */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if ((megaCfg->flag & BOARD_64BIT) && BITS_PER_LONG == 64) +#ifdef __LP64__ + pdev->dma_mask = 0xffffffffffffffff; +#else + pdev->dma_mask = 0xffffffff; +#endif +#endif + continue; + err_release: + if (flag & BOARD_QUARTZ) + release_region (megaBase, 16); + err_unregister: + scsi_unregister (host); + err_unmap: + if (flag & BOARD_QUARTZ) + iounmap ((void *) megaBase); + } + return numFound; } /*--------------------------------------------------------- * Detects if a megaraid controller exists in this system *---------------------------------------------------------*/ + int megaraid_detect (Scsi_Host_Template * pHostTmpl) { - int count = 0; + int ctlridx = 0, count = 0; -#ifdef MODULE - if (megaraid) - megaraid_setup(megaraid); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */ + pHostTmpl->proc_dir = &proc_scsi_megaraid; +#else + pHostTmpl->proc_name = "megaraid"; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ + if (!pcibios_present ()) { + printk (KERN_WARNING "megaraid: PCI bios not present." + M_RD_CRLFSTR); + return 0; + } #endif + skip_id = -1; + if (megaraid && !strncmp (megaraid, "skip", strlen ("skip"))) { + if (megaraid[4] != '\0') { + skip_id = megaraid[4] - '0'; + if (megaraid[5] != '\0') { + skip_id = (skip_id * 10) + (megaraid[5] - '0'); + } + } + skip_id = (skip_id > 15) ? -1 : skip_id; + } - pHostTmpl->proc_name = "megaraid"; + printk (KERN_INFO "megaraid: " MEGARAID_VERSION M_RD_CRLFSTR); - printk ("megaraid: " MEGARAID_VERSION CRLFSTR); + memset (mega_hbas, 0, sizeof (mega_hbas)); + + count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID, 0); + count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID2, 0); + count += mega_findCard (pHostTmpl, 0x8086, + PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ); + count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI, + PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ); + + mega_reorder_hosts (); + +#ifdef CONFIG_PROC_FS + if (count) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */ + mega_proc_dir_entry = proc_mkdir ("megaraid", &proc_root); +#else + mega_proc_dir_entry = create_proc_entry ("megaraid", + S_IFDIR | S_IRUGO | + S_IXUGO, &proc_root); +#endif + if (!mega_proc_dir_entry) + printk ("megaraid: failed to create megaraid root\n"); + else + for (ctlridx = 0; ctlridx < count; ctlridx++) + mega_create_proc_entry (ctlridx, + mega_proc_dir_entry); + } +#endif - count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0); - count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0); - count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); + /* + * Register the driver as a character device, for appliactions to access + * it for ioctls. + * Ideally, this should go in the init_module() routine, but since it is + * hidden in the file "scsi_module.c" ( included in the end ), we define + * it here + * First argument (major) to register_chrdev implies a dynamic major + * number allocation. + */ + major = register_chrdev (0, "megadev", &megadev_fops); + + /* + * Register the Shutdown Notification hook in kernel + */ + if (register_reboot_notifier (&mega_notifier)) { + printk ("MegaRAID Shutdown routine not registered!!\n"); + } + init_MUTEX (&mimd_entry_mtx); - return count; + return count; } /*--------------------------------------------------------------------- * Release the controller's resources *---------------------------------------------------------------------*/ -int megaraid_release (struct Scsi_Host *pSHost) +static int megaraid_release (struct Scsi_Host *pSHost) +{ + mega_host_config *megaCfg; + mega_mailbox *mbox; + u_char mboxData[16]; + int i; + + megaCfg = (mega_host_config *) pSHost->hostdata; + mbox = (mega_mailbox *) mboxData; + + /* Flush cache to disk */ + memset (mbox, 0, 16); + mboxData[0] = 0xA; + + free_irq (megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise + extra interrupt is generated */ + + /* Issue a blocking (interrupts disabled) command to the card */ + megaIssueCmd (megaCfg, mboxData, NULL, 0); + + /* Free our resources */ + if (megaCfg->flag & BOARD_QUARTZ) { + iounmap ((void *) megaCfg->base); + } else { + release_region (megaCfg->host->io_port, 16); + } + + mega_freeSgList (megaCfg); + pci_free_consistent (megaCfg->dev, + sizeof (mega_mailbox64), + (void *) megaCfg->mailbox64ptr, + megaCfg->dma_handle64); + scsi_unregister (pSHost); + +#ifdef CONFIG_PROC_FS + if (megaCfg->controller_proc_dir_entry) { + remove_proc_entry ("stat", megaCfg->controller_proc_dir_entry); + remove_proc_entry ("status", + megaCfg->controller_proc_dir_entry); + remove_proc_entry ("config", + megaCfg->controller_proc_dir_entry); + remove_proc_entry ("mailbox", + megaCfg->controller_proc_dir_entry); + for (i = 0; i < numCtlrs; i++) { + char buf[12] = { 0 }; + sprintf (buf, "%d", i); + remove_proc_entry (buf, mega_proc_dir_entry); + } + remove_proc_entry ("megaraid", &proc_root); + } +#endif + + /* + * Unregister the character device interface to the driver. Ideally this + * should have been done in cleanup_module routine. Since this is hidden + * in file "scsi_module.c", we do it here. + * major is the major number of the character device returned by call to + * register_chrdev() routine. + */ + unregister_chrdev (major, "megadev"); + unregister_reboot_notifier (&mega_notifier); + + return 0; +} + +static int mega_is_bios_enabled (mega_host_config * megacfg) { - mega_host_config *megaCfg; - mega_mailbox *mbox; - u_char mboxData[16]; + mega_mailbox *mboxpnt; + unsigned char mbox[16]; + int ret; - megaCfg = (mega_host_config *) pSHost->hostdata; - mbox = (mega_mailbox *) mboxData; + mboxpnt = (mega_mailbox *) mbox; - /* Flush cache to disk */ - memset (mbox, 0, 16); - mboxData[0] = 0xA; + memset (mbox, 0, sizeof (mbox)); + memset ((void *) megacfg->mega_buffer, + 0, sizeof (megacfg->mega_buffer)); - free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise - extra interrupt is generated */ + /* + * issue command to find out if the BIOS is enbled for this controller + */ + mbox[0] = IS_BIOS_ENABLED; + mbox[2] = GET_BIOS; - /* Issue a blocking (interrupts disabled) command to the card */ - megaIssueCmd (megaCfg, mboxData, NULL, 0); + mboxpnt->xferaddr = virt_to_bus ((void *) megacfg->mega_buffer); - /* Free our resources */ - if (megaCfg->flag & BOARD_QUARTZ) { - iounmap ((void *) megaCfg->base); - } - else { - release_region (megaCfg->host->io_port, 16); - } + ret = megaIssueCmd (megacfg, mbox, NULL, 0); - mega_freeSgList(megaCfg); - scsi_unregister (pSHost); + return (*(char *) megacfg->mega_buffer); +} + +static void mega_reorder_hosts (void) +{ + struct Scsi_Host *shpnt; + struct Scsi_Host *shone; + struct Scsi_Host *shtwo; + mega_host_config *boot_host; + int i; + + /* + * Find the (first) host which has it's BIOS enabled + */ + boot_host = NULL; + for (i = 0; i < MAX_CONTROLLERS; i++) { + if (mega_hbas[i].is_bios_enabled) { + boot_host = mega_hbas[i].hostdata_addr; + break; + } + } - return 0; + if (boot_host == NULL) { + printk (KERN_WARNING "megaraid: no BIOS enabled.\n"); + return; + } + + /* + * Traverse through the list of SCSI hosts for our HBA locations + */ + shone = shtwo = NULL; + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + /* Is it one of ours? */ + for (i = 0; i < MAX_CONTROLLERS; i++) { + if ((mega_host_config *) shpnt->hostdata == + mega_hbas[i].hostdata_addr) { + /* Does this one has BIOS enabled */ + if (mega_hbas[i].hostdata_addr == boot_host) { + + /* Are we first */ + if (shtwo == NULL) /* Yes! */ + return; + else { /* :-( */ + shone = shpnt; + } + } else { + if (!shtwo) { + /* were we here before? xchng first */ + shtwo = shpnt; + } + } + break; + } + } + /* + * Have we got the boot host and one which does not have the bios + * enabled. + */ + if (shone && shtwo) + break; + } + if (shone && shtwo) { + mega_swap_hosts (shone, shtwo); + } + + return; } -static inline void mega_freeSgList(mega_host_config *megaCfg) +static void mega_swap_hosts (struct Scsi_Host *shone, struct Scsi_Host *shtwo) { - int i; + struct Scsi_Host *prevtoshtwo; + struct Scsi_Host *prevtoshone; + struct Scsi_Host *save = NULL;; + + /* Are these two nodes adjacent */ + if (shtwo->next == shone) { + + if (shtwo == scsi_hostlist && shone->next == NULL) { + + /* just two nodes */ + scsi_hostlist = shone; + shone->next = shtwo; + shtwo->next = NULL; + } else if (shtwo == scsi_hostlist) { + /* first two nodes of the list */ + + scsi_hostlist = shone; + shtwo->next = shone->next; + scsi_hostlist->next = shtwo; + } else if (shone->next == NULL) { + /* last two nodes of the list */ + + prevtoshtwo = scsi_hostlist; + + while (prevtoshtwo->next != shtwo) + prevtoshtwo = prevtoshtwo->next; + + prevtoshtwo->next = shone; + shone->next = shtwo; + shtwo->next = NULL; + } else { + prevtoshtwo = scsi_hostlist; + + while (prevtoshtwo->next != shtwo) + prevtoshtwo = prevtoshtwo->next; + + prevtoshtwo->next = shone; + shtwo->next = shone->next; + shone->next = shtwo; + } + + } else if (shtwo == scsi_hostlist && shone->next == NULL) { + /* shtwo at head, shone at tail, not adjacent */ + + prevtoshone = scsi_hostlist; + + while (prevtoshone->next != shone) + prevtoshone = prevtoshone->next; + + scsi_hostlist = shone; + shone->next = shtwo->next; + prevtoshone->next = shtwo; + shtwo->next = NULL; + } else if (shtwo == scsi_hostlist && shone->next != NULL) { + /* shtwo at head, shone is not at tail */ + + prevtoshone = scsi_hostlist; + while (prevtoshone->next != shone) + prevtoshone = prevtoshone->next; + + scsi_hostlist = shone; + prevtoshone->next = shtwo; + save = shtwo->next; + shtwo->next = shone->next; + shone->next = save; + } else if (shone->next == NULL) { + /* shtwo not at head, shone at tail */ + + prevtoshtwo = scsi_hostlist; + prevtoshone = scsi_hostlist; + + while (prevtoshtwo->next != shtwo) + prevtoshtwo = prevtoshtwo->next; + while (prevtoshone->next != shone) + prevtoshone = prevtoshone->next; + + prevtoshtwo->next = shone; + shone->next = shtwo->next; + prevtoshone->next = shtwo; + shtwo->next = NULL; + + } else { + prevtoshtwo = scsi_hostlist; + prevtoshone = scsi_hostlist; + save = NULL;; + + while (prevtoshtwo->next != shtwo) + prevtoshtwo = prevtoshtwo->next; + while (prevtoshone->next != shone) + prevtoshone = prevtoshone->next; + + prevtoshtwo->next = shone; + save = shone->next; + shone->next = shtwo->next; + prevtoshone->next = shtwo; + shtwo->next = save; + } + return; +} + +static inline void mega_freeSgList (mega_host_config * megaCfg) +{ + int i; - for (i = 0; i < megaCfg->max_cmds; i++) { - if (megaCfg->scbList[i].sgList) - kfree (megaCfg->scbList[i].sgList); /* free sgList */ - } + for (i = 0; i < megaCfg->max_cmds; i++) { + if (megaCfg->scbList[i].sgList) + pci_free_consistent (megaCfg->dev, + sizeof (mega_64sglist) * + MAX_SGLIST, + megaCfg->scbList[i].sgList, + megaCfg->scbList[i]. + dma_sghandle64); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x020400 */ + kfree (megaCfg->scbList[i].sgList); /* free sgList */ +#endif + } } /*---------------------------------------------- - * Get information about the card/driver + * Get information about the card/driver *----------------------------------------------*/ -const char * megaraid_info (struct Scsi_Host *pSHost) +static const char *megaraid_info (struct Scsi_Host *pSHost) { - static char buffer[512]; - mega_host_config *megaCfg; + static char buffer[512]; + mega_host_config *megaCfg; - megaCfg = (mega_host_config *) pSHost->hostdata; + megaCfg = (mega_host_config *) pSHost->hostdata; - sprintf (buffer, "AMI MegaRAID %s %d commands %d targs %d chans %d luns", - megaCfg->fwVer, - megaCfg->productInfo.MaxConcCmds, - megaCfg->host->max_id, - megaCfg->host->max_channel, - megaCfg->host->max_lun); - return buffer; + sprintf (buffer, + "AMI MegaRAID %s %d commands %d targs %d chans %d luns", + megaCfg->fwVer, megaCfg->productInfo.MaxConcCmds, + megaCfg->host->max_id, megaCfg->host->max_channel, + megaCfg->host->max_lun); + return buffer; } /*----------------------------------------------------------------- @@ -1690,107 +3040,115 @@ * 0E 01 reserved * 0F 01 mailbox busy * 10 01 numstatus byte - * 11 01 status byte + * 11 01 status byte *-----------------------------------------------------------------*/ -int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)) +static int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)) { - DRIVER_LOCK_T - mega_host_config *megaCfg; - mega_scb *pScb; - - megaCfg = (mega_host_config *) SCpnt->host->hostdata; - DRIVER_LOCK(megaCfg); - - if (!(megaCfg->flag & (1L << SCpnt->channel))) { - if (SCpnt->channel < SCpnt->host->max_channel) - printk (/*KERN_INFO*/ "scsi%d: scanning channel %c for devices.\n", - megaCfg->host->host_no, - SCpnt->channel + '1'); - else - printk(/*KERN_INFO*/ "scsi%d: scanning virtual channel for logical drives.\n", megaCfg->host->host_no); - - megaCfg->flag |= (1L << SCpnt->channel); - } - - SCpnt->scsi_done = pktComp; - - /* If driver in abort or reset.. cancel this command */ - if (megaCfg->flag & IN_ABORT) { - SCpnt->result = (DID_ABORT << 16); - /* Add Scsi_Command to end of completed queue */ - if( megaCfg->qCompletedH == NULL ) { - megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; - } - else { - megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt; - megaCfg->qCompletedT = SCpnt; - } - megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; - megaCfg->qCcnt++; - - DRIVER_UNLOCK(megaCfg); - return 0; - } - else if (megaCfg->flag & IN_RESET) { - SCpnt->result = (DID_RESET << 16); - /* Add Scsi_Command to end of completed queue */ - if( megaCfg->qCompletedH == NULL ) { - megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; - } - else { - megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt; - megaCfg->qCompletedT = SCpnt; - } - megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; - megaCfg->qCcnt++; - - DRIVER_UNLOCK(megaCfg); - return 0; - } - - megaCfg->flag |= IN_QUEUE; - /* Allocate and build a SCB request */ - if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) { - /*build SCpnt for IOCTL_CMD_NEW cmd in mega_ioctl()*/ - /* Add SCB to the head of the pending queue */ - /* Add SCB to the head of the pending queue */ - if( megaCfg->qPendingH == NULL ) { - megaCfg->qPendingH = megaCfg->qPendingT = pScb; - } - else { - megaCfg->qPendingT->next = pScb; - megaCfg->qPendingT = pScb; - } - megaCfg->qPendingT->next = NULL; - megaCfg->qPcnt++; - - mega_runpendq(megaCfg); - -#if LINUX_VERSION_CODE > 0x020024 - if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW ) - { /* user data from external user buffer */ - char *user_area; - u32 xfer_size; - - init_MUTEX_LOCKED(&pScb->sem); - down(&pScb->sem); - - user_area = *((char **)&pScb->SCpnt->cmnd[4]); - xfer_size = *((u32 *)&pScb->SCpnt->cmnd[8]); - - copy_to_user(user_area,pScb->kern_area,xfer_size); - - kfree(pScb->kern_area); - - mega_freeSCB(megaCfg, pScb); - } -#endif - } + DRIVER_LOCK_T mega_host_config * megaCfg; + mega_scb *pScb; + char *user_area = NULL; + + megaCfg = (mega_host_config *) SCpnt->host->hostdata; + DRIVER_LOCK (megaCfg); + + if (!(megaCfg->flag & (1L << SCpnt->channel))) { + if (SCpnt->channel < SCpnt->host->max_channel) + printk ( /*KERN_INFO */ + "scsi%d: scanning channel %c for devices.\n", + megaCfg->host->host_no, SCpnt->channel + '1'); + else + printk ( /*KERN_INFO */ + "scsi%d: scanning virtual channel for logical drives.\n", + megaCfg->host->host_no); + + megaCfg->flag |= (1L << SCpnt->channel); + } + + SCpnt->scsi_done = pktComp; - megaCfg->flag &= ~IN_QUEUE; - DRIVER_UNLOCK(megaCfg); + if (mega_driver_ioctl (megaCfg, SCpnt)) + return 0; + + /* If driver in abort or reset.. cancel this command */ + if (megaCfg->flag & IN_ABORT) { + SCpnt->result = (DID_ABORT << 16); + /* Add Scsi_Command to end of completed queue */ + if (megaCfg->qCompletedH == NULL) { + megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; + } else { + megaCfg->qCompletedT->host_scribble = + (unsigned char *) SCpnt; + megaCfg->qCompletedT = SCpnt; + } + megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; + megaCfg->qCcnt++; + + DRIVER_UNLOCK (megaCfg); + return 0; + } else if (megaCfg->flag & IN_RESET) { + SCpnt->result = (DID_RESET << 16); + /* Add Scsi_Command to end of completed queue */ + if (megaCfg->qCompletedH == NULL) { + megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; + } else { + megaCfg->qCompletedT->host_scribble = + (unsigned char *) SCpnt; + megaCfg->qCompletedT = SCpnt; + } + megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; + megaCfg->qCcnt++; + + DRIVER_UNLOCK (megaCfg); + return 0; + } - return 0; + megaCfg->flag |= IN_QUEUE; + /* Allocate and build a SCB request */ + if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) { + /*build SCpnt for M_RD_IOCTL_CMD_NEW cmd in mega_ioctl() */ + /* Add SCB to the head of the pending queue */ + /* Add SCB to the head of the pending queue */ + if (megaCfg->qPendingH == NULL) { + megaCfg->qPendingH = megaCfg->qPendingT = pScb; + } else { + megaCfg->qPendingT->next = pScb; + megaCfg->qPendingT = pScb; + } + megaCfg->qPendingT->next = NULL; + megaCfg->qPcnt++; + + if (mega_runpendq (megaCfg) == -1) { + DRIVER_UNLOCK (megaCfg); + return 0; + } + + if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { + init_MUTEX_LOCKED (&pScb->ioctl_sem); + spin_unlock_irq (&io_request_lock); + down (&pScb->ioctl_sem); + user_area = *((char **) &pScb->SCpnt->cmnd[4]); + if (copy_to_user + (user_area, pScb->buff_ptr, pScb->iDataSize)) { + printk + ("megaraid: Error copying ioctl return value to user buffer.\n"); + pScb->SCpnt->result = (DID_ERROR << 16); + } + spin_lock_irq (&io_request_lock); + DRIVER_LOCK (megaCfg); + kfree (pScb->buff_ptr); + pScb->buff_ptr = NULL; + mega_cmd_done (megaCfg, pScb, pScb->SCpnt->result); + mega_rundoneq (megaCfg); + mega_runpendq (megaCfg); + DRIVER_UNLOCK (megaCfg); + } + + megaCfg->flag &= ~IN_QUEUE; + + } + + DRIVER_UNLOCK (megaCfg); + return 0; } /*---------------------------------------------------------------------- @@ -1798,167 +3156,404 @@ *----------------------------------------------------------------------*/ volatile static int internal_done_flag = 0; volatile static int internal_done_errcode = 0; -static DECLARE_WAIT_QUEUE_HEAD(internal_wait); + +static DECLARE_WAIT_QUEUE_HEAD (internal_wait); static void internal_done (Scsi_Cmnd * SCpnt) { - internal_done_errcode = SCpnt->result; - internal_done_flag++; - wake_up(&internal_wait); + internal_done_errcode = SCpnt->result; + internal_done_flag++; + wake_up (&internal_wait); } /* shouldn't be used, but included for completeness */ -int megaraid_command (Scsi_Cmnd * SCpnt) +static int megaraid_command (Scsi_Cmnd * SCpnt) { - internal_done_flag = 0; + internal_done_flag = 0; - /* Queue command, and wait until it has completed */ - megaraid_queue (SCpnt, internal_done); + /* Queue command, and wait until it has completed */ + megaraid_queue (SCpnt, internal_done); - while (!internal_done_flag) { - interruptible_sleep_on(&internal_wait); - } + while (!internal_done_flag) { + interruptible_sleep_on (&internal_wait); + } - return internal_done_errcode; + return internal_done_errcode; } /*--------------------------------------------------------------------- * Abort a previous SCSI request *---------------------------------------------------------------------*/ -int -megaraid_abort (Scsi_Cmnd * SCpnt) +static int megaraid_abort (Scsi_Cmnd * SCpnt) { - mega_host_config *megaCfg; - int rc; //, idx; - mega_scb *pScb; + mega_host_config *megaCfg; + int rc; /*, idx; */ + mega_scb *pScb; - rc = SCSI_ABORT_NOT_RUNNING; + rc = SCSI_ABORT_NOT_RUNNING; - megaCfg = (mega_host_config *) SCpnt->host->hostdata; + megaCfg = (mega_host_config *) SCpnt->host->hostdata; - megaCfg->flag |= IN_ABORT; + megaCfg->flag |= IN_ABORT; - for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) { - if (pScb->SCpnt == SCpnt) { - /* Found an aborting command */ + for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) { + if (pScb->SCpnt == SCpnt) { + /* Found an aborting command */ #if DEBUG - showMbox(pScb); + showMbox (pScb); #endif -/* - * If the command is queued to be issued to the firmware, abort the scsi cmd, - * If the command is already aborted in a previous call to the _abort entry - * point, return SCSI_ABORT_SNOOZE, suggesting a reset. - * If the command is issued to the firmware, which might complete after - * some time, we will mark the scb as aborted, and return to the mid layer, - * that abort could not be done. - * In the ISR, when this command actually completes, we will perform a normal - * completion. - * - * Oct 27, 1999 - */ - - switch(pScb->state) { - case SCB_ABORTED: /* Already aborted */ - rc = SCSI_ABORT_SNOOZE; - break; - case SCB_ISSUED: /* Waiting on ISR result */ - rc = SCSI_ABORT_NOT_RUNNING; - pScb->state = SCB_ABORTED; - break; - case SCB_ACTIVE: /* still on the pending queue */ - mega_freeSCB (megaCfg, pScb); - SCpnt->result = (DID_ABORT << 16) ; - if( megaCfg->qCompletedH == NULL ) { - megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt; - } - else { - megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt; - megaCfg->qCompletedT = SCpnt; - } - megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; - megaCfg->qCcnt++; - rc = SCSI_ABORT_SUCCESS; - break; - default: - printk("megaraid_abort: unknown command state!!\n"); - rc = SCSI_ABORT_NOT_RUNNING; - break; - } - break; - } - } + /* + * If the command is queued to be issued to the firmware, abort the scsi cmd, + * If the command is already aborted in a previous call to the _abort entry + * point, return SCSI_ABORT_SNOOZE, suggesting a reset. + * If the command is issued to the firmware, which might complete after + * some time, we will mark the scb as aborted, and return to the mid layer, + * that abort could not be done. + * In the ISR, when this command actually completes, we will perform a normal + * completion. + * + * Oct 27, 1999 + */ + + switch (pScb->state) { + case SCB_ABORTED: /* Already aborted */ + rc = SCSI_ABORT_SNOOZE; + break; + case SCB_ISSUED: /* Waiting on ISR result */ + rc = SCSI_ABORT_NOT_RUNNING; + pScb->state = SCB_ABORTED; + break; + case SCB_ACTIVE: /* still on the pending queue */ + mega_freeSCB (megaCfg, pScb); + SCpnt->result = (DID_ABORT << 16); + if (megaCfg->qCompletedH == NULL) { + megaCfg->qCompletedH = + megaCfg->qCompletedT = SCpnt; + } else { + megaCfg->qCompletedT->host_scribble = + (unsigned char *) SCpnt; + megaCfg->qCompletedT = SCpnt; + } + megaCfg->qCompletedT->host_scribble = + (unsigned char *) NULL; + megaCfg->qCcnt++; + rc = SCSI_ABORT_SUCCESS; + break; + default: + printk + ("megaraid_abort: unknown command state!!\n"); + rc = SCSI_ABORT_NOT_RUNNING; + break; + } + break; + } + } - megaCfg->flag &= ~IN_ABORT; + megaCfg->flag &= ~IN_ABORT; #if DEBUG -if(megaCfg->flag & IN_QUEUE) printk("ma:flag is in queue\n"); -if(megaCfg->qCompletedH == NULL) printk("ma:qchead == null\n"); + if (megaCfg->flag & IN_QUEUE) + printk ("ma:flag is in queue\n"); + if (megaCfg->qCompletedH == NULL) + printk ("ma:qchead == null\n"); #endif - -/* - * This is required here to complete any completed requests to be communicated - * over to the mid layer. - * Calling just mega_rundoneq() did not work. - */ -if(megaCfg->qCompletedH) { - SCpnt = megaCfg->qCompletedH; - megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble; - megaCfg->qCcnt--; - - SCpnt->host_scribble = (unsigned char *) NULL ; - /* Callback */ - callDone (SCpnt); -} - mega_rundoneq(megaCfg); - return rc; + /* + * This is required here to complete any completed requests to be communicated + * over to the mid layer. + * Calling just mega_rundoneq() did not work. + */ + if (megaCfg->qCompletedH) { + SCpnt = megaCfg->qCompletedH; + megaCfg->qCompletedH = (Scsi_Cmnd *) SCpnt->host_scribble; + megaCfg->qCcnt--; + + SCpnt->host_scribble = (unsigned char *) NULL; + /* Callback */ + callDone (SCpnt); + } + mega_rundoneq (megaCfg); + + return rc; } /*--------------------------------------------------------------------- * Reset a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags) + +static int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags) +{ + mega_host_config *megaCfg; + int idx; + int rc; + mega_scb *pScb; + + rc = SCSI_RESET_NOT_RUNNING; + megaCfg = (mega_host_config *) SCpnt->host->hostdata; + + megaCfg->flag |= IN_RESET; + + printk + ("megaraid_RESET: %.08lx cmd=%.02x , flag = %x\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, + SCpnt->target, SCpnt->lun, rstflags); + + TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, + SCpnt->target, SCpnt->lun)); + + /* + * Walk list of SCBs for any that are still outstanding + */ + for (idx = 0; idx < megaCfg->max_cmds; idx++) { + if (megaCfg->scbList[idx].state != SCB_FREE) { + SCpnt = megaCfg->scbList[idx].SCpnt; + pScb = &megaCfg->scbList[idx]; + if (SCpnt != NULL) { + pScb->state = SCB_RESET; + break; + } + } + } + + megaCfg->flag &= ~IN_RESET; + + mega_rundoneq (megaCfg); + return rc; +} + +#ifdef CONFIG_PROC_FS +/* Following code handles /proc fs */ +static int proc_printf (mega_host_config * megaCfg, const char *fmt, ...) +{ + va_list args; + int i; + + if (megaCfg->procidx > PROCBUFSIZE) + return 0; + + va_start (args, fmt); + i = vsprintf ((megaCfg->procbuf + megaCfg->procidx), fmt, args); + va_end (args); + + megaCfg->procidx += i; + return i; +} + +static int proc_read_config (char *page, char **start, off_t offset, + int count, int *eof, void *data) { - mega_host_config *megaCfg; - int idx; - int rc; - mega_scb *pScb; - - rc = SCSI_RESET_NOT_RUNNING; - megaCfg = (mega_host_config *) SCpnt->host->hostdata; - - megaCfg->flag |= IN_RESET; - - printk ("megaraid_RESET: %.08lx cmd=%.02x , flag = %x\n", - SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, - SCpnt->lun, rstflags); - - TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n", - SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, - SCpnt->lun)); - - /* - * Walk list of SCBs for any that are still outstanding - */ - for (idx = 0; idx < megaCfg->max_cmds; idx++) { - if (megaCfg->scbList[idx].state != SCB_FREE) { - SCpnt = megaCfg->scbList[idx].SCpnt; - pScb = &megaCfg->scbList[idx]; - if (SCpnt != NULL) { - pScb->state = SCB_RESET; - break; - } - } - } - megaCfg->flag &= ~IN_RESET; + mega_host_config *megaCfg = (mega_host_config *) data; + + *start = page; + + if (megaCfg->productInfo.ProductName[0] != 0) + proc_printf (megaCfg, "%s\n", megaCfg->productInfo.ProductName); + + proc_printf (megaCfg, "Controller Type: "); - mega_rundoneq(megaCfg); - return rc; + if (megaCfg->flag & BOARD_QUARTZ) + proc_printf (megaCfg, "438/466/467/471/493\n"); + else + proc_printf (megaCfg, "418/428/434\n"); + + if (megaCfg->flag & BOARD_40LD) + proc_printf (megaCfg, + "Controller Supports 40 Logical Drives\n"); + + if (megaCfg->flag & BOARD_64BIT) + proc_printf (megaCfg, + "Controller / Driver uses 64 bit memory addressing\n"); + + proc_printf (megaCfg, "Base = %08x, Irq = %d, ", megaCfg->base, + megaCfg->host->irq); + + proc_printf (megaCfg, "Logical Drives = %d, Channels = %d\n", + megaCfg->numldrv, megaCfg->productInfo.SCSIChanPresent); + + proc_printf (megaCfg, "Version =%s:%s, DRAM = %dMb\n", + megaCfg->fwVer, megaCfg->biosVer, + megaCfg->productInfo.DramSize); + + proc_printf (megaCfg, + "Controller Queue Depth = %d, Driver Queue Depth = %d\n", + megaCfg->productInfo.MaxConcCmds, megaCfg->max_cmds); + COPY_BACK; + return count; } +static int proc_read_stat (char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + int i; + mega_host_config *megaCfg = (mega_host_config *) data; + + *start = page; + + proc_printf (megaCfg, "Statistical Information for this controller\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020100 */ + proc_printf (megaCfg, "Interrupts Collected = %Lu\n", + megaCfg->nInterrupts); +#else + proc_printf (megaCfg, "Interrupts Collected = %u\n", + (u32) megaCfg->nInterrupts); +#endif + + for (i = 0; i < megaCfg->numldrv; i++) { + proc_printf (megaCfg, "Logical Drive %d:\n", i); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + proc_printf (megaCfg, + "\tReads Issued = %Lu, Writes Issued = %Lu\n", + megaCfg->nReads[i], megaCfg->nWrites[i]); + + proc_printf (megaCfg, + "\tSectors Read = %Lu, Sectors Written = %Lu\n\n", + megaCfg->nReadBlocks[i], megaCfg->nWriteBlocks[i]); +#else + proc_printf (megaCfg, + "\tReads Issued = %10u, Writes Issued = %10u\n", + (u32) megaCfg->nReads[i], + (u32) megaCfg->nWrites[i]); + + proc_printf (megaCfg, + "\tSectors Read = %10u, Sectors Written = %10u\n\n", + (u32) megaCfg->nReadBlocks[i], + (u32) megaCfg->nWriteBlocks[i]); +#endif + + } + + COPY_BACK; + return count; +} + +static int proc_read_status (char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + mega_host_config *megaCfg = (mega_host_config *) data; + *start = page; + + proc_printf (megaCfg, "TBD\n"); + COPY_BACK; + return count; +} + +static int proc_read_mbox (char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + + mega_host_config *megaCfg = (mega_host_config *) data; + volatile mega_mailbox *mbox = megaCfg->mbox; + + *start = page; + + proc_printf (megaCfg, "Contents of Mail Box Structure\n"); + proc_printf (megaCfg, " Fw Command = 0x%02x\n", mbox->cmd); + proc_printf (megaCfg, " Cmd Sequence = 0x%02x\n", mbox->cmdid); + proc_printf (megaCfg, " No of Sectors= %04d\n", mbox->numsectors); + proc_printf (megaCfg, " LBA = 0x%02x\n", mbox->lba); + proc_printf (megaCfg, " DTA = 0x%08x\n", mbox->xferaddr); + proc_printf (megaCfg, " Logical Drive= 0x%02x\n", mbox->logdrv); + proc_printf (megaCfg, " No of SG Elmt= 0x%02x\n", mbox->numsgelements); + proc_printf (megaCfg, " Busy = %01x\n", mbox->busy); + proc_printf (megaCfg, " Status = 0x%02x\n", mbox->status); + + /* proc_printf(megaCfg, "Dump of MailBox\n"); + for (i = 0; i < 16; i++) + proc_printf(megaCfg, "%02x ",*(mbox + i)); + + proc_printf(megaCfg, "\n\nNumber of Status = %02d\n",mbox->numstatus); + + for (i = 0; i < 46; i++) { + proc_printf(megaCfg,"%02d ",*(mbox + 16 + i)); + if (i%16) + proc_printf(megaCfg,"\n"); + } + + if (!mbox->numsgelements) { + dta = phys_to_virt(mbox->xferaddr); + for (i = 0; i < mbox->numsgelements; i++) + if (dta) { + proc_printf(megaCfg,"Addr = %08x\n", (ulong)*(dta + i)); proc_printf(megaCfg,"Length = %08x\n", + (ulong)*(dta + i + 4)); + } + }*/ + COPY_BACK; + return count; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */ +#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string, \ + S_IRUSR | S_IFREG,\ + controller_proc_dir_entry,\ + fxn, megaCfg) +#else +#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,S_IRUSR | S_IFREG, controller_proc_dir_entry, fxn, megaCfg) + +static struct proc_dir_entry * +create_proc_read_entry (const char *string, + int mode, + struct proc_dir_entry *parent, + read_proc_t * fxn, mega_host_config * megaCfg) +{ + struct proc_dir_entry *temp = NULL; + + temp = kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL); + if (!temp) + return NULL; + memset (temp, 0, sizeof (struct proc_dir_entry)); + + if ((temp->name = kmalloc (strlen (string) + 1, GFP_KERNEL)) == NULL) { + kfree (temp); + return NULL; + } + + strcpy ((char *) temp->name, string); + temp->namelen = strlen (string); + temp->mode = mode; /*S_IFREG | S_IRUSR */ ; + temp->data = (void *) megaCfg; + temp->read_proc = fxn; + proc_register (parent, temp); + return temp; +} +#endif + +static void mega_create_proc_entry (int index, struct proc_dir_entry *parent) +{ + u_char string[64] = { 0 }; + mega_host_config *megaCfg = megaCtlrs[index]; + struct proc_dir_entry *controller_proc_dir_entry = NULL; + + sprintf (string, "%d", index); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */ + controller_proc_dir_entry = + megaCfg->controller_proc_dir_entry = proc_mkdir (string, parent); +#else + controller_proc_dir_entry = + megaCfg->controller_proc_dir_entry = + create_proc_entry (string, S_IFDIR | S_IRUGO | S_IXUGO, parent); +#endif + + if (!controller_proc_dir_entry) + printk ("\nmegaraid: proc_mkdir failed\n"); + else { + megaCfg->proc_read = + CREATE_READ_PROC ("config", proc_read_config); + megaCfg->proc_status = + CREATE_READ_PROC ("status", proc_read_status); + megaCfg->proc_stat = CREATE_READ_PROC ("stat", proc_read_stat); + megaCfg->proc_mbox = + CREATE_READ_PROC ("mailbox", proc_read_mbox); + } + +} +#endif /* CONFIG_PROC_FS */ + /*------------------------------------------------------------- * Return the disk geometry for a particular disk * Input: @@ -1969,51 +3564,749 @@ * geom[1] = sectors * geom[2] = cylinders *-------------------------------------------------------------*/ -int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) +static int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) +{ + int heads, sectors, cylinders; + mega_host_config *megaCfg; + + /* Get pointer to host config structure */ + megaCfg = (mega_host_config *) disk->device->host->hostdata; + + /* Default heads (64) & sectors (32) */ + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + + /* Handle extended translation size for logical drives > 1Gb */ + if (disk->capacity >= 0x200000) { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + + /* return result */ + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return 0; +} + +/* + * This routine will be called when the use has done a forced shutdown on the + * system. Flush the Adapter cache, that's the most we can do. + */ +static int megaraid_reboot_notify (struct notifier_block *this, unsigned long code, + void *unused) +{ + struct Scsi_Host *pSHost; + mega_host_config *megaCfg; + mega_mailbox *mbox; + u_char mboxData[16]; + int i; + + if (code == SYS_DOWN || code == SYS_HALT) { + for (i = 0; i < numCtlrs; i++) { + pSHost = megaCtlrs[i]->host; + + megaCfg = (mega_host_config *) pSHost->hostdata; + mbox = (mega_mailbox *) mboxData; + + /* Flush cache to disk */ + memset (mbox, 0, 16); + mboxData[0] = 0xA; + + /* + * Free irq, otherwise extra interrupt is generated + */ + free_irq (megaCfg->host->irq, megaCfg); + + /* + * Issue a blocking (interrupts disabled) command to + * the card + */ + megaIssueCmd (megaCfg, mboxData, NULL, 0); + } + } + return NOTIFY_DONE; +} + +static int mega_init_scb (mega_host_config * megacfg) +{ + int idx; + +#if DEBUG + if (megacfg->max_cmds >= MAX_COMMANDS) { + printk ("megaraid:ctlr max cmds = %x : MAX_CMDS = %x", + megacfg->max_cmds, MAX_COMMANDS); + } +#endif + + for (idx = megacfg->max_cmds - 1; idx >= 0; idx--) { + + megacfg->scbList[idx].idx = idx; + + /* + * ISR will make this flag zero to indicate the command has been + * completed. This is only for user ioctl calls. Rest of the driver + * and the mid-layer operations are not connected with this flag. + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + megacfg->scbList[idx].sgList = + pci_alloc_consistent (megacfg->dev, + sizeof (mega_64sglist) * MAX_SGLIST, + &(megacfg->scbList[idx]. + dma_sghandle64)); + + megacfg->scbList[idx].sg64List = + (mega_64sglist *) megacfg->scbList[idx].sgList; +#else + megacfg->scbList[idx].sgList = kmalloc (sizeof (mega_sglist) * MAX_SGLIST, GFP_ATOMIC | GFP_DMA); +#endif + + if (megacfg->scbList[idx].sgList == NULL) { + printk (KERN_WARNING + "Can't allocate sglist for id %d\n", idx); + mega_freeSgList (megacfg); + return -1; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + megacfg->scbList[idx].pthru = pci_alloc_consistent (megacfg->dev, + sizeof (mega_passthru), + &(megacfg->scbList[idx]. + dma_passthruhandle64)); + + if (megacfg->scbList[idx].pthru == NULL) { + printk (KERN_WARNING + "Can't allocate passthru for id %d\n", idx); + } + /* + * Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA + */ + megacfg->scbList[idx].bounce_buffer = pci_alloc_consistent (megacfg->dev, + 256, + &(megacfg->scbList[idx]. + dma_bounce_buffer)); + + if (!megacfg->scbList[idx].bounce_buffer) + printk + ("megaraid: allocation for bounce buffer failed\n"); + + megacfg->scbList[idx].dma_type = M_RD_DMA_TYPE_NONE; +#endif + + if (idx < MAX_COMMANDS) { + /* + * Link to free list + * lock not required since we are loading the driver, so no + * commands possible right now. + */ + enq_scb_freelist (megacfg, &megacfg->scbList[idx], + NO_LOCK, INTR_ENB); + + } + } + + return 0; +} + +/* + * Enqueues a SCB + */ +static void enq_scb_freelist (mega_host_config * megacfg, mega_scb * scb, int lock, + int intr) +{ + + if (lock == INTERNAL_LOCK || intr == INTR_DIS) { + if (intr == INTR_DIS) + spin_lock_irq (&megacfg->lock_free); + else + spin_lock (&megacfg->lock_free); + } + + scb->state = SCB_FREE; + scb->SCpnt = NULL; + + if (megacfg->qFreeH == (mega_scb *) NULL) { + megacfg->qFreeH = megacfg->qFreeT = scb; + } else { + megacfg->qFreeT->next = scb; + megacfg->qFreeT = scb; + } + + megacfg->qFreeT->next = NULL; + megacfg->qFcnt++; + + if (lock == INTERNAL_LOCK || intr == INTR_DIS) { + if (intr == INTR_DIS) + spin_unlock_irq (&megacfg->lock_free); + else + spin_unlock (&megacfg->lock_free); + } +} + +/* + * Routines for the character/ioctl interface to the driver + */ +static int megadev_open (struct inode *inode, struct file *filep) +{ + MOD_INC_USE_COUNT; + return 0; /* success */ +} + +static int megadev_ioctl_entry (struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg) +{ + int ret = -1; + + /* + * We do not allow parallel ioctls to the driver as of now. + */ + down (&mimd_entry_mtx); + ret = megadev_ioctl (inode, filep, cmd, arg); + up (&mimd_entry_mtx); + + return ret; + +} + +static int megadev_ioctl (struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg) { - int heads, sectors, cylinders; - mega_host_config *megaCfg; + int adapno; + kdev_t dev; + u32 inlen; + struct uioctl_t ioc; + char *kphysaddr = NULL; + int nadap = numCtlrs; + int npages; + u8 opcode; + int order = 0; + u32 outlen; + int ret; + u8 subopcode; + Scsi_Cmnd *scsicmd; + struct Scsi_Host *shpnt; + char *uaddr; + struct uioctl_t *uioc; + IO_LOCK_T; + + if (!inode || !(dev = inode->i_rdev)) + return -EINVAL; + + if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC) + return (-EINVAL); + + /* + * We do not transfer more than IOCTL_MAX_DATALEN (see megaraid.h) with + * this interface.If the user needs to transfer more than this,he should + * use 0x81 command op-code. + */ + + /* + * Get the user ioctl structure + */ + ret = verify_area (VERIFY_WRITE, (char *) arg, sizeof (struct uioctl_t)); + + if (ret) + return ret; + + if(copy_from_user (&ioc, (char *) arg, sizeof (struct uioctl_t))) + return -EFAULT; + + /* + * The first call the applications should make is to find out the number + * of controllers in the system. The next logical call should be for + * getting the list of controllers in the system as detected by the + * driver. + */ + + /* + * Get the opcode and subopcode for the commands + */ + opcode = ioc.ui.fcs.opcode; + subopcode = ioc.ui.fcs.subopcode; + + switch (opcode) { + case M_RD_DRIVER_IOCTL_INTERFACE: + switch (subopcode) { + case MEGAIOC_QDRVRVER: /* Query driver version */ + put_user (driver_ver, (u32 *) ioc.data); + return 0; + + case MEGAIOC_QNADAP: /* Get # of adapters */ + put_user (nadap, (int *) ioc.data); + return nadap; + + case MEGAIOC_QADAPINFO: /* Get adapter information */ + /* + * which adapter? + */ + adapno = ioc.ui.fcs.adapno; + + /* + * The adapter numbers do not start with 0, at least in + * the user space. This is just to make sure, 0 is not the + * default value which will refer to adapter 1. So the + * user needs to make use of macros MKADAP() and GETADAP() + * (See megaraid.h) while making ioctl() call. + */ + adapno = GETADAP (adapno); + + if (adapno >= numCtlrs) + return (-ENODEV); + + ret = verify_area (VERIFY_WRITE, + ioc.data, + sizeof (struct mcontroller)); + if (ret) + return ret; + + /* + * Copy struct mcontroller to user area + */ + copy_to_user (ioc.data, + mcontroller + adapno, + sizeof (struct mcontroller)); + return 0; + + default: + return (-EINVAL); + + } /* inner switch */ + break; + + case M_RD_IOCTL_CMD_NEW: + /* which adapter? */ + adapno = ioc.ui.fcs.adapno; + + /* See comment above: MEGAIOC_QADAPINFO */ + adapno = GETADAP (adapno); + + if (adapno >= numCtlrs) + return (-ENODEV); + + /* Check for zero length buffer. */ + if (!ioc.ui.fcs.length) + return -EINVAL; - /* Get pointer to host config structure */ - megaCfg = (mega_host_config *) disk->device->host->hostdata; + /* save the user address */ + uaddr = ioc.ui.fcs.buffer; - /* Default heads (64) & sectors (32) */ - heads = 64; - sectors = 32; - cylinders = disk->capacity / (heads * sectors); - - /* Handle extended translation size for logical drives > 1Gb */ - if (disk->capacity >= 0x200000) { - heads = 255; - sectors = 63; - cylinders = disk->capacity / (heads * sectors); - } - - /* return result */ - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return 0; -} - -static int __init megaraid_setup(char *str) -{ - skip_id = -1; - if (str && !strncmp(str, "skip", strlen("skip"))) { - if (str[4] != '\0') { - skip_id = str[4] - '0'; - if (str[5] != '\0') { - skip_id = (skip_id * 10) + (str[5] - '0'); - } - } - skip_id = (skip_id > 15) ? -1 : skip_id; - } - return 1; +/* +* For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of uioctl_t +* structure are treated as flags. If outlen is 1, the data is +* transferred from the device and if inlen is 1, the data is +* transferred to the device. +*/ + outlen = ioc.outlen; + inlen = ioc.inlen; +#if 0 + if (inlen && outlen) + return -EINVAL; +#endif + if (outlen) { + ret = verify_area (VERIFY_WRITE, + (char *) ioc.ui.fcs.buffer, + ioc.ui.fcs.length); + if (ret) + return ret; + } else if (inlen) { + ret = verify_area (VERIFY_READ, + (char *) ioc.ui.fcs.buffer, + ioc.ui.fcs.length); + + if (ret) + return ret; + } + + /* How many pages required of size PAGE_SIZE */ + npages = ioc.ui.fcs.length / PAGE_SIZE; + /* Do we need one more? */ + + if (ioc.ui.fcs.length % PAGE_SIZE) + npages++; + + /* ioctl does not support data xfer > 32KB */ + if (npages == 1) + order = 0; + else if (npages == 2) + order = 1; + else if (npages <= 4) + order = 2; + else if (npages <= 8) + order = 3; + else + return -EINVAL; + + if (outlen || inlen) { + /* + * Allocate kernel space for npages. + * + * Since we need the memory for DMA, it needs to be physically + * contiguous. __get_free_pags() return consecutive free pages + * in kernel space. + * Note: We don't do __get_dma_pages(), since for PCI devices, + * the DMA memory is not restriceted to 16M, which is ensured + * by __get_dma_pages() + */ + + if ((kphysaddr = (char *) __get_free_pages (GFP_KERNEL, + order)) == + 0) { + printk (KERN_INFO + "megaraid:allocation failed\n"); + return -ENOMEM; + } + + memset (kphysaddr, 0, npages * PAGE_SIZE); + ioc.ui.fcs.buffer = kphysaddr; + + if (inlen) { + /* copyin the user data */ + copy_from_user (kphysaddr, + (char *) uaddr, + ioc.ui.fcs.length); + } + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd), + GFP_KERNEL | GFP_DMA); + memset (scsicmd, 0, sizeof (Scsi_Cmnd)); +#else + scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), + GFP_ATOMIC | GFP_DMA); +#endif + if (!scsicmd) { + if (kphysaddr) + free_pages ((unsigned long) kphysaddr, order); + return -ENOMEM; + } + + scsicmd->host = NULL; + + /* + * Find this host + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostdata == + (unsigned long *) megaCtlrs[adapno]) + scsicmd->host = shpnt; + } + + if (scsicmd->host == NULL) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + kfree (scsicmd); +#else + scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd)); +#endif + if (kphysaddr) + free_pages ((unsigned long) kphysaddr, order); + return -ENODEV; + } + + scsicmd->cmnd[0] = MEGADEVIOC; + scsicmd->request_buffer = (void *) &ioc; + + init_MUTEX_LOCKED (&mimd_ioctl_sem); + + IO_LOCK; + megaraid_queue (scsicmd, megadev_ioctl_done); + + IO_UNLOCK; + + down (&mimd_ioctl_sem); + + if (!scsicmd->result && outlen) { + copy_to_user (uaddr, kphysaddr, ioc.ui.fcs.length); + } + + /* + * copyout the result + */ + uioc = (struct uioctl_t *) arg; + + if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { + put_user (scsicmd->result, &uioc->pthru.scsistatus); + } else { + put_user (1, &uioc->mbox[16]); /* numstatus */ + /* status */ + put_user (scsicmd->result, &uioc->mbox[17]); + } + + if (kphysaddr) { + free_pages ((ulong) kphysaddr, order); + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ + kfree (scsicmd); +#else + scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd)); +#endif + + return ret; + + case M_RD_IOCTL_CMD: + /* which adapter? */ + adapno = ioc.ui.fcs.adapno; + /* See comment above: MEGAIOC_QADAPINFO */ + adapno = GETADAP (adapno); + + if (adapno >= numCtlrs) + return (-ENODEV); + + /* save the user address */ + uaddr = ioc.data; + outlen = ioc.outlen; + inlen = ioc.inlen; + + if ((outlen >= IOCTL_MAX_DATALEN) + || (inlen >= IOCTL_MAX_DATALEN)) + return (-EINVAL); + + if (outlen) { + ret = verify_area (VERIFY_WRITE, ioc.data, outlen); + if (ret) + return ret; + } else if (inlen) { + ret = verify_area (VERIFY_READ, ioc.data, inlen); + + if (ret) + return ret; + } + + if (outlen || inlen) { + /* + * Allocate a page of kernel space. + */ + if ((kphysaddr = + (char *) __get_free_pages (GFP_KERNEL, 0)) == 0) { + + printk (KERN_INFO + "megaraid:allocation failed\n"); + return -ENOMEM; + } + + memset (kphysaddr, 0, PAGE_SIZE); + ioc.data = kphysaddr; + + if (inlen) { + if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { + /* copyin the user data */ + copy_from_user (kphysaddr, + uaddr, + ioc.pthru.dataxferlen); + } else { + copy_from_user (kphysaddr, + uaddr, inlen); + } + } + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ + scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd), + GFP_KERNEL | GFP_DMA); + memset (scsicmd, 0, sizeof (Scsi_Cmnd)); +#else + scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), + GFP_ATOMIC | GFP_DMA); +#endif + + if (!scsicmd) { + if (kphysaddr) + free_pages ((unsigned long) kphysaddr, 0); + return -ENOMEM; + } + + scsicmd->host = NULL; + + /* + * Find this host in the hostlist + */ + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + if (shpnt->hostdata == + (unsigned long *) megaCtlrs[adapno]) + scsicmd->host = shpnt; + } + + if (scsicmd->host == NULL) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + kfree (scsicmd); +#else + scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd)); +#endif + if (kphysaddr) + free_pages ((unsigned long) kphysaddr, 0); + + return -ENODEV; + } + + scsicmd->cmnd[0] = MEGADEVIOC; + scsicmd->request_buffer = (void *) &ioc; + + init_MUTEX_LOCKED (&mimd_ioctl_sem); + + IO_LOCK; + megaraid_queue (scsicmd, megadev_ioctl_done); + + IO_UNLOCK; + down (&mimd_ioctl_sem); + + if (!scsicmd->result && outlen) { + if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { + copy_to_user (uaddr, + kphysaddr, ioc.pthru.dataxferlen); + } else { + copy_to_user (uaddr, kphysaddr, outlen); + } + } + + /* + * copyout the result + */ + uioc = (struct uioctl_t *) arg; + + if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) { + put_user (scsicmd->result, &uioc->pthru.scsistatus); + } else { + put_user (1, &uioc->mbox[16]); /* numstatus */ + /* status */ + put_user (scsicmd->result, &uioc->mbox[17]); + } + + if (kphysaddr) + free_pages ((unsigned long) kphysaddr, 0); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + kfree (scsicmd); +#else + scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd)); +#endif + return ret; + + default: + return (-EINVAL); + + } /* Outer switch */ + + return 0; } -__setup("megaraid=", megaraid_setup); +static void +megadev_ioctl_done (Scsi_Cmnd * sc) +{ + up (&mimd_ioctl_sem); +} + +static mega_scb * +megadev_doioctl (mega_host_config * megacfg, Scsi_Cmnd * sc) +{ + u8 cmd; + struct uioctl_t *ioc = NULL; + mega_mailbox *mbox = NULL; + mega_ioctl_mbox *mboxioc = NULL; + struct mbox_passthru *mboxpthru = NULL; + mega_scb *scb = NULL; + mega_passthru *pthru = NULL; + + if ((scb = mega_allocateSCB (megacfg, sc)) == NULL) { + sc->result = (DID_ERROR << 16); + callDone (sc); + return NULL; + } + + ioc = (struct uioctl_t *) sc->request_buffer; + + memcpy (scb->mboxData, ioc->mbox, sizeof (scb->mboxData)); + + /* The generic mailbox */ + mbox = (mega_mailbox *) ioc->mbox; + + /* + * Get the user command + */ + cmd = ioc->mbox[0]; + + switch (cmd) { + case MEGA_MBOXCMD_PASSTHRU: + /* + * prepare the SCB with information from the user ioctl structure + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pthru = scb->pthru; +#else + pthru = &scb->pthru; +#endif + memcpy (pthru, &ioc->pthru, sizeof (mega_passthru)); + mboxpthru = (struct mbox_passthru *) scb->mboxData; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + if (megacfg->flag & BOARD_64BIT) { + /* This is just a sample with one element + * This if executes onlu on 2.4 kernels + */ + mboxpthru->dataxferaddr = scb->dma_passthruhandle64; + scb->sg64List[0].address = + pci_map_single (megacfg->dev, + ioc->data, + 4096, PCI_DMA_BIDIRECTIONAL); + scb->sg64List[0].length = 4096; // TODO: Check this + pthru->dataxferaddr = scb->dma_sghandle64; + pthru->numsgelements = 1; + mboxpthru->cmd = 0xC3; + } else { + mboxpthru->dataxferaddr = scb->dma_passthruhandle64; + pthru->dataxferaddr = + pci_map_single (megacfg->dev, + ioc->data, + 4096, PCI_DMA_BIDIRECTIONAL); + pthru->numsgelements = 0; + } + +#else + { + mboxpthru->dataxferaddr = virt_to_bus (&scb->pthru); + pthru->dataxferaddr = virt_to_bus (ioc->data); + pthru->numsgelements = 0; + } +#endif + + pthru->reqsenselen = 14; + break; + default: /* Normal command */ + mboxioc = (mega_ioctl_mbox *) scb->mboxData; + + if (ioc->ui.fcs.opcode == M_RD_IOCTL_CMD_NEW) { + scb->buff_ptr = ioc->ui.fcs.buffer; + scb->iDataSize = ioc->ui.fcs.length; + } else { + scb->buff_ptr = ioc->data; + scb->iDataSize = 4096; // TODO:check it + } + + set_mbox_xfer_addr (megacfg, scb, mboxioc, FROMTO_DEVICE); + mboxioc->numsgelements = 0; + break; + } + + return scb; +} + +static int +megadev_close (struct inode *inode, struct file *filep) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static Scsi_Host_Template driver_template = MEGARAID; +#include "scsi_module.c" +#else +#ifdef MODULE +Scsi_Host_Template driver_template = MEGARAID; #include "scsi_module.c" +#endif /* MODULE */ +#endif /* LINUX VERSION 2.4.XX test */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h --- v2.4.2/linux/drivers/scsi/megaraid.h Mon Dec 11 13:19:40 2000 +++ linux/drivers/scsi/megaraid.h Tue Mar 6 19:44:37 2001 @@ -5,14 +5,15 @@ #include #endif -#define IN_ISR 0x80000000L -#define IN_ABORT 0x40000000L -#define IN_RESET 0x20000000L -#define IN_QUEUE 0x10000000L -#define BOARD_QUARTZ 0x08000000L -#define BOARD_40LD 0x04000000L +#define IN_ISR 0x80000000L +#define IN_ABORT 0x40000000L +#define IN_RESET 0x20000000L +#define IN_QUEUE 0x10000000L + +#define BOARD_QUARTZ 0x08000000L +#define BOARD_40LD 0x04000000L +#define BOARD_64BIT 0x02000000L -#ifndef HOSTS_C #define SCB_FREE 0x0 #define SCB_ACTIVE 0x1 #define SCB_WAITQ 0x2 @@ -20,619 +21,862 @@ #define SCB_COMPLETE 0x4 #define SCB_ABORTED 0x5 #define SCB_RESET 0x6 -#endif -#define MEGA_CMD_TIMEOUT 10 +#define M_RD_CRLFSTR "\n" +#define M_RD_IOCTL_CMD 0x80 +#define M_RD_IOCTL_CMD_NEW 0x81 +#define M_RD_DRIVER_IOCTL_INTERFACE 0x82 + +#define MEGARAID_VERSION "v1.14g (Release Date: Feb 5, 2001; 11:42)" +#define MEGARAID_IOCTL_VERSION 114 + +/* Methods */ +#define GET_DRIVER_INFO 0x1 + +#define MEGA_CMD_TIMEOUT 10 /* Feel free to fiddle with these.. max values are: SGLIST 0..26 COMMANDS 0..253 CMDPERLUN 0..63 */ -#define MAX_SGLIST 0x1A -#define MAX_COMMANDS 127 -#define MAX_CMD_PER_LUN 63 + +#define MAX_SGLIST 0x1A +#define MAX_COMMANDS 127 +#define MAX_CMD_PER_LUN 63 #define MAX_FIRMWARE_STATUS 46 #define MAX_LOGICAL_DRIVES 8 -#define MAX_CHANNEL 5 -#define MAX_TARGET 15 +#define MAX_CHANNEL 5 +#define MAX_TARGET 15 #define MAX_PHYSICAL_DRIVES MAX_CHANNEL*MAX_TARGET #define INQUIRY_DATA_SIZE 0x24 -#define MAX_CDB_LEN 0x0A +#define MAX_CDB_LEN 0x0A #define MAX_REQ_SENSE_LEN 0x20 -#define INTR_VALID 0x40 +#define INTR_VALID 0x40 + +/* Direction Macros for MBOX Data direction */ +#define TO_DEVICE 0x0 +#define FROM_DEVICE 0x1 +#define FROMTO_DEVICE 0x2 /* Mailbox commands */ #define MEGA_MBOXCMD_LREAD 0x01 #define MEGA_MBOXCMD_LWRITE 0x02 +#define MEGA_MBOXCMD_LREAD64 0xA7 +#define MEGA_MBOXCMD_LWRITE64 0xA8 #define MEGA_MBOXCMD_PASSTHRU 0x03 #define MEGA_MBOXCMD_ADAPTERINQ 0x05 /* Offsets into Mailbox */ -#define COMMAND_PORT 0x00 -#define COMMAND_ID_PORT 0x01 -#define SG_LIST_PORT0 0x08 -#define SG_LIST_PORT1 0x09 -#define SG_LIST_PORT2 0x0a -#define SG_LIST_PORT3 0x0b -#define SG_ELEMENT_PORT 0x0d -#define NO_FIRED_PORT 0x0f +#define COMMAND_PORT 0x00 +#define COMMAND_ID_PORT 0x01 +#define SG_LIST_PORT0 0x08 +#define SG_LIST_PORT1 0x09 +#define SG_LIST_PORT2 0x0a +#define SG_LIST_PORT3 0x0b +#define SG_ELEMENT_PORT 0x0d +#define NO_FIRED_PORT 0x0f /* I/O Port offsets */ -#define I_CMD_PORT 0x00 -#define I_ACK_PORT 0x00 -#define I_TOGGLE_PORT 0x01 -#define INTR_PORT 0x0a - -#define MAILBOX_SIZE (sizeof(mega_mailbox)-16) -#define MBOX_BUSY_PORT 0x00 -#define MBOX_PORT0 0x04 -#define MBOX_PORT1 0x05 -#define MBOX_PORT2 0x06 -#define MBOX_PORT3 0x07 -#define ENABLE_MBOX_REGION 0x0B +#define I_CMD_PORT 0x00 +#define I_ACK_PORT 0x00 +#define I_TOGGLE_PORT 0x01 +#define INTR_PORT 0x0a + +#define MAILBOX_SIZE (sizeof(mega_mailbox)-16) +#define MBOX_BUSY_PORT 0x00 +#define MBOX_PORT0 0x04 +#define MBOX_PORT1 0x05 +#define MBOX_PORT2 0x06 +#define MBOX_PORT3 0x07 +#define ENABLE_MBOX_REGION 0x0B /* I/O Port Values */ -#define ISSUE_BYTE 0x10 -#define ACK_BYTE 0x08 -#define ENABLE_INTR_BYTE 0xc0 -#define DISABLE_INTR_BYTE 0x00 -#define VALID_INTR_BYTE 0x40 -#define MBOX_BUSY_BYTE 0x10 -#define ENABLE_MBOX_BYTE 0x00 +#define ISSUE_BYTE 0x10 +#define ACK_BYTE 0x08 +#define ENABLE_INTR_BYTE 0xc0 +#define DISABLE_INTR_BYTE 0x00 +#define VALID_INTR_BYTE 0x40 +#define MBOX_BUSY_BYTE 0x10 +#define ENABLE_MBOX_BYTE 0x00 /* Setup some port macros here */ -#define WRITE_MAILBOX(base,offset,value) *(base+offset)=value -#define READ_MAILBOX(base,offset) *(base+offset) - -#define WRITE_PORT(base,offset,value) outb_p(value,base+offset) -#define READ_PORT(base,offset) inb_p(base+offset) - -#define ISSUE_COMMAND(base) WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE) -#define CLEAR_INTR(base) WRITE_PORT(base,I_ACK_PORT,ACK_BYTE) -#define ENABLE_INTR(base) WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE) -#define DISABLE_INTR(base) WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE) +#define WRITE_MAILBOX(base,offset,value) *(base+offset)=value +#define READ_MAILBOX(base,offset) *(base+offset) -/* Define AMI's PCI codes */ -#undef PCI_VENDOR_ID_AMI -#undef PCI_DEVICE_ID_AMI_MEGARAID +#define WRITE_PORT(base,offset,value) outb_p(value,base+offset) +#define READ_PORT(base,offset) inb_p(base+offset) -#ifndef PCI_VENDOR_ID_AMI -#define PCI_VENDOR_ID_AMI 0x101E -#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 -#endif - -#define PCI_CONF_BASE_ADDR_OFFSET 0x10 -#define PCI_CONF_IRQ_OFFSET 0x3c -#define PCI_CONF_AMISIG 0xa0 -#define AMI_SIGNATURE 0x3344 -#define AMI_SIGNATURE_471 0xCCCC +#define ISSUE_COMMAND(base) WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE) +#define CLEAR_INTR(base) WRITE_PORT(base,I_ACK_PORT,ACK_BYTE) +#define ENABLE_INTR(base) WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE) +#define DISABLE_INTR(base) WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE) + +/* Special Adapter Commands */ +#define FW_FIRE_WRITE 0x2C +#define FW_FIRE_FLASH 0x2D + +#define FC_NEW_CONFIG 0xA1 +#define DCMD_FC_CMD 0xA1 +#define DCMD_FC_PROCEED 0x02 +#define DCMD_DELETE_LOGDRV 0x03 +#define DCMD_FC_READ_NVRAM_CONFIG 0x04 +#define DCMD_FC_READ_NVRAM_CONFIG_64 0xC0 +#define DCMD_FC_READ_FINAL_CONFIG 0x05 +#define DCMD_GET_DISK_CONFIG 0x06 +#define DCMD_GET_DISK_CONFIG_64 0xC2 +#define DCMD_CHANGE_LDNO 0x07 +#define DCMD_COMPACT_CONFIG 0x08 +#define DCMD_DELETE_DRIVEGROUP 0x09 +#define DCMD_GET_LOOPID_INFO 0x0A +#define DCMD_CHANGE_LOOPID 0x0B +#define DCMD_GET_NUM_SCSI_CHANS 0x0C +#define DCMD_WRITE_CONFIG 0x0D +#define DCMD_WRITE_CONFIG_64 0xC1 + +#define NC_SUBOP_PRODUCT_INFO 0x0E +#define NC_SUBOP_ENQUIRY3 0x0F +#define ENQ3_GET_SOLICITED_NOTIFY_ONLY 0x01 +#define ENQ3_GET_SOLICITED_FULL 0x02 +#define ENQ3_GET_UNSOLICITED 0x03 + +#define PCI_CONF_BASE_ADDR_OFFSET 0x10 +#define PCI_CONF_IRQ_OFFSET 0x3c +#define PCI_CONF_AMISIG 0xa0 +#define PCI_CONF_AMISIG64 0xa4 + +/* Sub-System Vendor ID sorted on alphabetical order*/ +#define AMI_SUBSYS_ID 0x101E +#define DELL_SUBSYS_ID 0x1028 +#define HP_SUBSYS_ID 0x103C + +#define AMI_SIGNATURE 0x3344 +#define AMI_SIGNATURE_471 0xCCCC +#define AMI_64BIT_SIGNATURE 0x0299 -#if LINUX_VERSION_CODE < 0x20100 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /*0x20100 */ #define MEGARAID \ - { NULL, /* Next */\ - NULL, /* Usage Count Pointer */\ - NULL, /* /proc Directory Entry */\ - megaraid_proc_info, /* /proc Info Function */\ - "MegaRAID", /* Driver Name */\ - megaraid_detect, /* Detect Host Adapter */\ - megaraid_release, /* Release Host Adapter */\ - megaraid_info, /* Driver Info Function */\ - megaraid_command, /* Command Function */\ - megaraid_queue, /* Queue Command Function */\ - megaraid_abort, /* Abort Command Function */\ - megaraid_reset, /* Reset Command Function */\ - NULL, /* Slave Attach Function */\ - megaraid_biosparam, /* Disk BIOS Parameters */\ - MAX_COMMANDS, /* # of cmds that can be\ - outstanding at any time */\ - 7, /* HBA Target ID */\ - MAX_SGLIST, /* Scatter/Gather Table Size */\ - MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ - 0, /* Present */\ - 0, /* Default Unchecked ISA DMA */\ - ENABLE_CLUSTERING } /* Enable Clustering */ + { NULL, /* Next */\ + NULL, /* Usage Count Pointer */\ + NULL, /* proc Directory Entry */\ + megaraid_proc_info, /* proc Info Function */\ + "MegaRAID", /* Driver Name */\ + megaraid_detect, /* Detect Host Adapter */\ + megaraid_release, /* Release Host Adapter */\ + megaraid_info, /* Driver Info Function */\ + megaraid_command, /* Command Function */\ + megaraid_queue, /* Queue Command Function */\ + megaraid_abort, /* Abort Command Function */\ + megaraid_reset, /* Reset Command Function */\ + NULL, /* Slave Attach Function */\ + megaraid_biosparam, /* Disk BIOS Parameters */\ + MAX_COMMANDS, /* # of cmds that can be\ + outstanding at any time */\ + 7, /* HBA Target ID */\ + MAX_SGLIST, /* Scatter/Gather Table Size */\ + MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ + 0, /* Present */\ + 0, /* Default Unchecked ISA DMA */\ + ENABLE_CLUSTERING } /* Enable Clustering */ #else #define MEGARAID \ {\ - name: "MegaRAID", /* Driver Name */\ - proc_info: megaraid_proc_info, /* /proc driver info */\ - detect: megaraid_detect, /* Detect Host Adapter */\ - release: megaraid_release, /* Release Host Adapter */\ - info: megaraid_info, /* Driver Info Function */\ - command: megaraid_command, /* Command Function */\ - queuecommand: megaraid_queue, /* Queue Command Function */\ - abort: megaraid_abort, /* Abort Command Function */\ - reset: megaraid_reset, /* Reset Command Function */\ - bios_param: megaraid_biosparam, /* Disk BIOS Parameters */\ - can_queue: MAX_COMMANDS, /* Can Queue */\ - this_id: 7, /* HBA Target ID */\ - sg_tablesize: MAX_SGLIST, /* Scatter/Gather Table Size */\ - cmd_per_lun: MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ - present: 0, /* Present */\ - unchecked_isa_dma:0, /* Default Unchecked ISA DMA */\ - use_clustering: ENABLE_CLUSTERING /* Enable Clustering */\ + name: "MegaRAID", /* Driver Name */\ + proc_info: megaraid_proc_info, /* /proc driver info */\ + detect: megaraid_detect, /* Detect Host Adapter */\ + release: megaraid_release, /* Release Host Adapter */\ + info: megaraid_info, /* Driver Info Function */\ + command: megaraid_command, /* Command Function */\ + queuecommand: megaraid_queue, /* Queue Command Function */\ + abort: megaraid_abort, /* Abort Command Function */\ + reset: megaraid_reset, /* Reset Command Function */\ + bios_param: megaraid_biosparam, /* Disk BIOS Parameters */\ + can_queue: MAX_COMMANDS, /* Can Queue */\ + this_id: 7, /* HBA Target ID */\ + sg_tablesize: MAX_SGLIST, /* Scatter/Gather Table Size */\ + cmd_per_lun: MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ + present: 0, /* Present */\ + unchecked_isa_dma: 0, /* Default Unchecked ISA DMA */\ + use_clustering: ENABLE_CLUSTERING /* Enable Clustering */\ } #endif - /*********************************************************************** * Structure Declarations for the Firmware supporting 40 Logical Drives * and 256 Physical Drives. ***********************************************************************/ -#define FC_MAX_LOGICAL_DRIVES 40 -#define FC_MAX_LOG_DEVICES FC_MAX_LOGICAL_DRIVES -#define FC_MAX_SPAN_DEPTH 8 -#define FC_MAX_ROW_SIZE 32 - -#define FC_MAX_CHANNELS 16 -#define FC_MAX_TARGETS_PER_CHANNEL 16 -#define FC_MAX_PHYSICAL_DEVICES 256 - -#define FC_NEW_CONFIG 0xA1 -#define DCMD_FC_CMD 0xA1 - #define NC_SUBOP_PRODUCT_INFO 0x0E - #define NC_SUBOP_ENQUIRY3 0x0F - #define ENQ3_GET_SOLICITED_NOTIFY_ONLY 0x01 - #define ENQ3_GET_SOLICITED_FULL 0x02 - #define ENQ3_GET_UNSOLICITED 0x03 - +#define FC_MAX_LOGICAL_DRIVES 40 +#define FC_MAX_LOG_DEVICES FC_MAX_LOGICAL_DRIVES +#define FC_MAX_SPAN_DEPTH 8 +#define FC_MAX_ROW_SIZE 32 + +#define FC_MAX_CHANNELS 16 +#define FC_MAX_TARGETS_PER_CHANNEL 16 +#define FC_MAX_PHYSICAL_DEVICES 256 /******************************************** - * PRODUCT_INFO Strucure + * PRODUCT_INFO ********************************************/ #define SIG_40LOG_32STR_8SPN 0x00282008 -/* +/* * Utilities declare this strcture size as 1024 bytes. So more fields can * be added in future. */ -struct MRaidProductInfo -{ - u32 DataSize; /* current size in bytes (not including resvd) */ - u32 ConfigSignature; - /* Current value is 0x00282008 - * 0x28=MAX_LOGICAL_DRIVES, - * 0x20=Number of stripes and - * 0x08=Number of spans */ - u8 FwVer[16]; /* printable ASCI string */ - u8 BiosVer[16]; /* printable ASCI string */ - u8 ProductName[80]; /* printable ASCI string */ - - u8 MaxConcCmds; /* Max. concurrent commands supported */ - u8 SCSIChanPresent; /* Number of SCSI Channels detected */ - u8 FCLoopPresent; /* Number of Fibre Loops detected */ - u8 memType; /* EDO, FPM, SDRAM etc */ - - u32 signature; - u16 DramSize; /* In terms of MB */ - u16 subSystemID; - - u16 subSystemVendorID; - u8 numNotifyCounters; - u8 pad1k[889]; /* 135 + 889 resvd = 1024 total size */ -}__attribute__((packed)); +struct MRaidProductInfo { + u32 DataSize; /* current size in bytes (not including resvd) */ + u32 ConfigSignature; + /* Current value is 0x00282008 + * 0x28=MAX_LOGICAL_DRIVES, + * 0x20=Number of stripes and + * 0x08=Number of spans */ + u8 FwVer[16]; /* printable ASCI string */ + u8 BiosVer[16]; /* printable ASCI string */ + u8 ProductName[80]; /* printable ASCI string */ + + u8 MaxConcCmds; /* Max. concurrent commands supported */ + u8 SCSIChanPresent; /* Number of SCSI Channels detected */ + u8 FCLoopPresent; /* Number of Fibre Loops detected */ + u8 memType; /* EDO, FPM, SDRAM etc */ + + u32 signature; + u16 DramSize; /* In terms of MB */ + u16 subSystemID; + + u16 subSystemVendorID; + u8 numNotifyCounters; + u8 pad1k[889]; /* 135 + 889 resvd = 1024 total size */ +} __attribute__ ((packed)); typedef struct MRaidProductInfo megaRaidProductInfo; /******************************************** - * Standard ENQUIRY Strucure + * Standard ENQUIRY ********************************************/ -struct FC_ADP_INFO -{ - u8 MaxConcCmds; /* Max. concurrent commands supported. */ - u8 RbldRate; /* Rebuild Rate. Varies from 0%-100% */ - u8 MaxTargPerChan; /* Max. Targets supported per chan. */ - u8 ChanPresent; /* No. of Chans present on this adapter. */ - u8 FwVer[4]; /* Firmware version. */ - u16 AgeOfFlash; /* No. of times FW has been downloaded. */ - u8 ChipSetValue; /* Contents of 0xC0000832 */ - u8 DramSize; /* In terms of MB */ - u8 CacheFlushInterval; /* In terms of Seconds */ - u8 BiosVersion[4]; - u8 BoardType; - u8 sense_alert; - u8 write_config_count; /* Increase with evry configuration change */ - u8 drive_inserted_count; /* Increase with every drive inserted */ - u8 inserted_drive; /* Channel: Id of inserted drive */ - u8 battery_status; - /* - BIT 0 : battery module missing - BIT 1 : VBAD - BIT 2 : temp high - BIT 3 : battery pack missing - BIT 4,5 : 00 - charge complete - 01 - fast charge in prog - 10 - fast charge fail - 11 - undefined - BIt 6 : counter > 1000 - Bit 7 : undefined - */ - u8 dec_fault_bus_info; /* was resvd */ -}__attribute__((packed)); - -struct FC_LDRV_INFO -{ - u8 NumLDrv; /* No. of Log. Drvs configured. */ - u8 recon_state[FC_MAX_LOGICAL_DRIVES/8]; - /* bit field for State of reconstruct */ - u16 LDrvOpStatus[FC_MAX_LOGICAL_DRIVES/8]; - /* bit field Status of Long Operations. */ - - u32 LDrvSize[FC_MAX_LOGICAL_DRIVES]; /* Size of each log. Drv. */ - u8 LDrvProp[FC_MAX_LOGICAL_DRIVES]; - u8 LDrvState[FC_MAX_LOGICAL_DRIVES]; /* State of Logical Drives. */ -}__attribute__((packed)); +struct FC_ADP_INFO { + u8 MaxConcCmds; /* Max. concurrent commands supported. */ + u8 RbldRate; /* Rebuild Rate. Varies from 0%-100% */ + u8 MaxTargPerChan; /* Max. Targets supported per chan. */ + u8 ChanPresent; /* No. of Chans present on this adapter. */ + u8 FwVer[4]; /* Firmware version. */ + u16 AgeOfFlash; /* No. of times FW has been downloaded. */ + u8 ChipSetValue; /* Contents of 0xC0000832 */ + u8 DramSize; /* In terms of MB */ + u8 CacheFlushInterval; /* In terms of Seconds */ + u8 BiosVersion[4]; + u8 BoardType; + u8 sense_alert; + u8 write_config_count; /* Increase with evry configuration change */ + u8 drive_inserted_count;/* Increase with every drive inserted */ + u8 inserted_drive; /* Channel: Id of inserted drive */ + u8 battery_status; + /* + BIT 0 : battery module missing + BIT 1 : VBAD + BIT 2 : temp high + BIT 3 : battery pack missing + BIT 4,5 : 00 - charge complete + 01 - fast charge in prog + 10 - fast charge fail + 11 - undefined + BIt 6 : counter > 1000 + Bit 7 : undefined + */ + u8 dec_fault_bus_info; /* was resvd */ +} __attribute__ ((packed)); + +struct FC_LDRV_INFO { + u8 NumLDrv; /* No. of Log. Drvs configured. */ + u8 recon_state[FC_MAX_LOGICAL_DRIVES / 8]; + /* bit field for State of reconstruct */ + u16 LDrvOpStatus[FC_MAX_LOGICAL_DRIVES / 8]; + /* bit field Status of Long Operations. */ + + u32 LDrvSize[FC_MAX_LOGICAL_DRIVES]; /* Size of each log. Drv. */ + u8 LDrvProp[FC_MAX_LOGICAL_DRIVES]; + u8 LDrvState[FC_MAX_LOGICAL_DRIVES]; /* State of Logical Drives. */ +} __attribute__ ((packed)); #define PREVSTAT_MASK 0xf0 #define CURRSTAT_MASK 0x0f -struct FC_PDRV_INFO -{ - u8 PDrvState[FC_MAX_PHYSICAL_DEVICES]; /* State of Phys Drvs. */ -}__attribute__((packed)); +struct FC_PDRV_INFO { + u8 PDrvState[FC_MAX_PHYSICAL_DEVICES]; /* State of Phys Drvs. */ +} __attribute__ ((packed)); + +struct FC_AdapterInq { + struct FC_ADP_INFO AdpInfo; + struct FC_LDRV_INFO LogdrvInfo; + struct FC_PDRV_INFO PhysdrvInfo; +} __attribute__ ((packed)); - -struct FC_AdapterInq -{ - struct FC_ADP_INFO AdpInfo; - struct FC_LDRV_INFO LogdrvInfo; - struct FC_PDRV_INFO PhysdrvInfo; -}__attribute__((packed)); - - -typedef struct FC_AdapterInq mega_RAIDINQ_FC; +typedef struct FC_AdapterInq mega_RAIDINQ_FC; /******************************************** - * NOTIFICATION Strucure + * NOTIFICATION ********************************************/ #define MAX_NOTIFY_SIZE 0x80 #define CUR_NOTIFY_SIZE sizeof(struct MegaRAID_Notify) -/* +/* * Utilities declare this strcture size as ?? bytes. So more fields can * be added in future. */ -struct MegaRAID_Notify -{ - u32 globalCounter; /* Any change increments this counter */ - - u8 paramCounter; /* Indicates any params changed */ - u8 paramId; /* Param modified - defined below */ - u16 paramVal; /* New val of last param modified */ - - u8 writeConfigCounter; /* write config occurred */ - u8 writeConfigRsvd[3]; - - u8 ldrvOpCounter; /* Indicates ldrv op started/completed */ - u8 ldrvOpId; /* ldrv num */ - u8 ldrvOpCmd; /* ldrv operation - defined below */ - u8 ldrvOpStatus; /* status of the operation */ - - u8 ldrvStateCounter; /* Indicates change of ldrv state */ - u8 ldrvStateId; /* ldrv num */ - u8 ldrvStateNew; /* New state */ - u8 ldrvStateOld; /* old state */ - - u8 pdrvStateCounter; /* Indicates change of ldrv state */ - u8 pdrvStateId; /* pdrv id */ - u8 pdrvStateNew; /* New state */ - u8 pdrvStateOld; /* old state */ - - u8 pdrvFmtCounter; /* Indicates pdrv format started/over */ - u8 pdrvFmtId; /* pdrv id */ - u8 pdrvFmtVal; /* format started/over */ - u8 pdrvFmtRsvd; - - u8 targXferCounter; /* Indicates SCSI-2 Xfer rate change */ - u8 targXferId; /* pdrv Id */ - u8 targXferVal; /* new Xfer params of last pdrv */ - u8 targXferRsvd; - - u8 fcLoopIdChgCounter; /* Indicates loopid changed */ - u8 fcLoopIdPdrvId; /* pdrv id */ - u8 fcLoopId0; /* loopid on fc loop 0 */ - u8 fcLoopId1; /* loopid on fc loop 1 */ - - u8 fcLoopStateCounter; /* Indicates loop state changed */ - u8 fcLoopState0; /* state of fc loop 0 */ - u8 fcLoopState1; /* state of fc loop 1 */ - u8 fcLoopStateRsvd; -}__attribute__((packed)); +struct MegaRAID_Notify { + u32 globalCounter; /* Any change increments this counter */ + u8 paramCounter; /* Indicates any params changed */ + u8 paramId; /* Param modified - defined below */ + u16 paramVal; /* New val of last param modified */ + + u8 writeConfigCounter; /* write config occurred */ + u8 writeConfigRsvd[3]; + + u8 ldrvOpCounter; /* Indicates ldrv op started/completed */ + u8 ldrvOpId; /* ldrv num */ + u8 ldrvOpCmd; /* ldrv operation - defined below */ + u8 ldrvOpStatus; /* status of the operation */ + + u8 ldrvStateCounter; /* Indicates change of ldrv state */ + u8 ldrvStateId; /* ldrv num */ + u8 ldrvStateNew; /* New state */ + u8 ldrvStateOld; /* old state */ + + u8 pdrvStateCounter; /* Indicates change of ldrv state */ + u8 pdrvStateId; /* pdrv id */ + u8 pdrvStateNew; /* New state */ + u8 pdrvStateOld; /* old state */ + + u8 pdrvFmtCounter; /* Indicates pdrv format started/over */ + u8 pdrvFmtId; /* pdrv id */ + u8 pdrvFmtVal; /* format started/over */ + u8 pdrvFmtRsvd; + + u8 targXferCounter; /* Indicates SCSI-2 Xfer rate change */ + u8 targXferId; /* pdrv Id */ + u8 targXferVal; /* new Xfer params of last pdrv */ + u8 targXferRsvd; + + u8 fcLoopIdChgCounter; /* Indicates loopid changed */ + u8 fcLoopIdPdrvId; /* pdrv id */ + u8 fcLoopId0; /* loopid on fc loop 0 */ + u8 fcLoopId1; /* loopid on fc loop 1 */ + + u8 fcLoopStateCounter; /* Indicates loop state changed */ + u8 fcLoopState0; /* state of fc loop 0 */ + u8 fcLoopState1; /* state of fc loop 1 */ + u8 fcLoopStateRsvd; +} __attribute__ ((packed)); /******************************************** * PARAM IDs in Notify struct ********************************************/ -#define PARAM_RBLD_RATE 0x01 +#define PARAM_RBLD_RATE 0x01 /*-------------------------------------- - * Param val = - * byte 0: new rbld rate + * Param val = + * byte 0: new rbld rate *--------------------------------------*/ #define PARAM_CACHE_FLUSH_INTERVAL 0x02 /*-------------------------------------- - * Param val = + * Param val = * byte 0: new cache flush interval *--------------------------------------*/ -#define PARAM_SENSE_ALERT 0x03 +#define PARAM_SENSE_ALERT 0x03 /*-------------------------------------- - * Param val = + * Param val = * byte 0: last pdrv id causing chkcond *--------------------------------------*/ -#define PARAM_DRIVE_INSERTED 0x04 +#define PARAM_DRIVE_INSERTED 0x04 /*-------------------------------------- - * Param val = + * Param val = * byte 0: last pdrv id inserted *--------------------------------------*/ -#define PARAM_BATTERY_STATUS 0x05 +#define PARAM_BATTERY_STATUS 0x05 /*-------------------------------------- - * Param val = + * Param val = * byte 0: battery status *--------------------------------------*/ /******************************************** * Ldrv operation cmd in Notify struct ********************************************/ -#define LDRV_CMD_CHKCONSISTANCY 0x01 -#define LDRV_CMD_INITIALIZE 0x02 -#define LDRV_CMD_RECONSTRUCTION 0x03 +#define LDRV_CMD_CHKCONSISTANCY 0x01 +#define LDRV_CMD_INITIALIZE 0x02 +#define LDRV_CMD_RECONSTRUCTION 0x03 /******************************************** * Ldrv operation status in Notify struct ********************************************/ -#define LDRV_OP_SUCCESS 0x00 -#define LDRV_OP_FAILED 0x01 -#define LDRV_OP_ABORTED 0x02 -#define LDRV_OP_CORRECTED 0x03 -#define LDRV_OP_STARTED 0x04 - +#define LDRV_OP_SUCCESS 0x00 +#define LDRV_OP_FAILED 0x01 +#define LDRV_OP_ABORTED 0x02 +#define LDRV_OP_CORRECTED 0x03 +#define LDRV_OP_STARTED 0x04 /******************************************** * Raid Logical drive states. ********************************************/ -#define RDRV_OFFLINE 0 -#define RDRV_DEGRADED 1 -#define RDRV_OPTIMAL 2 -#define RDRV_DELETED 3 +#define RDRV_OFFLINE 0 +#define RDRV_DEGRADED 1 +#define RDRV_OPTIMAL 2 +#define RDRV_DELETED 3 /******************************************* * Physical drive states. *******************************************/ -#define PDRV_UNCNF 0 -#define PDRV_ONLINE 3 -#define PDRV_FAILED 4 -#define PDRV_RBLD 5 -/* #define PDRV_HOTSPARE 6 */ +#define PDRV_UNCNF 0 +#define PDRV_ONLINE 3 +#define PDRV_FAILED 4 +#define PDRV_RBLD 5 /******************************************* * Formal val in Notify struct *******************************************/ -#define PDRV_FMT_START 0x01 -#define PDRV_FMT_OVER 0x02 +#define PDRV_FMT_START 0x01 +#define PDRV_FMT_OVER 0x02 /******************************************** * FC Loop State in Notify Struct ********************************************/ -#define ENQ_FCLOOP_FAILED 0 -#define ENQ_FCLOOP_ACTIVE 1 -#define ENQ_FCLOOP_TRANSIENT 2 - +#define ENQ_FCLOOP_FAILED 0 +#define ENQ_FCLOOP_ACTIVE 1 +#define ENQ_FCLOOP_TRANSIENT 2 + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#define M_RD_DMA_TYPE_NONE 0xFFFF +#define M_RD_PTHRU_WITH_BULK_DATA 0x0001 +#define M_RD_PTHRU_WITH_SGLIST 0x0002 +#define M_RD_BULK_DATA_ONLY 0x0004 +#define M_RD_SGLIST_ONLY 0x0008 +#endif /******************************************** - * ENQUIRY3 Strucure + * ENQUIRY3 ********************************************/ -/* +/* * Utilities declare this strcture size as 1024 bytes. So more fields can * be added in future. */ -struct MegaRAID_Enquiry3 -{ - u32 dataSize; /* current size in bytes (not including resvd) */ - - struct MegaRAID_Notify notify; - - u8 notifyRsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE]; - - u8 rbldRate; /* Rebuild rate (0% - 100%) */ - u8 cacheFlushInterval; /* In terms of Seconds */ - u8 senseAlert; - u8 driveInsertedCount; /* drive insertion count */ - - u8 batteryStatus; - u8 numLDrv; /* No. of Log Drives configured */ - u8 reconState[FC_MAX_LOGICAL_DRIVES/8]; /* State of reconstruct */ - u16 lDrvOpStatus[FC_MAX_LOGICAL_DRIVES/8]; /* log. Drv Status */ - - u32 lDrvSize[FC_MAX_LOGICAL_DRIVES]; /* Size of each log. Drv */ - u8 lDrvProp[FC_MAX_LOGICAL_DRIVES]; - u8 lDrvState[FC_MAX_LOGICAL_DRIVES]; /* State of Logical Drives */ - u8 pDrvState[FC_MAX_PHYSICAL_DEVICES]; /* State of Phys. Drvs. */ - u16 physDrvFormat[FC_MAX_PHYSICAL_DEVICES/16]; - - u8 targXfer[80]; /* phys device transfer rate */ - u8 pad1k[263]; /* 761 + 263reserved = 1024 bytes total size */ -}__attribute__((packed)); +struct MegaRAID_Enquiry3 { + u32 dataSize; /* current size in bytes (not including resvd) */ + + struct MegaRAID_Notify notify; + + u8 notifyRsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE]; + + u8 rbldRate; /* Rebuild rate (0% - 100%) */ + u8 cacheFlushInterval; /* In terms of Seconds */ + u8 senseAlert; + u8 driveInsertedCount; /* drive insertion count */ + + u8 batteryStatus; + u8 numLDrv; /* No. of Log Drives configured */ + u8 reconState[FC_MAX_LOGICAL_DRIVES / 8]; /* State of reconstruct */ + u16 lDrvOpStatus[FC_MAX_LOGICAL_DRIVES / 8]; /* log. Drv Status */ + + u32 lDrvSize[FC_MAX_LOGICAL_DRIVES]; /* Size of each log. Drv */ + u8 lDrvProp[FC_MAX_LOGICAL_DRIVES]; + u8 lDrvState[FC_MAX_LOGICAL_DRIVES]; /* State of Logical Drives */ + u8 pDrvState[FC_MAX_PHYSICAL_DEVICES]; /* State of Phys. Drvs. */ + u16 physDrvFormat[FC_MAX_PHYSICAL_DEVICES / 16]; + + u8 targXfer[80]; /* phys device transfer rate */ + u8 pad1k[263]; /* 761 + 263reserved = 1024 bytes total size */ +} __attribute__ ((packed)); typedef struct MegaRAID_Enquiry3 mega_Enquiry3; /* Structures */ typedef struct _mega_ADP_INFO { - u8 MaxConcCmds; - u8 RbldRate; - u8 MaxTargPerChan; - u8 ChanPresent; - u8 FwVer[4]; - u16 AgeOfFlash; - u8 ChipSetValue; - u8 DramSize; - u8 CacheFlushInterval; - u8 BiosVer[4]; - u8 resvd[7]; + u8 MaxConcCmds; + u8 RbldRate; + u8 MaxTargPerChan; + u8 ChanPresent; + u8 FwVer[4]; + u16 AgeOfFlash; + u8 ChipSetValue; + u8 DramSize; + u8 CacheFlushInterval; + u8 BiosVer[4]; + u8 resvd[7]; } mega_ADP_INFO; typedef struct _mega_LDRV_INFO { - u8 NumLDrv; - u8 resvd[3]; - u32 LDrvSize[MAX_LOGICAL_DRIVES]; - u8 LDrvProp[MAX_LOGICAL_DRIVES]; - u8 LDrvState[MAX_LOGICAL_DRIVES]; + u8 NumLDrv; + u8 resvd[3]; + u32 LDrvSize[MAX_LOGICAL_DRIVES]; + u8 LDrvProp[MAX_LOGICAL_DRIVES]; + u8 LDrvState[MAX_LOGICAL_DRIVES]; } mega_LDRV_INFO; typedef struct _mega_PDRV_INFO { - u8 PDrvState[MAX_PHYSICAL_DRIVES]; - u8 resvd; + u8 PDrvState[MAX_PHYSICAL_DRIVES]; + u8 resvd; } mega_PDRV_INFO; -// RAID inquiry: Mailbox command 0x5 +/* RAID inquiry: Mailbox command 0x5*/ typedef struct _mega_RAIDINQ { - mega_ADP_INFO AdpInfo; - mega_LDRV_INFO LogdrvInfo; - mega_PDRV_INFO PhysdrvInfo; + mega_ADP_INFO AdpInfo; + mega_LDRV_INFO LogdrvInfo; + mega_PDRV_INFO PhysdrvInfo; } mega_RAIDINQ; -// Passthrough command: Mailbox command 0x3 +/* Passthrough command: Mailbox command 0x3*/ typedef struct mega_passthru { - u8 timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ - u8 ars:1; - u8 reserved:3; - u8 islogical:1; - u8 logdrv; /* if islogical == 1 */ - u8 channel; /* if islogical == 0 */ - u8 target; /* if islogical == 0 */ - u8 queuetag; /* unused */ - u8 queueaction; /* unused */ - u8 cdb[MAX_CDB_LEN]; - u8 cdblen; - u8 reqsenselen; - u8 reqsensearea[MAX_REQ_SENSE_LEN]; - u8 numsgelements; - u8 scsistatus; - u32 dataxferaddr; - u32 dataxferlen; + u8 timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ + u8 ars:1; + u8 reserved:3; + u8 islogical:1; + u8 logdrv; /* if islogical == 1 */ + u8 channel; /* if islogical == 0 */ + u8 target; /* if islogical == 0 */ + u8 queuetag; /* unused */ + u8 queueaction; /* unused */ + u8 cdb[MAX_CDB_LEN]; + u8 cdblen; + u8 reqsenselen; + u8 reqsensearea[MAX_REQ_SENSE_LEN]; + u8 numsgelements; + u8 scsistatus; + u32 dataxferaddr; + u32 dataxferlen; } mega_passthru; struct _mega_mailbox { - /* 0x0 */ u8 cmd; - /* 0x1 */ u8 cmdid; - /* 0x2 */ u16 numsectors; - /* 0x4 */ u32 lba; - /* 0x8 */ u32 xferaddr; - /* 0xC */ u8 logdrv; - /* 0xD */ u8 numsgelements; - /* 0xE */ u8 resvd; - /* 0xF */ u8 busy; - /* 0x10 */ u8 numstatus; - /* 0x11 */ u8 status; - /* 0x12 */ u8 completed[46]; - u8 mraid_poll; - u8 mraid_ack; - u8 pad[16]; /* for alignment purposes */ -}__attribute__((packed)); + /* 0x0 */ u8 cmd; + /* 0x1 */ u8 cmdid; + /* 0x2 */ u16 numsectors; + /* 0x4 */ u32 lba; + /* 0x8 */ u32 xferaddr; + /* 0xC */ u8 logdrv; + /* 0xD */ u8 numsgelements; + /* 0xE */ u8 resvd; + /* 0xF */ u8 busy; + /* 0x10 */ u8 numstatus; + /* 0x11 */ u8 status; + /* 0x12 */ u8 completed[46]; + volatile u8 mraid_poll; + volatile u8 mraid_ack; + u8 pad[16]; /* for alignment purposes */ +} __attribute__ ((packed)); typedef struct _mega_mailbox mega_mailbox; typedef struct { - u32 xferSegment; /* for 64-bit controllers */ - mega_mailbox mailbox; + u32 xferSegment_lo; + u32 xferSegment_hi; + mega_mailbox mailbox; } mega_mailbox64; typedef struct _mega_ioctl_mbox { - /* 0x0 */ u8 cmd; - /* 0x1 */ u8 cmdid; - /* 0x2 */ u8 channel; - /* 0x3 */ u8 param; - /* 0x4 */ u8 pad[4]; - /* 0x8 */ u32 xferaddr; - /* 0xC */ u8 logdrv; - /* 0xD */ u8 numsgelements; - /* 0xE */ u8 resvd; - /* 0xF */ u8 busy; - /* 0x10 */ u8 numstatus; - /* 0x11 */ u8 status; - /* 0x12 */ u8 completed[46]; - u8 mraid_poll; - u8 mraid_ack; - u8 malign[16]; + /* 0x0 */ u8 cmd; + /* 0x1 */ u8 cmdid; + /* 0x2 */ u8 channel; + /* 0x3 */ u8 param; + /* 0x4 */ u8 pad[4]; + /* 0x8 */ u32 xferaddr; + /* 0xC */ u8 logdrv; + /* 0xD */ u8 numsgelements; + /* 0xE */ u8 resvd; + /* 0xF */ u8 busy; + /* 0x10 */ u8 numstatus; + /* 0x11 */ u8 status; + /* 0x12 */ u8 completed[46]; + u8 mraid_poll; + u8 mraid_ack; + u8 malign[16]; } mega_ioctl_mbox; +typedef struct _mega_64sglist32 { + u64 address; + u32 length; +} __attribute__ ((packed)) mega_64sglist; + typedef struct _mega_sglist { - u32 address; - u32 length; + u32 address; + u32 length; } mega_sglist; /* Queued command data */ typedef struct _mega_scb mega_scb; struct _mega_scb { - int idx; - u32 state; - u32 isrcount; - u8 mboxData[16]; - mega_passthru pthru; - Scsi_Cmnd *SCpnt; - mega_sglist *sgList; - char *kern_area; /* Only used for large ioctl xfers */ - struct wait_queue *ioctl_wait; - struct semaphore sem; - mega_scb *next; + int idx; + u32 state; + u32 isrcount; + u8 mboxData[16]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + u32 dma_type; + dma_addr_t dma_h_bulkdata; /*Dma handle for bulk data transfter */ + u32 dma_direction; /*Dma direction */ + dma_addr_t dma_h_sgdata; /*Dma handle for the sglist structure */ + dma_addr_t dma_h_sglist[MAX_SGLIST]; /*Dma handle for all SGL elements */ + u8 sglist_count; + dma_addr_t dma_sghandle64; + dma_addr_t dma_passthruhandle64; + dma_addr_t dma_bounce_buffer; + u8 *bounce_buffer; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + mega_passthru *pthru; +#else + mega_passthru pthru; +#endif + + Scsi_Cmnd *SCpnt; + mega_sglist *sgList; + mega_64sglist *sg64List; + struct semaphore ioctl_sem; + void *buff_ptr; + u32 iDataSize; + mega_scb *next; }; +/* internal locking by the queue manipulting routines */ +#define INTERNAL_LOCK 0 +/* external locking by the queue manipulting routines */ +#define EXTERNAL_LOCK 1 +#define NO_LOCK 2 +#define INTR_ENB 0 /* do not disable interrupt while manipulating */ +#define INTR_DIS 1 /* disable interrupt while manipulating */ + /* Per-controller data */ typedef struct _mega_host_config { - u8 numldrv; - u32 flag; - u32 base; - - mega_scb *qFreeH; - mega_scb *qFreeT; - mega_scb *qPendingH; - mega_scb *qPendingT; - - Scsi_Cmnd *qCompletedH; - Scsi_Cmnd *qCompletedT; - u32 qFcnt; - u32 qPcnt; - u32 qCcnt; - - u32 nReads[FC_MAX_LOGICAL_DRIVES]; - u32 nWrites[FC_MAX_LOGICAL_DRIVES]; - - /* Host adapter parameters */ - u8 fwVer[7]; - u8 biosVer[7]; - - struct Scsi_Host *host; - - volatile mega_mailbox64 *mbox64; /* ptr to beginning of 64-bit mailbox */ - volatile mega_mailbox *mbox; /* ptr to beginning of standard mailbox */ - volatile mega_mailbox64 mailbox64; -#if 0 - volatile union { - u8 generic_buffer[2 * 1024L]; - mega_RAIDINQ adapterInfoData; - mega_Enquiry3 enquiry3Data; - }mega_buffer; + u8 numldrv; + u32 flag; + +#ifdef __LP64__ + u64 base; +#else + u32 base; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + dma_addr_t dma_handle64, adjdmahandle64; + struct pci_dev *dev; +#endif + + mega_scb *qFreeH; + mega_scb *qFreeT; + spinlock_t lock_free; + + mega_scb *qPendingH; + mega_scb *qPendingT; + spinlock_t lock_pend; + + Scsi_Cmnd *qCompletedH; + Scsi_Cmnd *qCompletedT; + spinlock_t lock_scsicmd; + + u32 qFcnt; + u32 qPcnt; + u32 qCcnt; + + unsigned long nReads[FC_MAX_LOGICAL_DRIVES]; + unsigned long nReadBlocks[FC_MAX_LOGICAL_DRIVES]; + unsigned long nWrites[FC_MAX_LOGICAL_DRIVES]; + unsigned long nWriteBlocks[FC_MAX_LOGICAL_DRIVES]; + unsigned long nInterrupts; + /* Host adapter parameters */ + u8 fwVer[7]; + u8 biosVer[7]; + + struct Scsi_Host *host; + + volatile mega_mailbox64 *mbox64; /* ptr to beginning of 64-bit mailbox */ + volatile mega_mailbox *mbox; /* ptr to beginning of standard mailbox */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +/* ptr to beginning of standard mailbox */ + volatile mega_mailbox64 *mailbox64ptr; #else - volatile u8 mega_buffer[2*1024L]; + volatile mega_mailbox64 mailbox64; #endif - volatile megaRaidProductInfo productInfo; - u8 max_cmds; - mega_scb scbList[MAX_COMMANDS]; + volatile u8 mega_buffer[2 * 1024L]; + volatile megaRaidProductInfo productInfo; + + u8 max_cmds; + mega_scb scbList[MAX_COMMANDS]; + +#define PROCBUFSIZE 4096 + char procbuf[PROCBUFSIZE]; + int procidx; + struct proc_dir_entry *controller_proc_dir_entry; + struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox; } mega_host_config; -const char *megaraid_info(struct Scsi_Host *); -int megaraid_detect(Scsi_Host_Template *); -int megaraid_release(struct Scsi_Host *); -int megaraid_command(Scsi_Cmnd *); -int megaraid_abort(Scsi_Cmnd *); -int megaraid_reset(Scsi_Cmnd *, unsigned int); -int megaraid_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -int megaraid_biosparam(Disk *, kdev_t, int *); -int megaraid_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout); +typedef struct _driver_info { + int size; + ulong version; +} mega_driver_info; + +/* + * User ioctl structure. + * This structure will be used for Traditional Method ioctl interface + * commands (M_RD_IOCTL_CMD),Alternate Buffer Method (M_RD_IOCTL_CMD_NEW) + * ioctl commands and the Driver ioctls(M_RD_DRIVER_IOCTL_INTERFACE). + * The Driver ioctl interface handles the commands at + * the driver level, without being sent to the card. + */ +#define MEGADEVIOC 0x84 + +/* system call imposed limit. Change accordingly */ +#define IOCTL_MAX_DATALEN 4096 + +#pragma pack(1) +struct uioctl_t { + u32 inlen; + u32 outlen; + union { + u8 fca[16]; + struct { + u8 opcode; + u8 subopcode; + u16 adapno; +#if BITS_PER_LONG == 32 + u8 *buffer; + u8 pad[4]; +#endif +#if BITS_PER_LONG == 64 + u8 *buffer; +#endif + u32 length; + } fcs; + } ui; + u8 mbox[18]; /* 16 bytes + 2 status bytes */ + mega_passthru pthru; +#if BITS_PER_LONG == 32 + char *data; /* buffer <= 4096 for 0x80 commands */ + char pad[4]; +#endif +#if BITS_PER_LONG == 64 + char *data; +#endif +}; +#pragma pack() + +/* + * struct mcontroller is used to pass information about the controllers in the + * system. Its upto the application how to use the information. We are passing + * as much info about the cards as possible and useful. Before issuing the + * call to find information about the cards, the applicaiton needs to issue a + * ioctl first to find out the number of controllers in the system. + */ +#define MAX_CONTROLLERS 32 + +struct mcontroller { + u64 base; + u8 irq; + u8 numldrv; + u8 pcibus; + u16 pcidev; + u8 pcifun; + u16 pciid; + u16 pcivendor; + u8 pcislot; + u32 uid; +}; + +struct mbox_passthru { + u8 cmd; + u8 cmdid; + u16 pad1; + u32 pad2; + u32 dataxferaddr; + u8 pad3; + u8 pad4; + u8 rsvd; + u8 mboxbusy; + u8 nstatus; + u8 status; +}; + +/* + * Defines for Driver IOCTL interface, Op-code:M_RD_DRIVER_IOCTL_INTERFACE + */ +#define MEGAIOC_MAGIC 'm' +#define MEGAIOCCMD _IOWR(MEGAIOC_MAGIC, 0) /* Mega IOCTL command */ + +#define MEGAIOC_QNADAP 'm' /* Query # of adapters */ +#define MEGAIOC_QDRVRVER 'e' /* Query driver version */ +#define MEGAIOC_QADAPINFO 'g' /* Query adapter information */ +#define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | (adapno) ) +#define GETADAP(mkadap) ( (mkadap) ^ MEGAIOC_MAGIC << 8 ) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */ +extern struct proc_dir_entry proc_scsi_megaraid; +#endif + +/* For Host Re-Ordering */ +#define MAX_CONTROLLERS 32 + +struct mega_hbas { + int is_bios_enabled; + mega_host_config *hostdata_addr; +}; + +#define IS_BIOS_ENABLED 0x62 +#define GET_BIOS 0x01 + +/*================================================================ + * + * Function prototypes + * + *================================================================ + */ +static const char *megaraid_info (struct Scsi_Host *); +int megaraid_detect (Scsi_Host_Template *); +static int megaraid_release (struct Scsi_Host *); +static int megaraid_command (Scsi_Cmnd *); +static int megaraid_abort (Scsi_Cmnd *); +static int megaraid_reset (Scsi_Cmnd *, unsigned int); +static int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +static int megaraid_biosparam (Disk *, kdev_t, int *); +static int megaraid_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, + mega_scb * scb, int intr); +static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb, + u32 * buffer, u32 * length); +static int mega_busyWaitMbox (mega_host_config *); +static int mega_runpendq (mega_host_config *); +static void mega_rundoneq (mega_host_config *); +static void mega_cmd_done (mega_host_config *, mega_scb *, int); +static inline void mega_freeSgList (mega_host_config * megaCfg); +static void mega_Convert8ldTo40ld (mega_RAIDINQ * inquiry, + mega_Enquiry3 * enquiry3, + megaRaidProductInfo * productInfo); + +static int megaraid_reboot_notify (struct notifier_block *, + unsigned long, void *); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) +static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt); +static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, + mega_ioctl_mbox * mbox); +#endif + +static int megadev_open (struct inode *, struct file *); +static int megadev_ioctl_entry (struct inode *, struct file *, + unsigned int, unsigned long); +static int megadev_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); +static mega_scb *megadev_doioctl (mega_host_config *, Scsi_Cmnd *); +static int megadev_close (struct inode *, struct file *); +static void megadev_ioctl_done (Scsi_Cmnd *); +static int mega_init_scb (mega_host_config *); +static void enq_scb_freelist (mega_host_config *, mega_scb *, + int lock, int intr); + +static int mega_is_bios_enabled (mega_host_config *); +static void mega_reorder_hosts (void); +static void mega_swap_hosts (struct Scsi_Host *, struct Scsi_Host *); + +static void mega_create_proc_entry (int index, struct proc_dir_entry *); #endif diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.4.2/linux/drivers/scsi/ncr53c8xx.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/ncr53c8xx.c Tue Mar 6 19:34:25 2001 @@ -73,8 +73,6 @@ */ /* -** May 11 2000, version 3.3b -** ** Supported SCSI-II features: ** Synchronous negotiation ** Wide negotiation (depends on the NCR Chip) @@ -105,7 +103,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.3b" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.3-20010212" #define SCSI_NCR_DEBUG_FLAGS (0) @@ -136,7 +134,6 @@ #include #include #include -#include #include #include #include @@ -192,7 +189,8 @@ ** Donnot compile integrity checking code for Linux-2.3.0 ** and above since SCSI data structures are not ready yet. */ -#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) +/* #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) */ +#if 0 #define SCSI_NCR_INTEGRITY_CHECKING #endif @@ -556,50 +554,12 @@ #define UC_SETORDER 13 #define UC_SETWIDE 14 #define UC_SETFLAG 15 -#define UC_CLEARPROF 16 #define UC_SETVERBOSE 17 #define UF_TRACE (0x01) #define UF_NODISC (0x02) #define UF_NOSCAN (0x04) -/*--------------------------------------- -** -** Timestamps for profiling -** -**--------------------------------------- -*/ - -#ifdef SCSI_NCR_PROFILE_SUPPORT - -struct tstamp { - u_long start; - u_long end; - u_long command; - u_long status; - u_long disconnect; - u_long reselect; -}; - -/* -** profiling data (per device) -*/ - -struct profile { - u_long num_trans; - u_long num_kbytes; - u_long rest_bytes; - u_long num_disc; - u_long num_break; - u_long num_int; - u_long num_fly; - u_long ms_setup; - u_long ms_data; - u_long ms_disc; - u_long ms_post; -}; -#endif - /*======================================================================== ** ** Declaration of structs: target control block @@ -841,14 +801,6 @@ */ ccb_p cp; -#ifdef SCSI_NCR_PROFILE_SUPPORT - /*---------------------------------------------------------------- - ** Space for some timestamps to gather profiling data. - **---------------------------------------------------------------- - */ - struct tstamp stamp; -#endif - /*---------------------------------------------------------------- ** Status fields. **---------------------------------------------------------------- @@ -1176,11 +1128,6 @@ */ struct ncr_reg regdump; /* Register dump */ u_long regtime; /* Time it has been done */ -#ifdef SCSI_NCR_PROFILE_SUPPORT - struct profile profile; /* Profiling data */ - u_int disc_phys; /* Disconnection counters */ - u_int disc_ref; -#endif /*---------------------------------------------------------------- ** Miscellaneous buffers accessed by the scripts-processor. @@ -1216,9 +1163,6 @@ ** Fields that should be removed or changed. **---------------------------------------------------------------- */ -#ifdef SCSI_NCR_PROFILE_SUPPORT - u_long ktime; /* Copy of kernel time */ -#endif struct ccb *ccb; /* Global CCB */ struct usrcmd user; /* Command from user */ u_char release_stage; /* Synchronisation stage on release */ @@ -1272,19 +1216,11 @@ ncrcmd send_ident [ 9]; ncrcmd prepare [ 6]; ncrcmd prepare2 [ 7]; -#ifdef SCSI_NCR_PROFILE_SUPPORT - ncrcmd command [ 9]; -#else ncrcmd command [ 6]; -#endif ncrcmd dispatch [ 32]; ncrcmd clrack [ 4]; ncrcmd no_data [ 17]; -#ifdef SCSI_NCR_PROFILE_SUPPORT - ncrcmd status [ 11]; -#else ncrcmd status [ 8]; -#endif ncrcmd msg_in [ 2]; ncrcmd msg_in2 [ 16]; ncrcmd msg_bad [ 4]; @@ -1303,22 +1239,14 @@ #endif ncrcmd save_dp [ 7]; ncrcmd restore_dp [ 5]; -#ifdef SCSI_NCR_PROFILE_SUPPORT - ncrcmd disconnect [ 28]; -#else ncrcmd disconnect [ 17]; -#endif ncrcmd msg_out [ 9]; ncrcmd msg_out_done [ 7]; ncrcmd idle [ 2]; ncrcmd reselect [ 8]; ncrcmd reselected [ 8]; ncrcmd resel_dsa [ 6]; -#ifdef SCSI_NCR_PROFILE_SUPPORT - ncrcmd loadpos1 [ 7]; -#else ncrcmd loadpos1 [ 4]; -#endif ncrcmd resel_lun [ 6]; ncrcmd resel_tag [ 6]; ncrcmd jump_to_nexus [ 4]; @@ -1416,10 +1344,6 @@ static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr); #endif -#ifdef SCSI_NCR_PROFILE_SUPPORT -static void ncb_profile (ncb_p np, ccb_p cp); -#endif - static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); static void ncr_script_fill (struct script * scr, struct scripth * scripth); @@ -1673,14 +1597,6 @@ PADDR (dispatch), }/*-------------------------< COMMAND >--------------------*/,{ -#ifdef SCSI_NCR_PROFILE_SUPPORT - /* - ** ... set a timestamp ... - */ - SCR_COPY (sizeof (u_long)), - NADDR (ktime), - NADDR (header.stamp.command), -#endif /* ** ... and send the command */ @@ -1786,14 +1702,6 @@ PADDR (no_data), }/*-------------------------< STATUS >--------------------*/,{ -#ifdef SCSI_NCR_PROFILE_SUPPORT - /* - ** set the timestamp. - */ - SCR_COPY (sizeof (u_long)), - NADDR (ktime), - NADDR (header.stamp.status), -#endif /* ** get the status */ @@ -2020,24 +1928,6 @@ */ SCR_WAIT_DISC, 0, -#ifdef SCSI_NCR_PROFILE_SUPPORT - /* - ** Profiling: - ** Set a time stamp, - ** and count the disconnects. - */ - SCR_COPY (sizeof (u_long)), - NADDR (ktime), - NADDR (header.stamp.disconnect), - SCR_COPY (4), - NADDR (disc_phys), - RADDR (scratcha), - SCR_REG_REG (scratcha, SCR_ADD, 0x01), - 0, - SCR_COPY (4), - RADDR (scratcha), - NADDR (disc_phys), -#endif /* ** Status is: DISCONNECTED. */ @@ -2178,14 +2068,6 @@ }/*-------------------------< LOADPOS1 >-------------------*/,{ 0, NADDR (header), -#ifdef SCSI_NCR_PROFILE_SUPPORT - /* - ** Set a time stamp for this reselection - */ - SCR_COPY (sizeof (u_long)), - NADDR (ktime), - NADDR (header.stamp.reselect), -#endif /* ** The DSA contains the data structure address. */ @@ -3136,8 +3018,7 @@ switch (old & RELOC_MASK) { case RELOC_REGISTER: - new = (old & ~RELOC_MASK) - + pcivtobus(np->paddr); + new = (old & ~RELOC_MASK) + np->paddr; break; case RELOC_LABEL: new = (old & ~RELOC_MASK) + np->p_script; @@ -3359,11 +3240,19 @@ np->maxwide = (np->features & FE_WIDE)? 1 : 0; - /* - ** Get the frequency of the chip's clock. - ** Find the right value for scntl3. - */ + /* + * Guess the frequency of the chip's clock. + */ + if (np->features & (FE_ULTRA3 | FE_ULTRA2)) + np->clock_khz = 160000; + else if (np->features & FE_ULTRA) + np->clock_khz = 80000; + else + np->clock_khz = 40000; + /* + * Get the clock multiplier factor. + */ if (np->features & FE_QUAD) np->multiplier = 4; else if (np->features & FE_DBLR) @@ -3371,10 +3260,11 @@ else np->multiplier = 1; - np->clock_khz = (np->features & FE_CLK80)? 80000 : 40000; - np->clock_khz *= np->multiplier; - - if (np->clock_khz != 40000) + /* + * Measure SCSI clock frequency for chips + * it may vary from assumed one. + */ + if (np->features & FE_VARCLK) ncr_getclock(np, np->multiplier); /* @@ -3741,8 +3631,8 @@ np->paddr = device->slot.base; np->paddr2 = (np->features & FE_RAM)? device->slot.base_2 : 0; -#ifndef NCR_IOMAPPED - np->vaddr = remap_pci_mem((u_long) np->paddr, (u_long) 128); +#ifndef SCSI_NCR_IOMAPPED + np->vaddr = remap_pci_mem(device->slot.base_c, (u_long) 128); if (!np->vaddr) { printk(KERN_ERR "%s: can't map memory mapped IO region\n",ncr_name(np)); @@ -3761,7 +3651,7 @@ np->reg = (struct ncr_reg*) np->vaddr; -#endif /* !defined NCR_IOMAPPED */ +#endif /* !defined SCSI_NCR_IOMAPPED */ /* ** Try to map the controller chip into iospace. @@ -3810,7 +3700,7 @@ instance->this_id = np->myaddr; instance->max_id = np->maxwide ? 16 : 8; instance->max_lun = SCSI_NCR_MAX_LUN; -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,29) instance->base = (unsigned long) np->reg; #else @@ -3845,8 +3735,7 @@ np->scripth = np->scripth0; np->p_scripth = vtobus(np->scripth); - np->p_script = (np->paddr2) ? - pcivtobus(np->paddr2) : vtobus(np->script0); + np->p_script = (np->paddr2) ? np->paddr2 : vtobus(np->script0); ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script)); ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth)); @@ -3988,14 +3877,14 @@ printk(KERN_INFO "%s: detaching...\n", ncr_name(np)); if (!np) goto unregister; -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED if (np->vaddr) { #ifdef DEBUG_NCR53C8XX printk(KERN_DEBUG "%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); #endif unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128); } -#endif /* !NCR_IOMAPPED */ +#endif /* !SCSI_NCR_IOMAPPED */ if (np->base_io) { #ifdef DEBUG_NCR53C8XX printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128); @@ -4373,7 +4262,8 @@ ** **--------------------------------------------- */ - if (cmd->cmnd[0] == 0 && (tp->usrflag & UF_NOSCAN)) { + if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) && + (tp->usrflag & UF_NOSCAN)) { tp->usrflag &= ~UF_NOSCAN; return DID_BAD_TARGET; } @@ -4418,18 +4308,6 @@ } #endif - /*--------------------------------------------------- - ** - ** timestamp - ** - **---------------------------------------------------- - */ -#ifdef SCSI_NCR_PROFILE_SUPPORT - bzero (&cp->phys.header.stamp, sizeof (struct tstamp)); - cp->phys.header.stamp.start = jiffies; -#endif - - /*---------------------------------------------------- ** ** Build the identify / tag / sdtr message @@ -5105,12 +4983,12 @@ ** Release Memory mapped IO region and IO mapped region */ -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED #ifdef DEBUG_NCR53C8XX printk("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); #endif unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128); -#endif /* !NCR_IOMAPPED */ +#endif /* !SCSI_NCR_IOMAPPED */ #ifdef DEBUG_NCR53C8XX printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128); @@ -5190,12 +5068,8 @@ return; /* - ** timestamp - ** Optional, spare some CPU time + ** Print minimal debug information. */ -#ifdef SCSI_NCR_PROFILE_SUPPORT - ncb_profile (np, cp); -#endif if (DEBUG_FLAGS & DEBUG_TINY) printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp, @@ -5722,16 +5596,15 @@ /* ** Start script processor. */ - MEMORY_BARRIER(); if (np->paddr2) { if (bootverbose) printk ("%s: Downloading SCSI SCRIPTS.\n", ncr_name(np)); OUTL (nc_scratcha, vtobus(np->script0)); - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, start_ram)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, start_ram)); } else - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); } /*========================================================== @@ -6201,12 +6074,6 @@ tp->usrflag = np->user.data; }; break; - -#ifdef SCSI_NCR_PROFILE_SUPPORT - case UC_CLEARPROF: - bzero(&np->profile, sizeof(np->profile)); - break; -#endif } np->user.cmd=0; } @@ -6241,12 +6108,7 @@ return; } -#ifdef SCSI_NCR_PROFILE_SUPPORT - np->ktime = thistime; - np->timer.expires = ktime_get(1); -#else np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL); -#endif add_timer(&np->timer); /* @@ -6274,15 +6136,6 @@ ** block ncr interrupts */ np->lasttime = thistime; - -#ifdef SCSI_NCR_PROFILE_SUPPORT - /* - ** Reset profile data to avoid ugly overflow - ** (Limited to 1024 GB for 32 bit architecture) - */ - if (np->profile.num_kbytes > (~0UL >> 2)) - bzero(&np->profile, sizeof(np->profile)); -#endif } #ifdef SCSI_NCR_BROKEN_INTR @@ -6426,19 +6279,12 @@ OUTB (nc_istat, (istat & SIGP) | INTF); istat = INB (nc_istat); if (DEBUG_FLAGS & DEBUG_TINY) printk ("F "); -#ifdef SCSI_NCR_PROFILE_SUPPORT - np->profile.num_fly++; -#endif ncr_wakeup_done (np); }; if (!(istat & (SIP|DIP))) return; -#ifdef SCSI_NCR_PROFILE_SUPPORT - np->profile.num_int++; -#endif - if (istat & CABRT) OUTB (nc_istat, CABRT); @@ -6493,7 +6339,7 @@ ncr_name(np), istat, dstat, sist); return; } - OUTONB (nc_dcntl, (STD|NOCOM)); + OUTONB_STD (); return; }; @@ -6570,7 +6416,7 @@ if (sist & UDC) { printk ("%s: unexpected disconnect\n", ncr_name(np)); OUTB (HS_PRT, HS_UNEXPECTED); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, cleanup)); return; }; @@ -6622,7 +6468,7 @@ ** repair start queue and jump to start point. */ - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sto_restart)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, sto_restart)); return; } @@ -6740,7 +6586,7 @@ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ np->msgout[0] = msg; - OUTL (nc_dsp, jmp); + OUTL_DSP (jmp); return 1; reset_all: @@ -6991,11 +6837,8 @@ ** fake the return address (to the patch). ** and restart script processor at dispatcher. */ -#ifdef SCSI_NCR_PROFILE_SUPPORT - np->profile.num_break++; -#endif OUTL (nc_temp, newtmp); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch)); return; /* @@ -7057,7 +6900,7 @@ } if (nxtdsp) { - OUTL (nc_dsp, nxtdsp); + OUTL_DSP (nxtdsp); return; } @@ -7131,7 +6974,7 @@ ncr_put_start_queue(np, cp); if (disc_cnt) INB (nc_ctest2); /* Clear SIGP */ - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, reselect)); return; case S_TERMINATED: case S_CHECK_COND: @@ -7199,12 +7042,12 @@ ncr_put_start_queue(np, cp); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); return; } out: - OUTONB (nc_dcntl, (STD|NOCOM)); + OUTONB_STD (); return; } @@ -7267,7 +7110,7 @@ ** We just assume lun=0, 1 CCB, no tag. */ if (tp->lp[0]) { - OUTL (nc_dsp, scr_to_cpu(tp->lp[0]->jump_ccb[0])); + OUTL_DSP (scr_to_cpu(tp->lp[0]->jump_ccb[0])); return; } case SIR_RESEL_BAD_TARGET: /* Will send a TARGET RESET message */ @@ -7489,13 +7332,13 @@ ** Answer wasn't acceptable. */ ncr_setsync (np, cp, 0, 0xe0); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad)); } else { /* ** Answer is ok. */ ncr_setsync (np, cp, scntl3, (fak<<5)|ofs); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); }; return; @@ -7528,7 +7371,7 @@ } if (!ofs) { - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad)); return; } np->msgin [0] = M_NOOP; @@ -7586,13 +7429,13 @@ ** Answer wasn't acceptable. */ ncr_setwide (np, cp, 0, 1); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad)); } else { /* ** Answer is ok. */ ncr_setwide (np, cp, wide, 1); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); }; return; @@ -7700,7 +7543,7 @@ }; out: - OUTONB (nc_dcntl, (STD|NOCOM)); + OUTONB_STD (); } /*========================================================== @@ -7888,8 +7731,7 @@ } -#define ncr_reg_bus_addr(r) \ - (pcivtobus(np->paddr) + offsetof (struct ncr_reg, r)) +#define ncr_reg_bus_addr(r) (np->paddr + offsetof (struct ncr_reg, r)) /*------------------------------------------------------------------------ ** Initialize the fixed part of a CCB structure. @@ -8321,7 +8163,7 @@ **========================================================== */ -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED static int __init ncr_regtest (struct ncb* np) { register volatile u_int32 data; @@ -8350,7 +8192,7 @@ { u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; int i, err=0; -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED if (np->reg) { err |= ncr_regtest (np); if (err) return (err); @@ -8370,7 +8212,7 @@ /* ** Start script (exchange values) */ - OUTL (nc_dsp, pc); + OUTL_DSP (pc); /* ** Wait 'til done (with timeout) */ @@ -8434,73 +8276,6 @@ /*========================================================== ** ** -** Profiling the drivers and targets performance. -** -** -**========================================================== -*/ - -#ifdef SCSI_NCR_PROFILE_SUPPORT - -/* -** Compute the difference in jiffies ticks. -*/ - -#define ncr_delta(from, to) \ - ( ((to) && (from))? (to) - (from) : -1 ) - -#define PROFILE cp->phys.header.stamp -static void ncb_profile (ncb_p np, ccb_p cp) -{ - long co, st, en, di, re, post, work, disc; - u_int diff; - - PROFILE.end = jiffies; - - st = ncr_delta (PROFILE.start,PROFILE.status); - if (st<0) return; /* status not reached */ - - co = ncr_delta (PROFILE.start,PROFILE.command); - if (co<0) return; /* command not executed */ - - en = ncr_delta (PROFILE.start,PROFILE.end), - di = ncr_delta (PROFILE.start,PROFILE.disconnect), - re = ncr_delta (PROFILE.start,PROFILE.reselect); - post = en - st; - - /* - ** @PROFILE@ Disconnect time invalid if multiple disconnects - */ - - if (di>=0) disc = re - di; else disc = 0; - - work = (st - co) - disc; - - diff = (scr_to_cpu(np->disc_phys) - np->disc_ref) & 0xff; - np->disc_ref += diff; - - np->profile.num_trans += 1; - if (cp->cmd) { - np->profile.num_kbytes += (cp->cmd->request_bufflen >> 10); - np->profile.rest_bytes += (cp->cmd->request_bufflen & (0x400-1)); - if (np->profile.rest_bytes >= 0x400) { - ++np->profile.num_kbytes; - np->profile.rest_bytes -= 0x400; - } - } - np->profile.num_disc += diff; - np->profile.ms_setup += co; - np->profile.ms_data += work; - np->profile.ms_disc += disc; - np->profile.ms_post += post; -} -#undef PROFILE - -#endif /* SCSI_NCR_PROFILE_SUPPORT */ - -/*========================================================== -** -** ** Device lookup. ** ** @GENSCSI@ should be integrated to scsiconf.c @@ -9179,8 +8954,6 @@ uc->cmd = UC_SETDEBUG; else if ((arg_len = is_keyword(ptr, len, "setflag")) != 0) uc->cmd = UC_SETFLAG; - else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0) - uc->cmd = UC_CLEARPROF; else arg_len = 0; @@ -9297,11 +9070,9 @@ #ifdef SCSI_NCR_USER_INFO_SUPPORT /* -** Copy formatted profile information into the input buffer. +** Copy formatted information into the input buffer. */ -#define to_ms(t) ((t) * 1000 / HZ) - static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) { struct info_str info; @@ -9335,20 +9106,6 @@ driver_setup.debug, driver_setup.verbose); } -#ifdef SCSI_NCR_PROFILE_SUPPORT - copy_info(&info, "Profiling information:\n"); - copy_info(&info, " %-12s = %lu\n", "num_trans",np->profile.num_trans); - copy_info(&info, " %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes); - copy_info(&info, " %-12s = %lu\n", "num_disc", np->profile.num_disc); - copy_info(&info, " %-12s = %lu\n", "num_break",np->profile.num_break); - copy_info(&info, " %-12s = %lu\n", "num_int", np->profile.num_int); - copy_info(&info, " %-12s = %lu\n", "num_fly", np->profile.num_fly); - copy_info(&info, " %-12s = %lu\n", "ms_setup", to_ms(np->profile.ms_setup)); - copy_info(&info, " %-12s = %lu\n", "ms_data", to_ms(np->profile.ms_data)); - copy_info(&info, " %-12s = %lu\n", "ms_disc", to_ms(np->profile.ms_disc)); - copy_info(&info, " %-12s = %lu\n", "ms_post", to_ms(np->profile.ms_post)); -#endif - return info.pos > info.offset? info.pos - info.offset : 0; } @@ -9513,5 +9270,10 @@ ** Module stuff */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) static Scsi_Host_Template driver_template = NCR53C8XX; #include "scsi_module.c" +#elif defined(MODULE) +Scsi_Host_Template driver_template = NCR53C8XX; +#include "scsi_module.c" +#endif diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h --- v2.4.2/linux/drivers/scsi/ncr53c8xx.h Mon Sep 18 14:09:49 2000 +++ linux/drivers/scsi/ncr53c8xx.h Tue Mar 6 19:34:25 2001 @@ -50,6 +50,8 @@ ** Used by hosts.c and ncr53c8xx.c with module configuration. */ +#if (LINUX_VERSION_CODE >= 0x020400) || defined(HOSTS_C) || defined(MODULE) + #include int ncr53c8xx_abort(Scsi_Cmnd *); @@ -93,5 +95,7 @@ 0, 0, DISABLE_CLUSTERING} #endif /* LINUX_VERSION_CODE */ + +#endif /* defined(HOSTS_C) || defined(MODULE) */ #endif /* NCR53C8XX_H */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.4.2/linux/drivers/scsi/pci2220i.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/pci2220i.c Fri Mar 2 18:38:39 2001 @@ -2016,7 +2016,7 @@ del_timer (&padapter->timer); if ( status ) { - DEB (printk ("\npci2220i Interupt hanlder return error")); + DEB (printk ("\npci2220i Interrupt handler return error")); zl = DecodeError (padapter, status); } else diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/Config.in linux/drivers/scsi/pcmcia/Config.in --- v2.4.2/linux/drivers/scsi/pcmcia/Config.in Tue Feb 15 08:53:46 2000 +++ linux/drivers/scsi/pcmcia/Config.in Sun Mar 4 14:30:19 2001 @@ -10,13 +10,10 @@ dep_tristate ' Adaptec AHA152X PCMCIA support' CONFIG_PCMCIA_AHA152X m dep_tristate ' Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m dep_tristate ' Future Domain PCMCIA support' CONFIG_PCMCIA_FDOMAIN m - if [ "$CONFIG_CARDBUS" = "y" ]; then - dep_tristate ' Adaptec APA1480 CardBus support' CONFIG_PCMCIA_APA1480 m - fi fi if [ "$CONFIG_PCMCIA_QLOGIC" = "y" -o "$CONFIG_PCMCIA_AHA152X" = "y" -o \ - "$CONFIG_PCMCIA_FDOMAIN" = "y" -o "$CONFIG_PCMCIA_APA1480" = "y" ]; then + "$CONFIG_PCMCIA_FDOMAIN" = "y" ]; then define_bool CONFIG_PCMCIA_SCSICARD y fi diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/Makefile linux/drivers/scsi/pcmcia/Makefile --- v2.4.2/linux/drivers/scsi/pcmcia/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/scsi/pcmcia/Makefile Sun Mar 4 14:30:19 2001 @@ -12,7 +12,6 @@ vpath %c .. CFLAGS_aha152x.o = -DPCMCIA -D__NO_VERSION__ -DAHA152X_STAT -CFLAGS_aic7xxx.o = -DPCMCIA -D__NO_VERSION__ CFLAGS_fdomain.o = -DPCMCIA -D__NO_VERSION__ CFLAGS_qlogicfas.o = -DPCMCIA -D__NO_VERSION__ @@ -21,12 +20,8 @@ obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o -# Cardbus client drivers -obj-$(CONFIG_PCMCIA_APA1480) += apa1480_cb.o - -list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o apa1480_cb.o +list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o aha152x-objs := aha152x_stub.o aha152x.o -apa1480-objs := apa1480_stub.o aic7xxx.o fdomain-objs := fdomain_stub.o fdomain.o qlogic-objs := qlogic_stub.o qlogicfas.o @@ -34,9 +29,6 @@ aha152x_cs.o: $(aha152x-objs) $(LD) -r -o $@ $(aha152x-objs) - -apa1480_cb.o: $(apa1480-objs) - $(LD) -r -o $@ $(apa1480-objs) fdomain_cs.o: $(fdomain-objs) $(LD) -r -o $@ $(fdomain-objs) diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/aha152x_stub.c linux/drivers/scsi/pcmcia/aha152x_stub.c --- v2.4.2/linux/drivers/scsi/pcmcia/aha152x_stub.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/pcmcia/aha152x_stub.c Fri Mar 2 18:38:39 2001 @@ -22,7 +22,7 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which + terms of the GNU General Public License version 2 (the "GPL"), in which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/apa1480_stub.c linux/drivers/scsi/pcmcia/apa1480_stub.c --- v2.4.2/linux/drivers/scsi/pcmcia/apa1480_stub.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/pcmcia/apa1480_stub.c Wed Dec 31 16:00:00 1969 @@ -1,174 +0,0 @@ -/*====================================================================== - - A driver for the Adaptec APA1480 CardBus SCSI Host Adapter - - apa1480_cb.c 1.22 2000/06/12 21:27:25 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include <../drivers/scsi/scsi.h> -#include <../drivers/scsi/hosts.h> -#include -#include <../drivers/scsi/aic7xxx.h> - -#include - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"apa1480_cb.c 1.22 2000/06/12 21:27:25 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int reset = 1; -static int ultra = 0; - -MODULE_PARM(reset, "i"); -MODULE_PARM(ultra, "i"); - -/*====================================================================*/ - -static Scsi_Host_Template driver_template = AIC7XXX; - -extern void aic7xxx_setup(char *, int *); - -static dev_node_t *apa1480_attach(dev_locator_t *loc); -static void apa1480_detach(dev_node_t *node); - -struct driver_operations apa1480_ops = { - "apa1480_cb", apa1480_attach, NULL, NULL, apa1480_detach -}; - -/*====================================================================*/ - -static dev_node_t *apa1480_attach(dev_locator_t *loc) -{ - u_char bus, devfn; - Scsi_Device *dev; - dev_node_t *node; - char s[60]; - int n = 0; - struct Scsi_Host *host; - - if (loc->bus != LOC_PCI) return NULL; - bus = loc->b.pci.bus; devfn = loc->b.pci.devfn; - printk(KERN_INFO "apa1480_attach(bus %d, function %d)\n", - bus, devfn); - - driver_template.module = &__this_module; - - sprintf(s, "no_probe:1,no_reset:%d,ultra:%d", - (reset==0), (ultra!=0)); - aic7xxx_setup(s, NULL); - scsi_register_module(MODULE_SCSI_HA, &driver_template); - - node = kmalloc(7 * sizeof(dev_node_t), GFP_KERNEL); - for (host = scsi_hostlist; host; host = host->next) - if (host->hostt == &driver_template) - for (dev = host->host_queue; dev; dev = dev->next) { - u_long arg[2], id; - kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); - id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + - ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); - node[n].minor = 0; - switch (dev->type) { - case TYPE_TAPE: - node[n].major = SCSI_TAPE_MAJOR; - sprintf(node[n].dev_name, "st#%04lx", id); - break; - case TYPE_DISK: - case TYPE_MOD: - node[n].major = SCSI_DISK0_MAJOR; - sprintf(node[n].dev_name, "sd#%04lx", id); - break; - case TYPE_ROM: - case TYPE_WORM: - node[n].major = SCSI_CDROM_MAJOR; - sprintf(node[n].dev_name, "sr#%04lx", id); - break; - default: - node[n].major = SCSI_GENERIC_MAJOR; - sprintf(node[n].dev_name, "sg#%04lx", id); - break; - } - if (n) node[n-1].next = &node[n]; - n++; - } - if (n == 0) { - printk(KERN_INFO "apa1480_cs: no SCSI devices found\n"); - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); - kfree(node); - return NULL; - } else - node[n-1].next = NULL; - - MOD_INC_USE_COUNT; - return node; -} - -static void apa1480_detach(dev_node_t *node) -{ - MOD_DEC_USE_COUNT; - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); - kfree(node); -} - -/*====================================================================*/ - -static int __init init_apa1480_cb(void) { - DEBUG(0, "%s\n", version); - register_driver(&apa1480_ops); - return 0; -} - -static void __exit exit_apa1480_cb(void) { - DEBUG(0, "apa1480_cs: unloading\n"); - unregister_driver(&apa1480_ops); -} - -module_init(init_apa1480_cb); -module_exit(exit_apa1480_cb); diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/fdomain_stub.c linux/drivers/scsi/pcmcia/fdomain_stub.c --- v2.4.2/linux/drivers/scsi/pcmcia/fdomain_stub.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/pcmcia/fdomain_stub.c Fri Mar 2 18:38:39 2001 @@ -19,7 +19,7 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which + terms of the GNU General Public License version 2 (the "GPL"), in which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/qlogic_stub.c linux/drivers/scsi/pcmcia/qlogic_stub.c --- v2.4.2/linux/drivers/scsi/pcmcia/qlogic_stub.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/pcmcia/qlogic_stub.c Fri Mar 2 18:38:39 2001 @@ -19,7 +19,7 @@ are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which + terms of the GNU General Public License version 2 (the "GPL"), in which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c --- v2.4.2/linux/drivers/scsi/ppa.c Sat Feb 3 19:51:29 2001 +++ linux/drivers/scsi/ppa.c Fri Mar 2 18:38:39 2001 @@ -4,7 +4,7 @@ * (The PPA3 is the embedded controller in the ZIP drive.) * * (c) 1995,1996 Grant R. Guenther, grant@torque.net, - * under the terms of the GNU Public License. + * under the terms of the GNU General Public License. * * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800) * campbell@torque.net @@ -29,7 +29,7 @@ int mode; /* Transfer mode */ int host; /* Host number (for proc) */ Scsi_Cmnd *cur_cmd; /* Current queued command */ - struct tq_struct ppa_tq; /* Polling interupt stuff */ + struct tq_struct ppa_tq; /* Polling interrupt stuff */ unsigned long jstart; /* Jiffies at start */ unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */ unsigned int failed:1; /* Failure flag */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h --- v2.4.2/linux/drivers/scsi/ppa.h Thu Jan 4 13:00:55 2001 +++ linux/drivers/scsi/ppa.h Fri Mar 2 18:38:39 2001 @@ -126,7 +126,7 @@ #define PPA_SELECT_TMO 5000 /* how long to wait for target ? */ #define PPA_SPIN_TMO 50000 /* ppa_wait loop limiter */ #define PPA_RECON_TMO 500 /* scsi reconnection loop limiter */ -#define PPA_DEBUG 0 /* debuging option */ +#define PPA_DEBUG 0 /* debugging option */ #define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32) /* args to ppa_connect */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/psi_dale.h linux/drivers/scsi/psi_dale.h --- v2.4.2/linux/drivers/scsi/psi_dale.h Fri Feb 18 14:50:03 2000 +++ linux/drivers/scsi/psi_dale.h Fri Mar 2 18:38:39 2001 @@ -527,7 +527,7 @@ USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO USHORT Reserved6 :8; // 52 - DMA USHORT DMACycleTime :8; // 52 - DMA - USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild + USHORT Valid_54_58 :1; // 53 words 54 - 58 are valid USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid USHORT Reserved7 :14; // 53 USHORT LogNumCyl; // 54 Current Translation - Num Cyl diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c --- v2.4.2/linux/drivers/scsi/qla1280.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/qla1280.c Tue Mar 6 19:44:37 2001 @@ -810,6 +810,10 @@ #endif /* found a adapter */ host = scsi_register(template, sizeof(scsi_qla_host_t)); + if (!host) { + printk(KERN_WARNING "qla1280: Failed to register host, aborting.\n"); + return 0; + } ha = (scsi_qla_host_t *) host->hostdata; /* Clear our data area */ for( j =0, cp = (char *)ha; j < sizeof(scsi_qla_host_t); j++) @@ -1095,7 +1099,7 @@ CMD_HANDLE(cmd) = (unsigned char *)handle; /* Bookkeeping information */ - sp->r_start = jiffies; /* time the request was recieved */ + sp->r_start = jiffies; /* time the request was received */ sp->u_start = 0; /* add the command to our queue */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.4.2/linux/drivers/scsi/qlogicisp.c Mon Sep 18 13:36:25 2000 +++ linux/drivers/scsi/qlogicisp.c Tue Mar 6 19:44:37 2001 @@ -682,6 +682,9 @@ continue; host = scsi_register(tmpt, sizeof(struct isp1020_hostdata)); + if (!host) + continue; + hostdata = (struct isp1020_hostdata *) host->hostdata; memset(hostdata, 0, sizeof(struct isp1020_hostdata)); @@ -690,7 +693,7 @@ if (isp1020_init(host)) goto fail_and_unregister; - + if (isp1020_reset_hardware(host) #if USE_NVRAM_DEFAULTS || isp1020_get_defaults(host) @@ -698,9 +701,7 @@ || isp1020_set_defaults(host) #endif /* USE_NVRAM_DEFAULTS */ || isp1020_load_parameters(host)) { - iounmap((void *)hostdata->memaddr); - release_region(host->io_port, 0xff); - goto fail_and_unregister; + goto fail_uninit; } host->this_id = hostdata->host_param.initiator_scsi_id; @@ -710,9 +711,7 @@ { printk("qlogicisp : interrupt %d already in use\n", host->irq); - iounmap((void *)hostdata->memaddr); - release_region(host->io_port, 0xff); - goto fail_and_unregister; + goto fail_uninit; } isp_outw(0x0, host, PCI_SEMAPHORE); @@ -722,6 +721,9 @@ hosts++; continue; + fail_uninit: + iounmap((void *)hostdata->memaddr); + release_region(host->io_port, 0xff); fail_and_unregister: if (hostdata->res_cpu) pci_free_consistent(hostdata->pci_dev, @@ -1406,25 +1408,25 @@ sh->io_port = io_base; - if (check_region(sh->io_port, 0xff)) { + if (!request_region(sh->io_port, 0xff, "qlogicisp")) { printk("qlogicisp : i/o region 0x%lx-0x%lx already " "in use\n", sh->io_port, sh->io_port + 0xff); return 1; } - request_region(sh->io_port, 0xff, "qlogicisp"); - if ((command & PCI_COMMAND_MEMORY) && ((mem_flags & 1) == 0)) { mem_base = (u_long) ioremap(mem_base, PAGE_SIZE); + if (!mem_base) { + printk("qlogicisp : i/o remapping failed.\n"); + goto out_release; + } hostdata->memaddr = mem_base; } else { - if (command & PCI_COMMAND_IO && (io_flags & 3) != 1) - { - printk("qlogicisp : i/o mapping is disabled\n"); - release_region(sh->io_port, 0xff); - return 1; + if (command & PCI_COMMAND_IO && (io_flags & 3) != 1) { + printk("qlogicisp : i/o mapping is disabled\n"); + goto out_release; } hostdata->memaddr = 0; /* zero to signify no i/o mapping */ mem_base = 0; @@ -1439,9 +1441,7 @@ printk("qlogicisp : can't decode %s address space 0x%lx\n", (io_base ? "I/O" : "MEM"), (io_base ? io_base : mem_base)); - iounmap((void *)hostdata->memaddr); - release_region(sh->io_port, 0xff); - return 1; + goto out_unmap; } hostdata->revision = revision; @@ -1455,7 +1455,7 @@ &hostdata->res_dma); if (hostdata->res_cpu == NULL) { printk("qlogicisp : can't allocate response queue\n"); - return 1; + goto out_unmap; } hostdata->req_cpu = pci_alloc_consistent(hostdata->pci_dev, @@ -1467,12 +1467,18 @@ hostdata->res_cpu, hostdata->res_dma); printk("qlogicisp : can't allocate request queue\n"); - return 1; + goto out_unmap; } LEAVE("isp1020_init"); return 0; + +out_unmap: + iounmap((void *)hostdata->memaddr); +out_release: + release_region(sh->io_port, 0xff); + return 1; } diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.4.2/linux/drivers/scsi/scsi_error.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/scsi_error.c Sun Mar 4 14:30:27 2001 @@ -492,31 +492,20 @@ { static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; - unsigned char scsi_result0[256], *scsi_result = NULL; memcpy((void *) SCpnt->cmnd, (void *) tur_command, sizeof(tur_command)); SCpnt->cmnd[1] = SCpnt->lun << 5; - scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma) - ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA); - - if (scsi_result == NULL) { - printk("cannot allocate scsi_result in scsi_test_unit_ready.\n"); - return FAILED; - } /* - * Zero the sense buffer. Some host adapters automatically always request - * sense, so it is not a good idea that SCpnt->request_buffer and - * SCpnt->sense_buffer point to the same address (DB). - * 0 is not a valid sense code. + * Zero the sense buffer. The SCSI spec mandates that any + * untransferred sense data should be interpreted as being zero. */ memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); - memset((void *) scsi_result, 0, 256); - SCpnt->request_buffer = scsi_result; - SCpnt->request_bufflen = 256; + SCpnt->request_buffer = NULL; + SCpnt->request_bufflen = 0; SCpnt->use_sg = 0; SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); SCpnt->underflow = 0; @@ -524,15 +513,6 @@ scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); - /* Last chance to have valid sense data */ - if (!scsi_sense_valid(SCpnt)) - memcpy((void *) SCpnt->sense_buffer, - SCpnt->request_buffer, - sizeof(SCpnt->sense_buffer)); - - if (scsi_result != &scsi_result0[0] && scsi_result != NULL) - kfree(scsi_result); - /* * When we eventually call scsi_finish, we really wish to complete * the original request, so let's restore the original data. (DB) @@ -549,6 +529,9 @@ /* * Hey, we are done. Let's look to see what happened. */ + SCSI_LOG_ERROR_RECOVERY(3, + printk("scsi_test_unit_ready: SCpnt %p eh_state %x\n", + SCpnt, SCpnt->eh_state)); return SCpnt->eh_state; } @@ -671,11 +654,8 @@ spin_unlock_irqrestore(&io_request_lock, flags); SCpnt->result = temp; - if (scsi_eh_completed_normally(SCpnt)) { - SCpnt->eh_state = SUCCESS; - } else { - SCpnt->eh_state = FAILED; - } + /* Fall through to code below to examine status. */ + SCpnt->eh_state = SUCCESS; } /* @@ -683,7 +663,10 @@ * did complete normally. */ if (SCpnt->eh_state == SUCCESS) { - switch (scsi_eh_completed_normally(SCpnt)) { + int ret = scsi_eh_completed_normally(SCpnt); + SCSI_LOG_ERROR_RECOVERY(3, + printk("scsi_send_eh_cmnd: scsi_eh_completed_normally %x\n", ret)); + switch (ret) { case SUCCESS: SCpnt->eh_state = SUCCESS; break; @@ -1104,7 +1087,6 @@ */ STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt) { - int rtn; /* * First check the host byte, to see if there is anything in there * that would indicate what we need to do. @@ -1144,11 +1126,7 @@ case COMMAND_TERMINATED: return SUCCESS; case CHECK_CONDITION: - rtn = scsi_check_sense(SCpnt); - if (rtn == NEEDS_RETRY) { - return FAILED; - } - return rtn; + return scsi_check_sense(SCpnt); case CONDITION_GOOD: case INTERMEDIATE_GOOD: case INTERMEDIATE_C_GOOD: @@ -1634,8 +1612,10 @@ * FIXME(eric) - is this really the correct thing to do? */ if (rtn != SUCCESS) { - SCloop->device->online = FALSE; - SCloop->host->host_failed--; + printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after bus reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); + + SDloop->online = FALSE; + SDloop->host->host_failed--; scsi_eh_finish_command(&SCdone, SCloop); } } @@ -1725,8 +1705,9 @@ } } if (rtn != SUCCESS) { - SCloop->device->online = FALSE; - SCloop->host->host_failed--; + printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after host reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); + SDloop->online = FALSE; + SDloop->host->host_failed--; scsi_eh_finish_command(&SCdone, SCloop); } } @@ -1753,7 +1734,11 @@ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) { if (SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT) { - SCloop->device->online = FALSE; + SDloop = SCloop->device; + if (SDloop->online == TRUE) { + printk(KERN_INFO "scsi: device set offline - command error recover failed: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); + SDloop->online = FALSE; + } /* * This should pass the failure up to the top level driver, and @@ -1765,7 +1750,7 @@ SCloop->result |= (DRIVER_TIMEOUT << 24); } SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command for device %d %x\n", - SCloop->device->id, SCloop->result)); + SDloop->id, SCloop->result)); scsi_eh_finish_command(&SCdone, SCloop); } diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.4.2/linux/drivers/scsi/scsi_lib.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/scsi_lib.c Fri Mar 2 18:38:39 2001 @@ -549,7 +549,7 @@ * number of sectors. If we are done, the command block will * be released, and the queue function will be goosed. If we * are not done, then scsi_end_request will directly goose - * the the queue. + * the queue. * * We can just use scsi_queue_next_request() here. This * would be used if we just wanted to retry, for example. diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sun3_scsi.c linux/drivers/scsi/sun3_scsi.c --- v2.4.2/linux/drivers/scsi/sun3_scsi.c Fri Dec 29 14:07:22 2000 +++ linux/drivers/scsi/sun3_scsi.c Fri Mar 2 18:38:39 2001 @@ -34,7 +34,7 @@ /* - * This is from mac_scsi.h, but hey, maybe this is usefull for Sun3 too! :) + * This is from mac_scsi.h, but hey, maybe this is useful for Sun3 too! :) * * Options : * @@ -118,7 +118,7 @@ /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */ #define SUN3_DVMA_BUFSIZE 0xe000 -/* minimum number of bytes to to dma on */ +/* minimum number of bytes to do dma on */ #define SUN3_DMA_MINSIZE 128 static volatile unsigned char *sun3_scsi_regp; diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sun3x_esp.c linux/drivers/scsi/sun3x_esp.c --- v2.4.2/linux/drivers/scsi/sun3x_esp.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/sun3x_esp.c Tue Mar 6 19:44:37 2001 @@ -103,7 +103,11 @@ sizeof (cmd_buffer)); esp->irq = 2; - request_irq(esp->irq, esp_intr, SA_INTERRUPT, "SUN3X SCSI", NULL); + if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, + "SUN3X SCSI", NULL)) { + esp_deallocate(esp); + return 0; + } esp->scsi_id = 7; esp->diff = 0; diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c --- v2.4.2/linux/drivers/scsi/sym53c416.c Sat Nov 11 19:01:11 2000 +++ linux/drivers/scsi/sym53c416.c Tue Mar 6 19:44:37 2001 @@ -183,14 +183,10 @@ #define sym53c416_base_2 sym53c416_2 #define sym53c416_base_3 sym53c416_3 -static unsigned short sym53c416_base = 0; -static unsigned int sym53c416_irq = 0; -static unsigned short sym53c416_base_1 = 0; -static unsigned int sym53c416_irq_1 = 0; -static unsigned short sym53c416_base_2 = 0; -static unsigned int sym53c416_irq_2 = 0; -static unsigned short sym53c416_base_3 = 0; -static unsigned int sym53c416_irq_3 = 0; +static unsigned int sym53c416_base[2] = {0,0}; +static unsigned int sym53c416_base_1[2] = {0,0}; +static unsigned int sym53c416_base_2[2] = {0,0}; +static unsigned int sym53c416_base_3[2] = {0,0}; #endif @@ -636,26 +632,26 @@ ints[0] = 2; if(sym53c416_base) { - ints[1] = sym53c416_base; - ints[2] = sym53c416_irq; + ints[1] = sym53c416_base[0]; + ints[2] = sym53c416_base[1]; sym53c416_setup(NULL, ints); } if(sym53c416_base_1) { - ints[1] = sym53c416_base_1; - ints[2] = sym53c416_irq_1; + ints[1] = sym53c416_base_1[0]; + ints[2] = sym53c416_base_1[1]; sym53c416_setup(NULL, ints); } if(sym53c416_base_2) { - ints[1] = sym53c416_base_2; - ints[2] = sym53c416_irq_2; + ints[1] = sym53c416_base_2[0]; + ints[2] = sym53c416_base_2[1]; sym53c416_setup(NULL, ints); } if(sym53c416_base_3) { - ints[1] = sym53c416_base_3; - ints[2] = sym53c416_irq_3; + ints[1] = sym53c416_base_3[0]; + ints[2] = sym53c416_base_3[1]; sym53c416_setup(NULL, ints); } #endif diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- v2.4.2/linux/drivers/scsi/sym53c8xx.c Wed Feb 21 18:20:33 2001 +++ linux/drivers/scsi/sym53c8xx.c Tue Mar 6 19:34:25 2001 @@ -55,8 +55,6 @@ */ /* -** May 11 2000, sym53c8xx 1.6b -** ** Supported SCSI features: ** Synchronous data transfers ** Wide16 SCSI BUS @@ -87,11 +85,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.6b" - -/* #define DEBUG_896R1 */ -#define SCSI_NCR_OPTIMIZE_896 -/* #define SCSI_NCR_OPTIMIZE_896_1 */ +#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.3a-20010304" #define SCSI_NCR_DEBUG_FLAGS (0) @@ -107,7 +101,6 @@ #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) -#include #ifdef MODULE #include #endif @@ -126,7 +119,6 @@ #include #include #include -#include #include #include #include @@ -182,7 +174,8 @@ ** Donnot compile integrity checking code for Linux-2.3.0 ** and above since SCSI data structures are not ready yet. */ -#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) +/* #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) */ +#if 0 #define SCSI_NCR_INTEGRITY_CHECKING #endif @@ -290,33 +283,6 @@ /*========================================================== ** -** On x86 architecture, write buffers management does -** not reorder writes to memory. So, using compiler -** optimization barriers is enough to guarantee some -** ordering when the CPU is writing data accessed by -** the NCR. -** On Alpha architecture, explicit memory barriers have -** to be used. -** Other architectures are defaulted to mb() macro if -** defined, otherwise use compiler barrier. -** -**========================================================== -*/ - -#if defined(__i386__) -#define MEMORY_BARRIER() barrier() -#elif defined(__alpha__) -#define MEMORY_BARRIER() mb() -#else -# ifdef mb -# define MEMORY_BARRIER() mb() -# else -# define MEMORY_BARRIER() barrier() -# endif -#endif - -/*========================================================== -** ** Configuration and Debugging ** **========================================================== @@ -437,14 +403,6 @@ #define SCR_SG_SIZE (2) /* -** Io mapped or memory mapped. -*/ - -#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED) -#define NCR_IOMAPPED -#endif - -/* ** other */ @@ -495,30 +453,42 @@ #define PciDeviceId(d) (d)->device #define PciIrqLine(d) (d)->irq -#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) - -static int __init -pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) +static u_long __init +pci_get_base_cookie(struct pci_dev *pdev, int index) { - *base = pdev->resource[index].start; - if ((pdev->resource[index].flags & 0x7) == 0x4) - ++index; - return ++index; -} + u_long base; + +#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) + base = pdev->resource[index].start; #else -static int __init + base = pdev->base_address[index]; +#if BITS_PER_LONG > 32 + if ((base & 0x7) == 0x4) + *base |= (((u_long)pdev->base_address[++index]) << 32); +#endif +#endif + return (base & ~0x7ul); +} + +static int __init pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) { - *base = pdev->base_address[index++]; - if ((*base & 0x7) == 0x4) { + u32 tmp; +#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2)) + + pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp); + *base = tmp; + ++index; + if ((tmp & 0x7) == 0x4) { #if BITS_PER_LONG > 32 - *base |= (((u_long)pdev->base_address[index]) << 32); + pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp); + *base |= (((u_long)tmp) << 32); #endif ++index; } return index; +#undef PCI_BAR_OFFSET } -#endif #else /* Incomplete emulation of current PCI code for pre-2.2 kernels */ @@ -598,9 +568,23 @@ } return offset; } +static u_long __init +pci_get_base_cookie(struct pci_dev *pdev, int offset) +{ + u_long base; + + (void) pci_get_base_address(dev, offset, &base); + + return base; +} #endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */ +/* Does not make sense in earlier kernels */ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) +#define pci_enable_device(pdev) (0) +#endif + /*========================================================== ** ** Debugging tags @@ -694,16 +678,10 @@ #ifdef __sparc__ # include -# define pcivtobus(p) bus_dvma_to_mem(p) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #elif defined(__alpha__) -# define pcivtobus(p) ((p) & 0xfffffffful) -# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) -#elif defined(CONFIG_PPC) -# define pcivtobus(p) phys_to_bus(p) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #else /* others */ -# define pcivtobus(p) (p) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #endif @@ -1383,6 +1361,8 @@ u_long base; u_long base_2; u_long io_port; + u_long base_c; + u_long base_2_c; int irq; /* port and reg fields to use INB, OUTB macros */ u_long base_io; @@ -1439,175 +1419,6 @@ /*========================================================== ** -** Big/Little endian support. -** -**========================================================== -*/ - -/* -** If the NCR uses big endian addressing mode over the -** PCI, actual io register addresses for byte and word -** accesses must be changed according to lane routing. -** Btw, ncr_offb() and ncr_offw() macros only apply to -** constants and so donnot generate bloated code. -*/ - -#if defined(SCSI_NCR_BIG_ENDIAN) - -#define ncr_offb(o) (((o)&~3)+((~((o)&3))&3)) -#define ncr_offw(o) (((o)&~3)+((~((o)&3))&2)) - -#else - -#define ncr_offb(o) (o) -#define ncr_offw(o) (o) - -#endif - -/* -** If the CPU and the NCR use same endian-ness adressing, -** no byte reordering is needed for script patching. -** Macro cpu_to_scr() is to be used for script patching. -** Macro scr_to_cpu() is to be used for getting a DWORD -** from the script. -*/ - -#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) - -#define cpu_to_scr(dw) cpu_to_le32(dw) -#define scr_to_cpu(dw) le32_to_cpu(dw) - -#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) - -#define cpu_to_scr(dw) cpu_to_be32(dw) -#define scr_to_cpu(dw) be32_to_cpu(dw) - -#else - -#define cpu_to_scr(dw) (dw) -#define scr_to_cpu(dw) (dw) - -#endif - -/*========================================================== -** -** Access to the controller chip. -** -** If NCR_IOMAPPED is defined, the driver will use -** normal IOs instead of the MEMORY MAPPED IO method -** recommended by PCI specifications. -** If all PCI bridges, host brigdes and architectures -** would have been correctly designed for PCI, this -** option would be useless. -** -**========================================================== -*/ - -/* -** If the CPU and the NCR use same endian-ness adressing, -** no byte reordering is needed for accessing chip io -** registers. Functions suffixed by '_raw' are assumed -** to access the chip over the PCI without doing byte -** reordering. Functions suffixed by '_l2b' are -** assumed to perform little-endian to big-endian byte -** reordering, those suffixed by '_b2l' blah, blah, -** blah, ... -*/ - -#if defined(NCR_IOMAPPED) - -/* -** IO mapped only input / ouput -*/ - -#define INB_OFF(o) inb (np->base_io + ncr_offb(o)) -#define OUTB_OFF(o, val) outb ((val), np->base_io + ncr_offb(o)) - -#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) inw_l2b (np->base_io + ncr_offw(o)) -#define INL_OFF(o) inl_l2b (np->base_io + (o)) - -#define OUTW_OFF(o, val) outw_b2l ((val), np->base_io + ncr_offw(o)) -#define OUTL_OFF(o, val) outl_b2l ((val), np->base_io + (o)) - -#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) inw_b2l (np->base_io + ncr_offw(o)) -#define INL_OFF(o) inl_b2l (np->base_io + (o)) - -#define OUTW_OFF(o, val) outw_l2b ((val), np->base_io + ncr_offw(o)) -#define OUTL_OFF(o, val) outl_l2b ((val), np->base_io + (o)) - -#else - -#define INW_OFF(o) inw_raw (np->base_io + ncr_offw(o)) -#define INL_OFF(o) inl_raw (np->base_io + (o)) - -#define OUTW_OFF(o, val) outw_raw ((val), np->base_io + ncr_offw(o)) -#define OUTL_OFF(o, val) outl_raw ((val), np->base_io + (o)) - -#endif /* ENDIANs */ - -#else /* defined NCR_IOMAPPED */ - -/* -** MEMORY mapped IO input / output -*/ - -#define INB_OFF(o) readb((char *)np->reg + ncr_offb(o)) -#define OUTB_OFF(o, val) writeb((val), (char *)np->reg + ncr_offb(o)) - -#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) readw_l2b((char *)np->reg + ncr_offw(o)) -#define INL_OFF(o) readl_l2b((char *)np->reg + (o)) - -#define OUTW_OFF(o, val) writew_b2l((val), (char *)np->reg + ncr_offw(o)) -#define OUTL_OFF(o, val) writel_b2l((val), (char *)np->reg + (o)) - -#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) readw_b2l((char *)np->reg + ncr_offw(o)) -#define INL_OFF(o) readl_b2l((char *)np->reg + (o)) - -#define OUTW_OFF(o, val) writew_l2b((val), (char *)np->reg + ncr_offw(o)) -#define OUTL_OFF(o, val) writel_l2b((val), (char *)np->reg + (o)) - -#else - -#define INW_OFF(o) readw_raw((char *)np->reg + ncr_offw(o)) -#define INL_OFF(o) readl_raw((char *)np->reg + (o)) - -#define OUTW_OFF(o, val) writew_raw((val), (char *)np->reg + ncr_offw(o)) -#define OUTL_OFF(o, val) writel_raw((val), (char *)np->reg + (o)) - -#endif - -#endif /* defined NCR_IOMAPPED */ - -#define INB(r) INB_OFF (offsetof(struct ncr_reg,r)) -#define INW(r) INW_OFF (offsetof(struct ncr_reg,r)) -#define INL(r) INL_OFF (offsetof(struct ncr_reg,r)) - -#define OUTB(r, val) OUTB_OFF (offsetof(struct ncr_reg,r), (val)) -#define OUTW(r, val) OUTW_OFF (offsetof(struct ncr_reg,r), (val)) -#define OUTL(r, val) OUTL_OFF (offsetof(struct ncr_reg,r), (val)) - -/* -** Set bit field ON, OFF -*/ - -#define OUTONB(r, m) OUTB(r, INB(r) | (m)) -#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m)) -#define OUTONW(r, m) OUTW(r, INW(r) | (m)) -#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m)) -#define OUTONL(r, m) OUTL(r, INL(r) | (m)) -#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m)) - - -/*========================================================== -** ** Command control block states. ** **========================================================== @@ -1657,7 +1468,9 @@ #define SIR_MSG_OUT_DONE (19) #define SIR_AUTO_SENSE_DONE (20) #define SIR_DUMMY_INTERRUPT (21) -#define SIR_MAX (21) +#define SIR_DATA_OVERRUN (22) +#define SIR_BAD_PHASE (23) +#define SIR_MAX (23) /*========================================================== ** @@ -1757,7 +1570,6 @@ #define UC_SETORDER 13 #define UC_SETWIDE 14 #define UC_SETFLAG 15 -#define UC_CLEARPROF 16 #define UC_SETVERBOSE 17 #define UC_RESETDEV 18 #define UC_CLEARDEV 19 @@ -1766,29 +1578,6 @@ #define UF_NODISC (0x02) #define UF_NOSCAN (0x04) -#ifdef SCSI_NCR_PROFILE_SUPPORT -/* -** profiling data (per host) -*/ - -struct profile { - u_long num_trans; - u_long num_disc; - u_long num_disc0; - u_long num_break; - u_long num_int; - u_long num_fly; - u_long num_kbytes; -#if 000 - u_long num_br1k; - u_long num_br2k; - u_long num_br4k; - u_long num_br8k; - u_long num_brnk; -#endif -}; -#endif - /*======================================================================== ** ** Declaration of structs: target control block @@ -1831,26 +1620,20 @@ ccb_p nego_cp; /*---------------------------------------------------------------- - ** statistical data - **---------------------------------------------------------------- - */ - u_long transfers; - u_long bytes; - - /*---------------------------------------------------------------- ** negotiation of wide and synch transfer and device quirks. ** sval, wval and uval are read from SCRIPTS and so have alignment ** constraints. **---------------------------------------------------------------- */ -/*0*/ u_char minsync; +/*0*/ u_char uval; /*1*/ u_char sval; -/*2*/ u_short period; -/*0*/ u_char maxoffs; -/*1*/ u_char quirks; -/*2*/ u_char widedone; +/*2*/ u_char filler2; /*3*/ u_char wval; -/*0*/ u_char uval; + u_short period; + u_char minsync; + u_char maxoffs; + u_char quirks; + u_char widedone; #ifdef SCSI_NCR_INTEGRITY_CHECKING u_char ic_min_sync; @@ -2016,7 +1799,6 @@ ** Status fields. **---------------------------------------------------------------- */ - u_char scr_st[4]; /* script status */ u_char status[4]; /* host status */ }; @@ -2035,18 +1817,10 @@ /* ** The status bytes are used by the host and the script processor. ** -** The last four bytes (status[4]) are copied to the scratchb register +** The four bytes (status[4]) are copied to the scratchb register ** (declared as scr0..scr3 in ncr_reg.h) just after the select/reselect, ** and copied back just after disconnecting. ** Inside the script the XX_REG are used. -** -** The first four bytes (scr_st[4]) are used inside the script by -** "LOAD/STORE" commands. -** Because source and destination must have the same alignment -** in a DWORD, the fields HAVE to be at the choosen offsets. -** xerr_st 0 (0x34) scratcha -** sync_st 1 (0x05) sxfer -** wide_st 3 (0x03) scntl3 */ /* @@ -2089,20 +1863,6 @@ */ #define HF_DATA_ST (1u<<7) -/* -** First four bytes (script) -*/ -#define xerr_st header.scr_st[0] -#define sync_st header.scr_st[1] -#define nego_st header.scr_st[2] -#define wide_st header.scr_st[3] - -/* -** First four bytes (host) -*/ -#define xerr_status phys.xerr_st -#define nego_status phys.nego_st - /*========================================================== ** ** Declaration of structs: Data structure block @@ -2147,19 +1907,6 @@ struct pm_ctx pm0; struct pm_ctx pm1; - - /* - ** Extra bytes count transferred - ** in case of data overrun. - */ - u_int32 extra_bytes; - -#ifdef SCSI_NCR_PROFILE_SUPPORT - /* - ** Disconnection counter - */ - u_int32 num_disc; -#endif }; @@ -2199,8 +1946,16 @@ ** a SDTR or WDTR message is appended. **---------------------------------------------------------------- */ - u_char scsi_smsg [8]; - u_char scsi_smsg2[8]; + u_char scsi_smsg [12]; + u_char scsi_smsg2[12]; + + /*---------------------------------------------------------------- + ** Miscellaneous status'. + **---------------------------------------------------------------- + */ + u_char nego_status; /* Negotiation status */ + u_char xerr_status; /* Extended error flags */ + u_int32 extra_bytes; /* Extraneous bytes transferred */ /*---------------------------------------------------------------- ** Saved info for auto-sense @@ -2365,6 +2120,7 @@ u_char minsync; /* Minimum sync period factor */ u_char maxsync; /* Maximum sync period factor */ u_char maxoffs; /* Max scsi offset */ + u_char maxoffs_st; /* Max scsi offset in ST mode */ u_char multiplier; /* Clock multiplier (1,2,4) */ u_char clock_divn; /* Number of clock divisors */ u_long clock_khz; /* SCSI clock frequency in KHz */ @@ -2414,9 +2170,6 @@ */ struct ncr_reg regdump; /* Register dump */ u_long regtime; /* Time it has been done */ -#ifdef SCSI_NCR_PROFILE_SUPPORT - struct profile profile; /* Profiling data */ -#endif /*---------------------------------------------------------------- ** Miscellaneous buffers accessed by the scripts-processor. @@ -2496,7 +2249,7 @@ **---------------------------------------------------------------- */ struct usrcmd user; /* Command from user */ - u_char release_stage; /* Synchronisation stage on release */ + volatile u_char release_stage; /* Synchronisation stage on release */ /*---------------------------------------------------------------- ** Fields that are used (primarily) for integrity check @@ -2553,7 +2306,7 @@ ncrcmd select2 [ 2]; #endif ncrcmd command [ 2]; - ncrcmd dispatch [ 30]; + ncrcmd dispatch [ 28]; ncrcmd sel_no_cmd [ 10]; ncrcmd init [ 6]; ncrcmd clrack [ 4]; @@ -2561,11 +2314,7 @@ ncrcmd datai_done [ 26]; ncrcmd datao_done [ 12]; ncrcmd ign_i_w_r_msg [ 4]; -#ifdef SCSI_NCR_PROFILE_SUPPORT - ncrcmd datai_phase [ 4]; -#else ncrcmd datai_phase [ 2]; -#endif ncrcmd datao_phase [ 4]; ncrcmd msg_in [ 2]; ncrcmd msg_in2 [ 10]; @@ -2588,11 +2337,7 @@ ncrcmd done_end [ 2]; ncrcmd save_dp [ 8]; ncrcmd restore_dp [ 4]; -#ifdef SCSI_NCR_PROFILE_SUPPORT - ncrcmd disconnect [ 32]; -#else ncrcmd disconnect [ 20]; -#endif #ifdef SCSI_NCR_IARB_SUPPORT ncrcmd idle [ 4]; #else @@ -2657,8 +2402,9 @@ ncrcmd nego_bad_phase [ 4]; ncrcmd msg_out [ 4]; ncrcmd msg_out_done [ 4]; - ncrcmd data_ovrun [ 18]; - ncrcmd data_ovrun1 [ 20]; + ncrcmd data_ovrun [ 2]; + ncrcmd data_ovrun1 [ 22]; + ncrcmd data_ovrun2 [ 8]; ncrcmd abort_resel [ 16]; ncrcmd resend_ident [ 4]; ncrcmd ident_break [ 4]; @@ -2745,9 +2491,6 @@ #ifdef SCSI_NCR_INTEGRITY_CHECKING static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr); #endif -#ifdef SCSI_NCR_PROFILE_SUPPORT -static void ncb_profile (ncb_p np, ccb_p cp); -#endif static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); static void ncr_script_fill (struct script * scr, struct scripth * scripth); @@ -3039,31 +2782,25 @@ SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), PADDRH (msg_out), /* - * Set the extended error flag. + * Discard as many illegal phases as + * required and tell the C code about. */ - SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR), - 0, - - /* - ** Discard one illegal phase byte, if required. - */ - SCR_LOAD_REL (scratcha, 1), - offsetof (struct ccb, xerr_status), - SCR_REG_REG (scratcha, SCR_OR, XE_BAD_PHASE), - 0, - SCR_STORE_REL (scratcha, 1), - offsetof (struct ccb, xerr_status), - SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)), - 8, + SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)), + 16, SCR_MOVE_ABS (1) ^ SCR_ILG_OUT, NADDR (scratch), - SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)), - 8, + SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)), + -16, + SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)), + 16, SCR_MOVE_ABS (1) ^ SCR_ILG_IN, NADDR (scratch), + SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)), + -16, + SCR_INT, + SIR_BAD_PHASE, SCR_JUMP, PADDR (dispatch), - }/*---------------------< SEL_NO_CMD >----------------------*/,{ /* ** The target does not switch to command @@ -3230,10 +2967,6 @@ PADDR (clrack), }/*-------------------------< DATAI_PHASE >------------------*/,{ -#ifdef SCSI_NCR_PROFILE_SUPPORT - SCR_REG_REG (QU_REG, SCR_OR, HF_DATA_ST), - 0, -#endif SCR_RETURN, 0, }/*-------------------------< DATAO_PHASE >------------------*/,{ @@ -3478,25 +3211,6 @@ */ SCR_WAIT_DISC, 0, -#ifdef SCSI_NCR_PROFILE_SUPPORT - /* - ** Count the disconnects. - ** Disconnect without DATA PHASE having been - ** entered are counted in bits 8..15. - */ - SCR_LOAD_REL (scratcha, 4), - offsetof (struct ccb, phys.num_disc), - SCR_FROM_REG (QU_REG), - 0, - SCR_JUMPR ^ IFTRUE (MASK (HF_DATA_ST, HF_DATA_ST)), - 8, - SCR_REG_REG (scratcha1, SCR_ADD, 0x01), - 0, - SCR_REG_REG (scratcha, SCR_ADD, 0x01), - 0, - SCR_STORE_REL (scratcha, 4), - offsetof (struct ccb, phys.num_disc), -#endif /* ** Status is: DISCONNECTED. */ @@ -4226,7 +3940,13 @@ SCR_JUMP, PADDR (dispatch), -}/*-------------------------< DATA_OVRUN >--------------------*/,{ +}/*-------------------------< DATA_OVRUN >-----------------------*/,{ + /* + * Use scratcha to count the extra bytes. + */ + SCR_LOAD_ABS (scratcha, 4), + PADDRH (zero), +}/*-------------------------< DATA_OVRUN1 >----------------------*/,{ /* * The target may want to transfer too much data. * @@ -4237,7 +3957,7 @@ SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT, NADDR (scratch), SCR_JUMP, - PADDRH (data_ovrun1), + PADDRH (data_ovrun2), /* * If WSR is set, clear this condition, and * count this byte. @@ -4249,48 +3969,38 @@ SCR_REG_REG (scntl2, SCR_OR, WSR), 0, SCR_JUMP, - PADDRH (data_ovrun1), + PADDRH (data_ovrun2), /* * Finally check against DATA IN phase. - * Jump to dispatcher if not so. + * Signal data overrun to the C code + * and jump to dispatcher if not so. * Read 1 byte otherwise and count it. */ - SCR_JUMP ^ IFFALSE (IF (SCR_DATA_IN)), + SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)), + 16, + SCR_INT, + SIR_DATA_OVERRUN, + SCR_JUMP, PADDR (dispatch), SCR_CHMOV_ABS (1) ^ SCR_DATA_IN, NADDR (scratch), -}/*-------------------------< DATA_OVRUN1 >--------------------*/,{ - /* - * Set the extended error flag. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR), - 0, - SCR_LOAD_REL (scratcha, 1), - offsetof (struct ccb, xerr_status), - SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA), - 0, - SCR_STORE_REL (scratcha, 1), - offsetof (struct ccb, xerr_status), +}/*-------------------------< DATA_OVRUN2 >----------------------*/,{ /* * Count this byte. * This will allow to return a negative * residual to user. */ - SCR_LOAD_REL (scratcha, 4), - offsetof (struct ccb, phys.extra_bytes), SCR_REG_REG (scratcha, SCR_ADD, 0x01), 0, SCR_REG_REG (scratcha1, SCR_ADDC, 0), 0, SCR_REG_REG (scratcha2, SCR_ADDC, 0), 0, - SCR_STORE_REL (scratcha, 4), - offsetof (struct ccb, phys.extra_bytes), /* * .. and repeat as required. */ SCR_JUMP, - PADDRH (data_ovrun), + PADDRH (data_ovrun1), }/*-------------------------< ABORT_RESEL >----------------*/,{ SCR_SET (SCR_ATN), @@ -4962,7 +4672,7 @@ switch (old & RELOC_MASK) { case RELOC_REGISTER: - new = (old & ~RELOC_MASK) + pcivtobus(np->base_ba); + new = (old & ~RELOC_MASK) + np->base_ba; break; case RELOC_LABEL: new = (old & ~RELOC_MASK) + np->p_script; @@ -5207,11 +4917,19 @@ np->maxwide = (np->features & FE_WIDE)? 1 : 0; - /* - ** Get the frequency of the chip's clock. - ** Find the right value for scntl3. - */ + /* + * Guess the frequency of the chip's clock. + */ + if (np->features & (FE_ULTRA3 | FE_ULTRA2)) + np->clock_khz = 160000; + else if (np->features & FE_ULTRA) + np->clock_khz = 80000; + else + np->clock_khz = 40000; + /* + * Get the clock multiplier factor. + */ if (np->features & FE_QUAD) np->multiplier = 4; else if (np->features & FE_DBLR) @@ -5219,10 +4937,11 @@ else np->multiplier = 1; - np->clock_khz = (np->features & FE_CLK80)? 80000 : 40000; - np->clock_khz *= np->multiplier; - - if (np->clock_khz != 40000) + /* + * Measure SCSI clock frequency for chips + * it may vary from assumed one. + */ + if (np->features & FE_VARCLK) ncr_getclock(np, np->multiplier); /* @@ -5271,10 +4990,17 @@ /* * Fix up. If sync. factor is 10 (160000Khz clock) and chip * supports ultra3, then min. sync. period 12.5ns and the factor is 9 + * Also keep track of the maximum offset in ST mode which may differ + * from the maximum offset in DT mode. For now hardcoded to 31. */ - if ((np->minsync == 10) && (np->features & FE_ULTRA3)) - np->minsync = 9; + if (np->features & FE_ULTRA3) { + if (np->minsync == 10) + np->minsync = 9; + np->maxoffs_st = 31; + } + else + np->maxoffs_st = np->maxoffs; /* * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). @@ -5302,7 +5028,7 @@ /* ** 64 bit (53C895A or 53C896) ? */ - if (np->features & FE_64BIT) + if (np->features & FE_DAC) #ifdef SCSI_NCR_USE_64BIT_DAC np->rv_ccntl1 |= (XTIMOD | EXTIBMV); #else @@ -5373,7 +5099,7 @@ np->rv_dmode |= BOF; /* Burst Opcode Fetch */ if (np->features & FE_ERMP) np->rv_dmode |= ERMP; /* Enable Read Multiple */ -#ifdef SCSI_NCR_OPTIMIZE_896 +#if 1 if ((np->features & FE_PFEN) && !np->base2_ba) #else if (np->features & FE_PFEN) @@ -5785,8 +5511,8 @@ np->base_ws = (np->features & FE_IO256)? 256 : 128; np->base2_ba = (np->features & FE_RAM)? device->slot.base_2 : 0; -#ifndef NCR_IOMAPPED - np->base_va = remap_pci_mem(np->base_ba, np->base_ws); +#ifndef SCSI_NCR_IOMAPPED + np->base_va = remap_pci_mem(device->slot.base_c, np->base_ws); if (!np->base_va) { printk(KERN_ERR "%s: can't map PCI MMIO region\n",ncr_name(np)); goto attach_error; @@ -5802,7 +5528,7 @@ np->reg = (struct ncr_reg *) np->base_va; -#endif /* !defined NCR_IOMAPPED */ +#endif /* !defined SCSI_NCR_IOMAPPED */ /* ** If on-chip RAM is used, make sure SCRIPTS isn't too large. @@ -5917,7 +5643,7 @@ np->p_scripth0 = np->p_scripth; if (np->base2_ba) { - np->p_script = pcivtobus(np->base2_ba); + np->p_script = np->base2_ba; if (np->features & FE_RAM8K) { np->base2_ws = 8192; np->p_scripth = np->p_script + 4096; @@ -5928,7 +5654,8 @@ else np->base2_ws = 4096; #ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED - np->base2_va = remap_pci_mem(np->base2_ba, np->base2_ws); + np->base2_va = + remap_pci_mem(device->slot.base_2_c, np->base2_ws); if (!np->base2_va) { printk(KERN_ERR "%s: can't map PCI MEMORY region\n", ncr_name(np)); @@ -6021,8 +5748,10 @@ /* ** Patch the script to provide an extra clock cycle on ** data out phase - 53C1010_66MHz part only. + ** (Fixed in rev. 1 of the chip) */ - if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66){ + if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 && + np->revision_id < 1){ np->script0->datao_phase[0] = cpu_to_scr(SCR_REG_REG(scntl4, SCR_OR, 0x0c)); } @@ -6050,18 +5779,12 @@ if (np->device_id == PCI_DEVICE_ID_NCR_53C896 && np->revision_id <= 0x1 && (np->features & FE_NOPM)) { np->scatter = ncr_scatter_896R1; -#ifndef SCSI_NCR_PROFILE_SUPPORT -#define XXX 0 -#else -#define XXX 2 -#endif - np->script0->datai_phase[XXX] = cpu_to_scr(SCR_JUMP); - np->script0->datai_phase[XXX+1] = + np->script0->datai_phase[0] = cpu_to_scr(SCR_JUMP); + np->script0->datai_phase[1] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); np->script0->datao_phase[0] = cpu_to_scr(SCR_JUMP); np->script0->datao_phase[1] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj)); -#undef XXX } else #ifdef DEBUG_896R1 @@ -6168,7 +5891,7 @@ instance->this_id = np->myaddr; instance->max_id = np->maxwide ? 16 : 8; instance->max_lun = MAX_LUN; -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,29) instance->base = (unsigned long) np->reg; #else @@ -6524,11 +6247,10 @@ new_period = 0x0A; cmd->ic_nego_width = 1; new_width = 1; - new_offset &= 0x1f; } } - else if (new_period > 0x09) - new_offset &= 0x1f; + if (!options_byte && new_offset > np->maxoffs_st) + new_offset = np->maxoffs_st; nego = NS_PPR; @@ -6575,12 +6297,14 @@ tp->ic_min_sync = 0x0A; new_period = 0x0A; } + if (new_offset > np->maxoffs_st) + new_offset = np->maxoffs_st; nego = NS_SYNC; msgptr[msglen++] = M_EXTENDED; msgptr[msglen++] = 3; msgptr[msglen++] = M_X_SYNC_REQ; msgptr[msglen++] = new_period; - msgptr[msglen++] = new_offset & 0x1f; + msgptr[msglen++] = new_offset; } else cmd->ic_nego_sync = 0; @@ -6729,13 +6453,12 @@ if ( (factor==9) && offset) { if (!width) { factor = 0x0A; - offset &= 0x1f; } else last_byte = 0x02; } - else if (factor > 0x09) - offset &= 0x1f; + if (!last_byte && offset > np->maxoffs_st) + offset = np->maxoffs_st; msgptr[msglen++] = M_EXTENDED; msgptr[msglen++] = 6; @@ -6754,12 +6477,14 @@ factor = 0x0A; tp->minsync = 0x0A; } + if (offset > np->maxoffs_st) + offset = np->maxoffs_st; msgptr[msglen++] = M_EXTENDED; msgptr[msglen++] = 3; msgptr[msglen++] = M_X_SYNC_REQ; msgptr[msglen++] = factor; - msgptr[msglen++] = offset & 0x1f; + msgptr[msglen++] = offset; break; case NS_WIDE: msgptr[msglen++] = M_EXTENDED; @@ -6826,7 +6551,8 @@ ** **--------------------------------------------- */ - if (cmd->cmnd[0] == 0 && (tp->usrflag & UF_NOSCAN)) { + if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) && + (tp->usrflag & UF_NOSCAN)) { tp->usrflag &= ~UF_NOSCAN; return DID_BAD_TARGET; } @@ -6871,10 +6597,6 @@ } #endif -#ifdef SCSI_NCR_PROFILE_SUPPORT - cp->phys.num_disc = 0; -#endif - /*---------------------------------------------------- ** ** Build the identify / tag / sdtr message @@ -7131,7 +6853,7 @@ cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; cp->scsi_status = S_ILLEGAL; cp->xerr_status = 0; - cp->phys.extra_bytes = 0; + cp->extra_bytes = 0; /* ** extreme data pointer. @@ -7575,11 +7297,8 @@ return; /* - ** Gather profiling data + ** Print some debugging info. */ -#ifdef SCSI_NCR_PROFILE_SUPPORT - ncb_profile (np, cp); -#endif if (DEBUG_FLAGS & DEBUG_TINY) printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp, @@ -7622,7 +7341,8 @@ } else { cp->resid = 0; - if (cp->phys.header.lastp != cp->phys.header.goalp) + if (cp->xerr_status || + cp->phys.header.lastp != cp->phys.header.goalp) cp->resid = ncr_compute_residual(np, cp); } @@ -7666,10 +7386,16 @@ printk ("ERROR: cmd=%x host_status=%x scsi_status=%x " "data_len=%d residual=%d\n", cmd->cmnd[0], cp->host_status, cp->scsi_status, - cp->data_len, -cp->resid); + cp->data_len, cp->resid); } } +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,99) + /* + ** Move residual byte count to user structure. + */ + cmd->resid = cp->resid; +#endif /* ** Check the status. */ @@ -7701,9 +7427,6 @@ (char *) cmd->request_buffer); } - tp->bytes += cp->data_len; - tp->transfers ++; - /* ** If tags was reduced due to queue full, ** increase tags if 1000 good status received. @@ -7844,6 +7567,10 @@ /* ** The NCR has completed CCBs. ** Look at the DONE QUEUE. +** +** On architectures that may reorder LOAD/STORE operations, +** a memory barrier may be needed after the reading of the +** so-called `flag' and prior to dealing with the data. */ int ncr_wakeup_done (ncb_p np) { @@ -7863,6 +7590,7 @@ cp = ncr_ccb_from_dsa(np, dsa); if (cp) { + MEMORY_BARRIER(); ncr_complete (np, cp); ++n; } @@ -8014,12 +7742,11 @@ OUTB(nc_aipcntl1, (1<<3)); /* - ** If 64 bit (895A/896/1010/1010_66) write the CCNTL1 register to - ** enable 40 bit address table indirect addressing for MOVE. - ** Also write CCNTL0 if 64 bit chip, since this register seems - ** to only be used by 64 bit cores. + ** Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing + ** and/or hardware phase mismatch, since only such chips + ** seem to support those IO registers. */ - if (np->features & FE_64BIT) { + if (np->features & (FE_DAC | FE_NOPM)) { OUTB (nc_ccntl0, np->rv_ccntl0); OUTB (nc_ccntl1, np->rv_ccntl1); } @@ -8102,7 +7829,6 @@ ** For platforms that may not support PCI memory mapping, ** we use a simple SCRIPTS that performs MEMORY MOVEs. */ - MEMORY_BARRIER(); if (np->base2_ba) { if (bootverbose) printk ("%s: Downloading SCSI SCRIPTS.\n", @@ -8132,7 +7858,7 @@ np->istat_sem = 0; OUTL (nc_dsa, np->p_ncb); - OUTL (nc_dsp, phys); + OUTL_DSP (phys); } /*========================================================== @@ -8474,9 +8200,10 @@ else if (tp->period < 2000) scsi = "FAST-10"; else scsi = "FAST-5"; - printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi, + printk ("%s %sSCSI %d.%d MB/s (%d.%d ns, offset %d)\n", scsi, tp->widedone > 1 ? "WIDE " : "", - mb10 / 10, mb10 % 10, tp->period / 10, offset); + mb10 / 10, mb10 % 10, tp->period / 10, tp->period % 10, + offset); } else printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); next: @@ -8645,9 +8372,10 @@ else if (tp->period < 2000) scsi = "FAST-10"; else scsi = "FAST-5"; - printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi, + printk ("%s %sSCSI %d.%d MB/s (%d.%d ns, offset %d)\n", scsi, tp->widedone > 1 ? "WIDE " : "", - mb10 / 10, mb10 % 10, tp->period / 10, offset); + mb10 / 10, mb10 % 10, tp->period / 10, tp->period % 10, + offset); } else printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); next: @@ -8786,11 +8514,6 @@ np->verbose = np->user.data; break; -#ifdef SCSI_NCR_PROFILE_SUPPORT - case UC_CLEARPROF: - bzero(&np->profile, sizeof(np->profile)); - break; -#endif default: /* ** We assume that other commands apply to targets. @@ -9093,70 +8816,24 @@ u_short sist; int i; -#ifdef SCSI_NCR_OPTIMIZE_896_1 - /* - ** This optimization when used with a 896 that handles - ** phase mismatch from the SCRIPTS allows to only do - ** PCI memory writes transactions from the CPU and so to - ** take advantage of PCI posted writes. - ** Who wants his 500 MHz CPU to wait several micro-seconds - ** for the PCI BUS to be granted when this can be avoided? - ** I don't, even for my slow 233 MHz PII. :-) - ** - ** We assume we have been called for command completion. - ** If no completion found, go with normal handling. - ** Ordering is ensured by the SCRIPTS performing a read - ** from main memory prior to raising INTFLY. - ** We have to raise SIGP since the chip may be currently - ** going to a wait reselect instruction. IMO, SIGP should - ** not be clearable in ISTAT since it can be polled and - ** cleared by reading CTEST2. This tiny chip misdesign is a - ** penalty here. - ** - ** The MA interrupt and interrupt sharing may also have - ** adverse effects on this optimization, so we only want - ** to use it if it is enabled by user. - ** (BTW, this optimization seems to even have some goodness - ** with my 895 that unfortunately suffers of the MA int.). - */ - if (driver_setup.optimize & 1) { - OUTB(nc_istat, (INTF | SIGP | np->istat_sem)); - if (ncr_wakeup_done (np)) { -#ifdef SCSI_NCR_PROFILE_SUPPORT - ++np->profile.num_fly; -#endif - return; - } - } -#endif /* SCSI_NCR_OPTIMIZE_896_1 */ - /* ** interrupt on the fly ? ** - ** For bridges that donnot flush posted writes - ** in the reverse direction on read, a dummy read - ** may help not to miss completions. + ** A `dummy read' is needed to ensure that the + ** clear of the INTF flag reaches the device + ** before the scanning of the DONE queue. */ istat = INB (nc_istat); if (istat & INTF) { OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem); -#ifdef SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM istat = INB (nc_istat); /* DUMMY READ */ -#endif if (DEBUG_FLAGS & DEBUG_TINY) printk ("F "); (void)ncr_wakeup_done (np); -#ifdef SCSI_NCR_PROFILE_SUPPORT - ++np->profile.num_fly; -#endif }; if (!(istat & (SIP|DIP))) return; -#ifdef SCSI_NCR_PROFILE_SUPPORT - ++np->profile.num_int; -#endif - #if 0 /* We should never get this one */ if (istat & CABRT) OUTB (nc_istat, CABRT); @@ -9197,6 +8874,12 @@ (unsigned)INL(nc_dsp), (unsigned)INL(nc_dbc)); + /* + ** On paper, a memory barrier may be needed here. + ** And since we are paranoid ... :) + */ + MEMORY_BARRIER(); + /*======================================================== ** First, interrupts we want to service cleanly. ** @@ -9217,7 +8900,7 @@ if (sist & PAR) ncr_int_par (np, sist); else if (sist & MA) ncr_int_ma (np); else if (dstat & SIR) ncr_int_sir (np); - else if (dstat & SSI) OUTONB (nc_dcntl, (STD|NOCOM)); + else if (dstat & SSI) OUTONB_STD (); else goto unknown_int; return; }; @@ -9367,7 +9050,7 @@ OUTL (nc_dsa, DSA_INVALID); OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); } else goto reset_all; @@ -9419,7 +9102,6 @@ { u_int32 dsa = INL (nc_dsa); ccb_p cp = ncr_ccb_from_dsa(np, dsa); - tcb_p tp = &np->target[cp->target]; /* * Fix Up. Some disks respond to a PPR negotation with @@ -9427,9 +9109,11 @@ * Disable ppr negotiation if this is first time * tried ppr negotiation. */ - - if (tp->ppr_negotiation == 1) - tp->ppr_negotiation = 0; + if (cp) { + tcb_p tp = &np->target[cp->target]; + if (tp->ppr_negotiation == 1) + tp->ppr_negotiation = 0; + } printk ("%s: unexpected disconnect\n", ncr_name(np)); ncr_recover_scsi_int(np, HS_UNEXPECTED); @@ -9568,18 +9252,18 @@ if ((phase == 1) || (phase == 5)) { /* Phase mismatch handled by SCRIPTS */ if (dsp == NCB_SCRIPTH_PHYS (np, pm_handle)) - OUTL (nc_dsp, dsp); + OUTL_DSP (dsp); /* Phase mismatch handled by the C code */ else if (sist & MA) ncr_int_ma (np); /* No phase mismatch occurred */ else { OUTL (nc_temp, dsp); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch)); } } else - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); return; reset_all: @@ -9618,10 +9302,6 @@ struct pm_ctx *pm; ccb_p cp; -#ifdef SCSI_NCR_PROFILE_SUPPORT - ++np->profile.num_break; -#endif - dsp = INL (nc_dsp); dbc = INL (nc_dbc); dsa = INL (nc_dsa); @@ -9646,7 +9326,7 @@ ** raising the MA interrupt for interrupted INPUT phases. ** For DATA IN phase, we will check for the SWIDE later. */ - if ( !(((cmd & 7) == 1) || ((cmd & 7) == 5) ) ) { + if ((cmd & 7) != 1 && (cmd & 7) != 5) { u_int32 dfifo; u_char ss0, ss2; @@ -9772,9 +9452,11 @@ /* ** check cmd against assumed interrupted script command. + ** If dt data phase, the MOVE instruction hasn't bit 4 of + ** the phase. */ - if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) { + if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) { PRINT_ADDR(cp->cmd); printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", (unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24); @@ -9896,7 +9578,7 @@ */ OUTL (nc_temp, newcmd); - OUTL (nc_dsp, nxtdsp); + OUTL_DSP (nxtdsp); return; /* @@ -9969,7 +9651,7 @@ } if (nxtdsp) { - OUTL (nc_dsp, nxtdsp); + OUTL_DSP (nxtdsp); return; } @@ -10079,8 +9761,7 @@ /* ** Now we can restart the SCRIPTS processor safely. */ - MEMORY_BARRIER(); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); switch(s_status) { default: @@ -10114,7 +9795,7 @@ cp->host_status = HS_BUSY; cp->scsi_status = S_ILLEGAL; cp->xerr_status = 0; - cp->phys.extra_bytes = 0; + cp->extra_bytes = 0; cp->host_flags &= (HF_PM_TO_C|HF_DATA_IN); break; @@ -10416,7 +10097,7 @@ np->abrt_sel.sel_sxfer = tp->sval; np->abrt_sel.sel_scntl4 = tp->uval; OUTL(nc_dsa, np->p_ncb); - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, sel_for_abort)); return; } @@ -10503,7 +10184,7 @@ target = (INB (nc_sdid) & 0xf); tp = &np->target[target]; - np->abrt_tbl.addr = vtobus(np->abrt_msg); + np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg)); /* ** If the target is to be reset, prepare a @@ -10685,7 +10366,7 @@ /* ** Let the SCRIPTS processor continue. */ - OUTONB (nc_dcntl, (STD|NOCOM)); + OUTONB_STD (); } @@ -10911,11 +10592,11 @@ out_ok: OUTL (nc_temp, dp_scr); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); return; out_reject: - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); } @@ -10954,7 +10635,7 @@ */ if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) { if (cp->xerr_status & XE_EXTRA_DATA) - resid -= scr_to_cpu(cp->phys.extra_bytes); + resid -= cp->extra_bytes; if (cp->xerr_status & XE_SODL_UNRUN) ++resid; if (cp->xerr_status & XE_SWIDE_OVRUN) @@ -10963,11 +10644,11 @@ /* - ** If all data has been transferred, - ** there is no residual. + ** If SCRIPTS reaches its goal point, then + ** there is no additionnal residual. */ if (cp->phys.header.lastp == cp->phys.header.goalp) - return 0; + return resid; /* ** If the last data pointer is data_io (direction @@ -10975,35 +10656,27 @@ ** taken place. */ if (cp->phys.header.lastp == NCB_SCRIPTH_PHYS (np, data_io)) - return -cp->data_len; - - /* - ** If the device asked for more data than available, - ** return a positive residual value. - */ - if (cp->phys.extra_bytes) - return scr_to_cpu(cp->phys.extra_bytes); + return cp->data_len; /* - ** Evaluate the pointer saved on message COMPLETE. - ** According to our alchemy:), the extreme data - ** pointer will also be updated if needed. - ** On error, assume no data transferred (this may - ** happen if the data direction is unknown). + ** If no data transfer occurs, or if the data + ** pointer is weird, return full residual. */ - tmp = cpu_to_scr(cp->phys.header.lastp); - if (ncr_evaluate_dp(np, cp, tmp, &dp_ofs) < 0) - return -cp->data_len; + if (cp->startp == cp->phys.header.lastp || + ncr_evaluate_dp(np, cp, scr_to_cpu(cp->phys.header.lastp), + &dp_ofs) < 0) { + return cp->data_len; + } /* ** We are now full comfortable in the computation ** of the data residual (2's complement). */ dp_sgmin = MAX_SCATTER - cp->segments; - resid = cp->ext_ofs; + resid = -cp->ext_ofs; for (dp_sg = cp->ext_sg; dp_sg < MAX_SCATTER; ++dp_sg) { tmp = scr_to_cpu(cp->phys.data[dp_sg].size); - resid -= (tmp & 0xffffff); + resid += (tmp & 0xffffff); } /* @@ -11141,6 +10814,8 @@ {chg = 1; per = np->minsync;} if (per < tp->minsync) {chg = 1; per = tp->minsync;} + if (ofs > np->maxoffs_st) + {chg = 1; ofs = np->maxoffs_st;} if (ofs > tp->maxoffs) {chg = 1; ofs = tp->maxoffs;} @@ -11183,7 +10858,7 @@ ** Answer wasn't acceptable. */ ncr_setsync (np, cp, 0, 0xe0, 0); - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); } else { /* ** Answer is ok. @@ -11194,7 +10869,7 @@ else ncr_setsync (np, cp, scntl3, ofs, scntl4); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); }; return; @@ -11230,9 +10905,9 @@ np->msgin [0] = M_NOOP; if (!ofs) - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); else - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sdtr_resp)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, sdtr_resp)); } /*========================================================== @@ -11296,13 +10971,13 @@ ** Answer wasn't acceptable. */ ncr_setwide (np, cp, 0, 1); - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); } else { /* ** Answer is ok. */ ncr_setwide (np, cp, wide, 1); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); }; return; @@ -11332,7 +11007,7 @@ ncr_print_msg(cp, "wide msgout", np->msgout); } - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, wdtr_resp)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, wdtr_resp)); } /*========================================================== ** @@ -11429,6 +11104,9 @@ else if (( (per > 0x09) && dt) ) chg = 2; + /* Not acceptable since beyond controller limit */ + if (!dt && ofs > np->maxoffs_st) + {chg = 2; ofs = np->maxoffs_st;} if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); @@ -11456,7 +11134,7 @@ tp->widedone = 0; } ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0); - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); } else { /* ** Answer is ok. @@ -11468,7 +11146,7 @@ else ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); }; return; @@ -11496,12 +11174,12 @@ if ((per == 0x09) && ofs && (!wth || !dt)) { per = 0x0A; dt = 0; - ofs &= 0x1f; } else if ( (per > 0x09) && dt) { dt = 0; - ofs &= 0x1f; } + if (!dt && ofs > np->maxoffs_st) + ofs = np->maxoffs_st; if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && (np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)) @@ -11527,9 +11205,9 @@ np->msgin [0] = M_NOOP; if (!ofs) - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); else - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, ppr_resp)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, ppr_resp)); } @@ -11679,7 +11357,7 @@ */ if (tp->l0p) { OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0])); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, resel_go)); return; } /* @@ -11770,6 +11448,28 @@ } goto out; /* + ** The device wants us to tranfer more data than + ** expected or in the wrong direction. + ** The number of extra bytes is in scratcha. + ** It is a data overrun condition. + */ + case SIR_DATA_OVERRUN: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_EXTRA_DATA; + cp->extra_bytes += INL (nc_scratcha); + } + goto out; + /* + ** The device switched to an illegal phase (4/5). + */ + case SIR_BAD_PHASE: + if (cp) { + OUTONB (HF_PRT, HF_EXT_ERR); + cp->xerr_status |= XE_BAD_PHASE; + } + goto out; + /* ** We received a message. */ case SIR_MSG_RECEIVED: @@ -11835,7 +11535,7 @@ */ case SIR_MSG_WEIRD: ncr_print_msg(cp, "WEIRD message received", np->msgin); - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_weird)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_weird)); return; /* ** Negotiation failed. @@ -11854,15 +11554,15 @@ }; out: - OUTONB (nc_dcntl, (STD|NOCOM)); + OUTONB_STD (); return; out_reject: - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad)); + OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad)); return; out_clrack: - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); return; -out_stuck:; +out_stuck: } @@ -12493,7 +12193,7 @@ **========================================================== */ -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED static int __init ncr_regtest (struct ncb* np) { register volatile u_int32 data; @@ -12522,7 +12222,7 @@ { u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; int i, err=0; -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED if (np->reg) { err |= ncr_regtest (np); if (err) return (err); @@ -12543,7 +12243,7 @@ ** Start script (exchange values) */ OUTL (nc_dsa, np->p_ncb); - OUTL (nc_dsp, pc); + OUTL_DSP (pc); /* ** Wait 'til done (with timeout) */ @@ -12601,44 +12301,6 @@ /*========================================================== ** -** -** Profiling the drivers and targets performance. -** -** -**========================================================== -*/ - -#ifdef SCSI_NCR_PROFILE_SUPPORT - -static void ncb_profile (ncb_p np, ccb_p cp) -{ - int num_disc = (cp->phys.num_disc & 0xff); - int num_disc0 = (cp->phys.num_disc >> 8); - - ++np->profile.num_trans; - np->profile.num_disc += num_disc; - np->profile.num_disc0 += num_disc0; - np->profile.num_kbytes += (cp->data_len >> 10); -#if 000 - if (num_disc > num_disc0) { - if (cp->data_len <= 1024) - np->profile.num_br1k += (num_disc - num_disc0); - else if (cp->data_len <= 2048) - np->profile.num_br2k += (num_disc - num_disc0); - else if (cp->data_len <= 4096) - np->profile.num_br4k += (num_disc - num_disc0); - else if (cp->data_len <= 8192) - np->profile.num_br8k += (num_disc - num_disc0); - else - np->profile.num_brnk += (num_disc - num_disc0); - } -#endif -} - -#endif /* SCSI_NCR_PROFILE_SUPPORT */ - -/*========================================================== -** ** Determine the ncr's clock frequency. ** This is essential for the negotiation ** of the synchronous transfer rate. @@ -12745,14 +12407,8 @@ /* * adjust for prescaler, and convert into KHz - * scale values derived empirically. C1010 uses - * different dividers + * scale values derived empirically. */ -#if 0 - if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) - f = ms ? ((1 << gen) * 2866 ) / ms : 0; - else -#endif f = ms ? ((1 << gen) * 4340) / ms : 0; if (bootverbose >= 2) @@ -12796,19 +12452,11 @@ } /* - ** If multiplier not found but a C1010, assume a mult of 4. ** If multiplier not found or scntl3 not 7,5,3, ** reset chip and get frequency from general purpose timer. ** Otherwise trust scntl3 BIOS setting. */ - if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) || - (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) { - f1=40000; - np->multiplier = mult; - if (bootverbose >= 2) - printk ("%s: clock multiplier assumed\n", ncr_name(np)); - } - else if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { + if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { OUTB (nc_stest1, 0); /* make sure doubler is OFF */ f1 = ncr_getfreq (np); @@ -12898,7 +12546,7 @@ #define OPT_SCSI_PARITY 3 #define OPT_DISCONNECTION 4 #define OPT_SPECIAL_FEATURES 5 -#define OPT_ULTRA_SCSI 6 +#define OPT_RESERVED_1 6 #define OPT_FORCE_SYNC_NEGO 7 #define OPT_REVERSE_PROBE 8 #define OPT_DEFAULT_SYNC 9 @@ -12926,7 +12574,7 @@ static char setup_token[] __initdata = "tags:" "mpar:" "spar:" "disc:" - "specf:" "ultra:" + "specf:" "_rsvd1:" "fsn:" "revprob:" "sync:" "verb:" "debug:" "burst:" @@ -13012,9 +12660,6 @@ case OPT_SPECIAL_FEATURES: driver_setup.special_features = val; break; - case OPT_ULTRA_SCSI: - driver_setup.ultra_scsi = val; - break; case OPT_FORCE_SYNC_NEGO: driver_setup.force_sync_nego = val; break; @@ -13118,11 +12763,10 @@ static void __init ncr_print_driver_setup(void) { #define YesNo(y) y ? 'y' : 'n' - printk (NAME53C8XX ": setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d," + printk (NAME53C8XX ": setup=disc:%c,specf:%d,tags:%d,sync:%d," "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n", YesNo(driver_setup.disconnection), driver_setup.special_features, - driver_setup.ultra_scsi, driver_setup.default_tags, driver_setup.default_sync, driver_setup.burst_max, @@ -13294,6 +12938,8 @@ ++j; continue; } + if (pci_enable_device(pcidev)) /* @!*!$&*!%-*#;! */ + continue; /* Some HW as the HP LH4 may report twice PCI devices */ for (i = 0; i < count ; i++) { if (devtbl[i].slot.bus == PciBusNumber(pcidev) && @@ -13414,7 +13060,7 @@ u_char pci_fix_up = driver_setup.pci_fix_up; u_char revision; u_int irq; - u_long base, base_2, io_port; + u_long base, base_c, base_2, base_2_c, io_port; int i; ncr_chip *chip; @@ -13439,10 +13085,15 @@ vendor_id = PciVendorId(pdev); device_id = PciDeviceId(pdev); irq = PciIrqLine(pdev); - i = 0; - i = pci_get_base_address(pdev, i, &io_port); - i = pci_get_base_address(pdev, i, &base); - (void) pci_get_base_address(pdev, i, &base_2); + + i = pci_get_base_address(pdev, 0, &io_port); + io_port = pci_get_base_cookie(pdev, 0); + + base_c = pci_get_base_cookie(pdev, i); + i = pci_get_base_address(pdev, i, &base); + + base_2_c = pci_get_base_cookie(pdev, i); + (void) pci_get_base_address(pdev, i, &base_2); pci_read_config_word(pdev, PCI_COMMAND, &command); pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); @@ -13498,7 +13149,7 @@ ** This controller sets value 0x52414944 at RAM end - 16. */ #if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED) - if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) { + if (chip && (base_2_c & PCI_BASE_ADDRESS_MEM_MASK)) { unsigned int ram_size, ram_val; u_long ram_ptr; @@ -13507,7 +13158,7 @@ else ram_size = 4096; - ram_ptr = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK, + ram_ptr = remap_pci_mem(base_2_c & PCI_BASE_ADDRESS_MEM_MASK, ram_size); if (ram_ptr) { ram_val = readl_raw(ram_ptr + ram_size - 16); @@ -13589,7 +13240,7 @@ ** from attaching devices from the both drivers. ** If you have a better idea, let me know. */ -/* #ifdef NCR_IOMAPPED */ +/* #ifdef SCSI_NCR_IOMAPPED */ #if 1 if (!(command & PCI_COMMAND_IO)) { printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n", @@ -13606,7 +13257,7 @@ base &= PCI_BASE_ADDRESS_MEM_MASK; base_2 &= PCI_BASE_ADDRESS_MEM_MASK; -/* #ifdef NCR_IOMAPPED */ +/* #ifdef SCSI_NCR_IOMAPPED */ #if 1 if (io_port && check_region (io_port, 128)) { printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n", @@ -13616,7 +13267,7 @@ if (!io_port) return -1; #endif -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED if (!base) { printk(NAME53C8XX ": MMIO base address disabled.\n"); return -1; @@ -13670,28 +13321,6 @@ } } - if (driver_setup.ultra_scsi < 3 && (chip->features & FE_ULTRA3)) { - chip->features |= FE_ULTRA2; - chip->features &= ~FE_ULTRA3; - } - if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) { - chip->features |= FE_ULTRA; - chip->features &= ~FE_ULTRA2; - } - if (driver_setup.ultra_scsi < 1) - chip->features &= ~FE_ULTRA; - - if (!driver_setup.max_wide) - chip->features &= ~FE_WIDE; - - /* - * C1010 Ultra3 support requires 16 bit data transfers. - */ - if (!driver_setup.max_wide && (chip->features & FE_ULTRA3)) { - chip->features |= FE_ULTRA2; - chip->features |= ~FE_ULTRA3; - } - /* ** Some features are required to be enabled in order to ** work around some chip problems. :) ;) @@ -13751,6 +13380,8 @@ device->slot.device_fn = PciDeviceFn(pdev); device->slot.base = base; device->slot.base_2 = base_2; + device->slot.base_c = base_c; + device->slot.base_2_c = base_2_c; device->slot.io_port = io_port; device->slot.irq = irq; device->attach_done = 0; @@ -13780,11 +13411,12 @@ /* ** Get access to chip IO registers */ -#ifdef NCR_IOMAPPED +#ifdef SCSI_NCR_IOMAPPED request_region(devp->slot.io_port, 128, NAME53C8XX); devp->slot.base_io = devp->slot.io_port; #else - devp->slot.reg = (struct ncr_reg *) remap_pci_mem(devp->slot.base, 128); + devp->slot.reg = + (struct ncr_reg *) remap_pci_mem(devp->slot.base_c, 128); if (!devp->slot.reg) return; #endif @@ -13806,7 +13438,7 @@ /* ** Release access to chip IO registers */ -#ifdef NCR_IOMAPPED +#ifdef SCSI_NCR_IOMAPPED release_region(devp->slot.base_io, 128); #else unmap_pci_mem((u_long) devp->slot.reg, 128ul); @@ -14241,7 +13873,7 @@ /*========================================================================= ** Proc file system stuff ** -** A read operation returns profile information. +** A read operation returns adapter information. ** A write operation is a control command. ** The string is parsed in the driver code and the command is passed ** to the ncr_usercmd() function. @@ -14335,10 +13967,6 @@ uc->cmd = UC_RESETDEV; else if ((arg_len = is_keyword(ptr, len, "cleardev")) != 0) uc->cmd = UC_CLEARDEV; -#ifdef SCSI_NCR_PROFILE_SUPPORT - else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0) - uc->cmd = UC_CLEARPROF; -#endif else arg_len = 0; @@ -14499,11 +14127,9 @@ } /* -** Copy formatted profile information into the input buffer. +** Copy formatted information into the input buffer. */ -#define to_ms(t) ((t) * 1000 / HZ) - static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) { struct info_str info; @@ -14538,24 +14164,6 @@ driver_setup.debug, driver_setup.verbose); } -#ifdef SCSI_NCR_PROFILE_SUPPORT - copy_info(&info, "Profiling information:\n"); - copy_info(&info, " %-12s = %lu\n", "num_fly", np->profile.num_fly); - copy_info(&info, " %-12s = %lu\n", "num_trans",np->profile.num_trans); - copy_info(&info, " %-12s = %lu\n", "num_disc", np->profile.num_disc); - copy_info(&info, " %-12s = %lu\n", "num_disc0",np->profile.num_disc0); - copy_info(&info, " %-12s = %lu\n", "num_break",np->profile.num_break); -#if 000 - copy_info(&info, " %-12s = %lu\n", "num_br1k",np->profile.num_br1k); - copy_info(&info, " %-12s = %lu\n", "num_br2k",np->profile.num_br2k); - copy_info(&info, " %-12s = %lu\n", "num_br4k",np->profile.num_br4k); - copy_info(&info, " %-12s = %lu\n", "num_br8k",np->profile.num_br8k); - copy_info(&info, " %-12s = %lu\n", "num_brnk",np->profile.num_brnk); -#endif - copy_info(&info, " %-12s = %lu\n", "num_int", np->profile.num_int); - copy_info(&info, " %-12s = %lu\n","num_kbytes",np->profile.num_kbytes); -#endif - return info.pos > info.offset? info.pos - info.offset : 0; } @@ -14563,7 +14171,7 @@ /* ** Entry point of the scsi proc fs of the driver. -** - func = 0 means read (returns profile data) +** - func = 0 means read (returns adapter infos) ** - func = 1 means write (parse user control command) */ @@ -14830,10 +14438,10 @@ return retv; } -#undef SET_BIT /* 0 */ -#undef CLR_BIT /* 1 */ -#undef SET_CLK /* 2 */ -#undef CLR_CLK /* 3 */ +#undef SET_BIT +#undef CLR_BIT +#undef SET_CLK +#undef CLR_CLK /* * Try reading Symbios NVRAM. @@ -15063,5 +14671,10 @@ ** Module stuff */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) static Scsi_Host_Template driver_template = SYM53C8XX; #include "scsi_module.c" +#elif defined(MODULE) +Scsi_Host_Template driver_template = SYM53C8XX; +#include "scsi_module.c" +#endif diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c8xx.h linux/drivers/scsi/sym53c8xx.h --- v2.4.2/linux/drivers/scsi/sym53c8xx.h Thu Jan 4 14:52:35 2001 +++ linux/drivers/scsi/sym53c8xx.h Wed Mar 7 16:58:41 2001 @@ -65,6 +65,8 @@ ** Used by hosts.c and sym53c8xx.c with module configuration. */ +#if (LINUX_VERSION_CODE >= 0x020400) || defined(HOSTS_C) || defined(MODULE) + #include int sym53c8xx_abort(Scsi_Cmnd *); @@ -108,5 +110,7 @@ 0, 0, DISABLE_CLUSTERING} #endif /* LINUX_VERSION_CODE */ + +#endif /* defined(HOSTS_C) || defined(MODULE) */ #endif /* SYM53C8XX_H */ diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h --- v2.4.2/linux/drivers/scsi/sym53c8xx_comm.h Mon Oct 16 12:56:50 2000 +++ linux/drivers/scsi/sym53c8xx_comm.h Tue Mar 6 19:34:25 2001 @@ -80,17 +80,6 @@ /*========================================================== ** -** Io mapped versus memory mapped. -** -**========================================================== -*/ - -#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED) -#define NCR_IOMAPPED -#endif - -/*========================================================== -** ** Miscallaneous defines. ** **========================================================== @@ -261,33 +250,6 @@ /*========================================================== ** -** On x86 architecture, write buffers management does -** not reorder writes to memory. So, using compiler -** optimization barriers is enough to guarantee some -** ordering when the CPU is writing data accessed by -** the NCR. -** On Alpha architecture, explicit memory barriers have -** to be used. -** Other architectures are defaulted to mb() macro if -** defined, otherwise use compiler barrier. -** -**========================================================== -*/ - -#if defined(__i386__) -#define MEMORY_BARRIER() barrier() -#elif defined(__alpha__) -#define MEMORY_BARRIER() mb() -#else -# ifdef mb -# define MEMORY_BARRIER() mb() -# else -# define MEMORY_BARRIER() barrier() -# endif -#endif - -/*========================================================== -** ** Simple Wrapper to kernel PCI bus interface. ** ** This wrapper allows to get rid of old kernel PCI @@ -310,30 +272,42 @@ #define PciDeviceId(d) (d)->device #define PciIrqLine(d) (d)->irq -#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) - -static int __init -pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) +static u_long __init +pci_get_base_cookie(struct pci_dev *pdev, int index) { - *base = pdev->resource[index].start; - if ((pdev->resource[index].flags & 0x7) == 0x4) - ++index; - return ++index; -} + u_long base; + +#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) + base = pdev->resource[index].start; #else -static int __init + base = pdev->base_address[index]; +#if BITS_PER_LONG > 32 + if ((base & 0x7) == 0x4) + *base |= (((u_long)pdev->base_address[++index]) << 32); +#endif +#endif + return (base & ~0x7ul); +} + +static int __init pci_get_base_address(struct pci_dev *pdev, int index, u_long *base) { - *base = pdev->base_address[index++]; - if ((*base & 0x7) == 0x4) { + u32 tmp; +#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2)) + + pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp); + *base = tmp; + ++index; + if ((tmp & 0x7) == 0x4) { #if BITS_PER_LONG > 32 - *base |= (((u_long)pdev->base_address[index]) << 32); + pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp); + *base |= (((u_long)tmp) << 32); #endif ++index; } return index; +#undef PCI_BAR_OFFSET } -#endif #else /* Incomplete emulation of current PCI code for pre-2.2 kernels */ @@ -413,9 +387,23 @@ } return offset; } +static u_long __init +pci_get_base_cookie(struct pci_dev *pdev, int offset) +{ + u_long base; + + (void) pci_get_base_address(dev, offset, &base); + + return base; +} #endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */ +/* Does not make sense in earlier kernels */ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) +#define pci_enable_device(pdev) (0) +#endif + /*========================================================== ** ** SMP threading. @@ -488,18 +476,14 @@ #ifdef __sparc__ # include -# define pcivtobus(p) bus_dvma_to_mem(p) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #elif defined(__alpha__) -# define pcivtobus(p) ((p) & 0xfffffffful) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #else /* others */ -# define pcivtobus(p) (p) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #endif -#if (defined(SCSI_NCR_NVRAM_SUPPORT) && !defined(NCR_IOMAPPED)) || \ - (defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)) +#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED static u_long __init remap_pci_mem(u_long base, u_long size) { u_long page_base = ((u_long) base) & PAGE_MASK; @@ -1105,168 +1089,6 @@ #define initverbose (driver_setup.verbose) #define bootverbose (np->verbose) -/*========================================================== -** -** Big/Little endian support. -** -** If the NCR uses big endian addressing mode over the -** PCI, actual io register addresses for byte and word -** accesses must be changed according to lane routing. -** Btw, ncr_offb() and ncr_offw() macros only apply to -** constants and so donnot generate bloated code. -** -** If the CPU and the NCR use same endian-ness adressing, -** no byte reordering is needed for script patching. -** Macro cpu_to_scr() is to be used for script patching. -** Macro scr_to_cpu() is to be used for getting a DWORD -** from the script. -** -**========================================================== -*/ - -#if defined(SCSI_NCR_BIG_ENDIAN) - -#define ncr_offb(o) (((o)&~3)+((~((o)&3))&3)) -#define ncr_offw(o) (((o)&~3)+((~((o)&3))&2)) - -#else - -#define ncr_offb(o) (o) -#define ncr_offw(o) (o) - -#endif - -#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) - -#define cpu_to_scr(dw) cpu_to_le32(dw) -#define scr_to_cpu(dw) le32_to_cpu(dw) - -#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) - -#define cpu_to_scr(dw) cpu_to_be32(dw) -#define scr_to_cpu(dw) be32_to_cpu(dw) - -#else - -#define cpu_to_scr(dw) (dw) -#define scr_to_cpu(dw) (dw) - -#endif - -/*========================================================== -** -** Access to the controller chip. -** -** If NCR_IOMAPPED is defined, the driver will use -** normal IOs instead of the MEMORY MAPPED IO method -** recommended by PCI specifications. -** If all PCI bridges, host brigdes and architectures -** would have been correctly designed for PCI, this -** option would be useless. -** -** If the CPU and the NCR use same endian-ness adressing, -** no byte reordering is needed for accessing chip io -** registers. Functions suffixed by '_raw' are assumed -** to access the chip over the PCI without doing byte -** reordering. Functions suffixed by '_l2b' are -** assumed to perform little-endian to big-endian byte -** reordering, those suffixed by '_b2l' blah, blah, -** blah, ... -** -**========================================================== -*/ - -#if defined(NCR_IOMAPPED) - -/* -** IO mapped only input / ouput -*/ - -#define INB_OFF(o) inb (np->base_io + ncr_offb(o)) -#define OUTB_OFF(o, val) outb ((val), np->base_io + ncr_offb(o)) - -#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) inw_l2b (np->base_io + ncr_offw(o)) -#define INL_OFF(o) inl_l2b (np->base_io + (o)) - -#define OUTW_OFF(o, val) outw_b2l ((val), np->base_io + ncr_offw(o)) -#define OUTL_OFF(o, val) outl_b2l ((val), np->base_io + (o)) - -#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) inw_b2l (np->base_io + ncr_offw(o)) -#define INL_OFF(o) inl_b2l (np->base_io + (o)) - -#define OUTW_OFF(o, val) outw_l2b ((val), np->base_io + ncr_offw(o)) -#define OUTL_OFF(o, val) outl_l2b ((val), np->base_io + (o)) - -#else - -#define INW_OFF(o) inw_raw (np->base_io + ncr_offw(o)) -#define INL_OFF(o) inl_raw (np->base_io + (o)) - -#define OUTW_OFF(o, val) outw_raw ((val), np->base_io + ncr_offw(o)) -#define OUTL_OFF(o, val) outl_raw ((val), np->base_io + (o)) - -#endif /* ENDIANs */ - -#else /* defined NCR_IOMAPPED */ - -/* -** MEMORY mapped IO input / output -*/ - -#define INB_OFF(o) readb((char *)np->reg + ncr_offb(o)) -#define OUTB_OFF(o, val) writeb((val), (char *)np->reg + ncr_offb(o)) - -#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) readw_l2b((char *)np->reg + ncr_offw(o)) -#define INL_OFF(o) readl_l2b((char *)np->reg + (o)) - -#define OUTW_OFF(o, val) writew_b2l((val), (char *)np->reg + ncr_offw(o)) -#define OUTL_OFF(o, val) writel_b2l((val), (char *)np->reg + (o)) - -#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) readw_b2l((char *)np->reg + ncr_offw(o)) -#define INL_OFF(o) readl_b2l((char *)np->reg + (o)) - -#define OUTW_OFF(o, val) writew_l2b((val), (char *)np->reg + ncr_offw(o)) -#define OUTL_OFF(o, val) writel_l2b((val), (char *)np->reg + (o)) - -#else - -#define INW_OFF(o) readw_raw((char *)np->reg + ncr_offw(o)) -#define INL_OFF(o) readl_raw((char *)np->reg + (o)) - -#define OUTW_OFF(o, val) writew_raw((val), (char *)np->reg + ncr_offw(o)) -#define OUTL_OFF(o, val) writel_raw((val), (char *)np->reg + (o)) - -#endif - -#endif /* defined NCR_IOMAPPED */ - -#define INB(r) INB_OFF (offsetof(struct ncr_reg,r)) -#define INW(r) INW_OFF (offsetof(struct ncr_reg,r)) -#define INL(r) INL_OFF (offsetof(struct ncr_reg,r)) - -#define OUTB(r, val) OUTB_OFF (offsetof(struct ncr_reg,r), (val)) -#define OUTW(r, val) OUTW_OFF (offsetof(struct ncr_reg,r), (val)) -#define OUTL(r, val) OUTL_OFF (offsetof(struct ncr_reg,r), (val)) - -/* -** Set bit field ON, OFF -*/ - -#define OUTONB(r, m) OUTB(r, INB(r) | (m)) -#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m)) -#define OUTONW(r, m) OUTW(r, INW(r) | (m)) -#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m)) -#define OUTONL(r, m) OUTL(r, INL(r) | (m)) -#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m)) - /*========================================================== ** @@ -1281,6 +1103,8 @@ u_long base; u_long base_2; u_long io_port; + u_long base_c; + u_long base_2_c; int irq; /* port and reg fields to use INB, OUTB macros */ u_long base_io; @@ -1546,10 +1370,10 @@ return retv; } -#undef SET_BIT -#undef CLR_BIT -#undef SET_CLK -#undef CLR_CLK +#undef SET_BIT +#undef CLR_BIT +#undef SET_CLK +#undef CLR_CLK /* * Try reading Symbios NVRAM. @@ -1798,11 +1622,12 @@ /* ** Get access to chip IO registers */ -#ifdef NCR_IOMAPPED +#ifdef SCSI_NCR_IOMAPPED request_region(devp->slot.io_port, 128, NAME53C8XX); devp->slot.base_io = devp->slot.io_port; #else - devp->slot.reg = (struct ncr_reg *) remap_pci_mem(devp->slot.base, 128); + devp->slot.reg = + (struct ncr_reg *) remap_pci_mem(devp->slot.base_c, 128); if (!devp->slot.reg) return; #endif @@ -1824,7 +1649,7 @@ /* ** Release access to chip IO registers */ -#ifdef NCR_IOMAPPED +#ifdef SCSI_NCR_IOMAPPED release_region(devp->slot.base_io, 128); #else unmap_pci_mem((u_long) devp->slot.reg, 128ul); @@ -1991,7 +1816,7 @@ #define OPT_SCSI_PARITY 3 #define OPT_DISCONNECTION 4 #define OPT_SPECIAL_FEATURES 5 -#define OPT_ULTRA_SCSI 6 +#define OPT_UNUSED_1 6 #define OPT_FORCE_SYNC_NEGO 7 #define OPT_REVERSE_PROBE 8 #define OPT_DEFAULT_SYNC 9 @@ -2104,9 +1929,6 @@ case OPT_SPECIAL_FEATURES: driver_setup.special_features = val; break; - case OPT_ULTRA_SCSI: - driver_setup.ultra_scsi = val; - break; case OPT_FORCE_SYNC_NEGO: driver_setup.force_sync_nego = val; break; @@ -2248,11 +2070,10 @@ static void __init ncr_print_driver_setup(void) { #define YesNo(y) y ? 'y' : 'n' - printk (NAME53C8XX ": setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d," + printk (NAME53C8XX ": setup=disc:%c,specf:%d,tags:%d,sync:%d," "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n", YesNo(driver_setup.disconnection), driver_setup.special_features, - driver_setup.ultra_scsi, driver_setup.default_tags, driver_setup.default_sync, driver_setup.burst_max, @@ -2352,7 +2173,7 @@ u_char pci_fix_up = driver_setup.pci_fix_up; u_char revision; u_int irq; - u_long base, base_2, io_port; + u_long base, base_c, base_2, base_2_c, io_port; int i; ncr_chip *chip; @@ -2377,10 +2198,15 @@ vendor_id = PciVendorId(pdev); device_id = PciDeviceId(pdev); irq = PciIrqLine(pdev); - i = 0; - i = pci_get_base_address(pdev, i, &io_port); - i = pci_get_base_address(pdev, i, &base); - (void) pci_get_base_address(pdev, i, &base_2); + + i = pci_get_base_address(pdev, 0, &io_port); + io_port = pci_get_base_cookie(pdev, 0); + + base_c = pci_get_base_cookie(pdev, i); + i = pci_get_base_address(pdev, i, &base); + + base_2_c = pci_get_base_cookie(pdev, i); + (void) pci_get_base_address(pdev, i, &base_2); pci_read_config_word(pdev, PCI_COMMAND, &command); pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); @@ -2438,7 +2264,7 @@ ** This controller sets value 0x52414944 at RAM end - 16. */ #if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED) - if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) { + if (chip && (base_2_c & PCI_BASE_ADDRESS_MEM_MASK)) { unsigned int ram_size, ram_val; u_long ram_ptr; @@ -2447,7 +2273,7 @@ else ram_size = 4096; - ram_ptr = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK, + ram_ptr = remap_pci_mem(base_2_c & PCI_BASE_ADDRESS_MEM_MASK, ram_size); if (ram_ptr) { ram_val = readl_raw(ram_ptr + ram_size - 16); @@ -2529,7 +2355,7 @@ ** from attaching devices from the both drivers. ** If you have a better idea, let me know. */ -/* #ifdef NCR_IOMAPPED */ +/* #ifdef SCSI_NCR_IOMAPPED */ #if 1 if (!(command & PCI_COMMAND_IO)) { printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n", @@ -2546,7 +2372,7 @@ base &= PCI_BASE_ADDRESS_MEM_MASK; base_2 &= PCI_BASE_ADDRESS_MEM_MASK; -/* #ifdef NCR_IOMAPPED */ +/* #ifdef SCSI_NCR_IOMAPPED */ #if 1 if (io_port && check_region (io_port, 128)) { printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n", @@ -2556,7 +2382,7 @@ if (!io_port) return -1; #endif -#ifndef NCR_IOMAPPED +#ifndef SCSI_NCR_IOMAPPED if (!base) { printk(NAME53C8XX ": MMIO base address disabled.\n"); return -1; @@ -2602,14 +2428,6 @@ if (driver_setup.special_features & 4) chip->features &= ~FE_NOPM; } - if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) { - chip->features |= FE_ULTRA; - chip->features &= ~FE_ULTRA2; - } - if (driver_setup.ultra_scsi < 1) - chip->features &= ~FE_ULTRA; - if (!driver_setup.max_wide) - chip->features &= ~FE_WIDE; /* ** Some features are required to be enabled in order to @@ -2670,6 +2488,8 @@ device->slot.device_fn = PciDeviceFn(pdev); device->slot.base = base; device->slot.base_2 = base_2; + device->slot.base_c = base_c; + device->slot.base_2_c = base_2_c; device->slot.io_port = io_port; device->slot.irq = irq; device->attach_done = 0; @@ -2754,6 +2574,8 @@ ++j; continue; } + if (pci_enable_device(pcidev)) /* @!*!$&*!%-*#;! */ + continue; /* Some HW as the HP LH4 may report twice PCI devices */ for (i = 0; i < count ; i++) { if (devtbl[i].slot.bus == PciBusNumber(pcidev) && diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h --- v2.4.2/linux/drivers/scsi/sym53c8xx_defs.h Thu Jan 4 14:52:24 2001 +++ linux/drivers/scsi/sym53c8xx_defs.h Wed Mar 7 16:58:31 2001 @@ -95,9 +95,6 @@ #define SCSI_NCR_DEBUG_INFO_SUPPORT #define SCSI_NCR_PCI_FIX_UP_SUPPORT #ifdef SCSI_NCR_PROC_INFO_SUPPORT -# ifdef CONFIG_SCSI_NCR53C8XX_PROFILE -# define SCSI_NCR_PROFILE_SUPPORT -# endif # define SCSI_NCR_USER_COMMAND_SUPPORT # define SCSI_NCR_USER_INFO_SUPPORT #endif @@ -141,18 +138,6 @@ */ #define SCSI_NCR_SETUP_SPECIAL_FEATURES (3) -/* - * For Ultra2 and Ultra3 SCSI support allow 80Mhz synchronous data transfers. - * Value means: - * 0 - Ultra speeds disabled - * 1 - Ultra enabled (Maximum 20Mtrans/sec) - * 2 - Ultra2 enabled (Maximum 40Mtrans/sec) - * 3 - Ultra3 enabled (Maximum 80Mtrans/sec) - * - * Use boot options sym53c8xx=ultra:3 to enable Ultra3 support. - */ - -#define SCSI_NCR_SETUP_ULTRA_SCSI (3) #define SCSI_NCR_MAX_SYNC (80) /* @@ -183,17 +168,35 @@ #endif /* - * Use normal IO if configured. Forced for alpha and ppc. + * Use normal IO if configured. Forced for alpha and powerpc. + * Powerpc fails copying to on-chip RAM using memcpy_toio(). */ #if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) #define SCSI_NCR_IOMAPPED -#elif defined(__alpha__) || defined(__powerpc__) +#elif defined(__alpha__) #define SCSI_NCR_IOMAPPED +#elif defined(__powerpc__) +#define SCSI_NCR_IOMAPPED +#define SCSI_NCR_PCI_MEM_NOT_SUPPORTED #elif defined(__sparc__) #undef SCSI_NCR_IOMAPPED #endif /* + * Should we enable DAC cycles on Sparc64 platform? + * Until further investigation we do not enable it + * at the moment. + * We may want to enable it for __ia64__ (untested) + */ +#if defined(__ia64__) +# if !defined(SCSI_NCR_USE_64BIT_DAC) +# define SCSI_NCR_USE_64BIT_DAC +# endif +#else +# undef SCSI_NCR_USE_64BIT_DAC +#endif + +/* * Immediate arbitration */ #if defined(CONFIG_SCSI_NCR53C8XX_IARB) @@ -376,12 +379,11 @@ #define ktime_add(a, o) ((a) + (u_long)(o)) #define ktime_sub(a, o) ((a) - (u_long)(o)) + /* -** IO functions definition for big/little endian support. -** For now, the NCR is only supported in little endian addressing mode, -** and big endian byte ordering is only supported for the PPC. -** MMIO is not used on PPC. -*/ + * IO functions definition for big/little endian CPU support. + * For now, the NCR is only supported in little endian addressing mode, + */ #ifdef __BIG_ENDIAN @@ -389,27 +391,34 @@ #error "BIG ENDIAN byte ordering needs kernel version >= 2.1.0" #endif -#if defined(__powerpc__) #define inw_l2b inw #define inl_l2b inl #define outw_b2l outw #define outl_b2l outl -#elif defined(__sparc__) + +#define readb_raw readb +#define writeb_raw writeb + +#if defined(__hppa__) +#define readw_l2b(a) le16_to_cpu(readw(a)) +#define readl_l2b(a) le32_to_cpu(readl(a)) +#define writew_b2l(v,a) writew(cpu_to_le16(v),a) +#define writel_b2l(v,a) writel(cpu_to_le32(v),a) +#else /* Other bid-endian */ #define readw_l2b readw #define readl_l2b readl #define writew_b2l writew #define writel_b2l writel -#else -#error "Support for BIG ENDIAN is only available for PowerPC and SPARC" #endif #else /* little endian */ -#if defined(__i386__) /* i386 implements full FLAT memory/MMIO model */ #define inw_raw inw #define inl_raw inl #define outw_raw outw #define outl_raw outl + +#if defined(__i386__) /* i386 implements full FLAT memory/MMIO model */ #define readb_raw(a) (*(volatile unsigned char *) (a)) #define readw_raw(a) (*(volatile unsigned short *) (a)) #define readl_raw(a) (*(volatile unsigned int *) (a)) @@ -417,13 +426,11 @@ #define writew_raw(b,a) ((*(volatile unsigned short *) (a)) = (b)) #define writel_raw(b,a) ((*(volatile unsigned int *) (a)) = (b)) -#else /* Other little-endian (for now alpha) */ -#define inw_raw inw -#define inl_raw inl -#define outw_raw outw -#define outl_raw outl +#else /* Other little-endian */ +#define readb_raw readb #define readw_raw readw #define readl_raw readl +#define writeb_raw writeb #define writew_raw writew #define writel_raw writel @@ -434,6 +441,204 @@ #error "The NCR in BIG ENDIAN addressing mode is not (yet) supported" #endif + +/* + * IA32 architecture does not reorder STORES and prevents + * LOADS from passing STORES. It is called `program order' + * by Intel and allows device drivers to deal with memory + * ordering by only ensuring that the code is not reordered + * by the compiler when ordering is required. + * Other architectures implement a weaker ordering that + * requires memory barriers (and also IO barriers when they + * make sense) to be used. + * We want to be paranoid for ppc and ia64. :) + */ + +#if defined __i386__ +#define MEMORY_BARRIER() do { ; } while(0) +#elif defined __powerpc__ +#define MEMORY_BARRIER() __asm__ volatile("eieio; sync" : : : "memory") +#elif defined __ia64__ +#define MEMORY_BARRIER() __asm__ volatile("mf.a; mf" : : : "memory") +#else +#define MEMORY_BARRIER() mb() +#endif + + +/* + * If the NCR uses big endian addressing mode over the + * PCI, actual io register addresses for byte and word + * accesses must be changed according to lane routing. + * Btw, ncr_offb() and ncr_offw() macros only apply to + * constants and so donnot generate bloated code. + */ + +#if defined(SCSI_NCR_BIG_ENDIAN) + +#define ncr_offb(o) (((o)&~3)+((~((o)&3))&3)) +#define ncr_offw(o) (((o)&~3)+((~((o)&3))&2)) + +#else + +#define ncr_offb(o) (o) +#define ncr_offw(o) (o) + +#endif + +/* + * If the CPU and the NCR use same endian-ness adressing, + * no byte reordering is needed for script patching. + * Macro cpu_to_scr() is to be used for script patching. + * Macro scr_to_cpu() is to be used for getting a DWORD + * from the script. + */ + +#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) + +#define cpu_to_scr(dw) cpu_to_le32(dw) +#define scr_to_cpu(dw) le32_to_cpu(dw) + +#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) + +#define cpu_to_scr(dw) cpu_to_be32(dw) +#define scr_to_cpu(dw) be32_to_cpu(dw) + +#else + +#define cpu_to_scr(dw) (dw) +#define scr_to_cpu(dw) (dw) + +#endif + +/* + * Access to the controller chip. + * + * If SCSI_NCR_IOMAPPED is defined, the driver will use + * normal IOs instead of the MEMORY MAPPED IO method + * recommended by PCI specifications. + * If all PCI bridges, host brigdes and architectures + * would have been correctly designed for PCI, this + * option would be useless. + * + * If the CPU and the NCR use same endian-ness adressing, + * no byte reordering is needed for accessing chip io + * registers. Functions suffixed by '_raw' are assumed + * to access the chip over the PCI without doing byte + * reordering. Functions suffixed by '_l2b' are + * assumed to perform little-endian to big-endian byte + * reordering, those suffixed by '_b2l' blah, blah, + * blah, ... + */ + +#if defined(SCSI_NCR_IOMAPPED) + +/* + * IO mapped only input / ouput + */ + +#define INB_OFF(o) inb (np->base_io + ncr_offb(o)) +#define OUTB_OFF(o, val) outb ((val), np->base_io + ncr_offb(o)) + +#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) + +#define INW_OFF(o) inw_l2b (np->base_io + ncr_offw(o)) +#define INL_OFF(o) inl_l2b (np->base_io + (o)) + +#define OUTW_OFF(o, val) outw_b2l ((val), np->base_io + ncr_offw(o)) +#define OUTL_OFF(o, val) outl_b2l ((val), np->base_io + (o)) + +#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) + +#define INW_OFF(o) inw_b2l (np->base_io + ncr_offw(o)) +#define INL_OFF(o) inl_b2l (np->base_io + (o)) + +#define OUTW_OFF(o, val) outw_l2b ((val), np->base_io + ncr_offw(o)) +#define OUTL_OFF(o, val) outl_l2b ((val), np->base_io + (o)) + +#else + +#define INW_OFF(o) inw_raw (np->base_io + ncr_offw(o)) +#define INL_OFF(o) inl_raw (np->base_io + (o)) + +#define OUTW_OFF(o, val) outw_raw ((val), np->base_io + ncr_offw(o)) +#define OUTL_OFF(o, val) outl_raw ((val), np->base_io + (o)) + +#endif /* ENDIANs */ + +#else /* defined SCSI_NCR_IOMAPPED */ + +/* + * MEMORY mapped IO input / output + */ + +#define INB_OFF(o) readb_raw((char *)np->reg + ncr_offb(o)) +#define OUTB_OFF(o, val) writeb_raw((val), (char *)np->reg + ncr_offb(o)) + +#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) + +#define INW_OFF(o) readw_l2b((char *)np->reg + ncr_offw(o)) +#define INL_OFF(o) readl_l2b((char *)np->reg + (o)) + +#define OUTW_OFF(o, val) writew_b2l((val), (char *)np->reg + ncr_offw(o)) +#define OUTL_OFF(o, val) writel_b2l((val), (char *)np->reg + (o)) + +#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) + +#define INW_OFF(o) readw_b2l((char *)np->reg + ncr_offw(o)) +#define INL_OFF(o) readl_b2l((char *)np->reg + (o)) + +#define OUTW_OFF(o, val) writew_l2b((val), (char *)np->reg + ncr_offw(o)) +#define OUTL_OFF(o, val) writel_l2b((val), (char *)np->reg + (o)) + +#else + +#define INW_OFF(o) readw_raw((char *)np->reg + ncr_offw(o)) +#define INL_OFF(o) readl_raw((char *)np->reg + (o)) + +#define OUTW_OFF(o, val) writew_raw((val), (char *)np->reg + ncr_offw(o)) +#define OUTL_OFF(o, val) writel_raw((val), (char *)np->reg + (o)) + +#endif + +#endif /* defined SCSI_NCR_IOMAPPED */ + +#define INB(r) INB_OFF (offsetof(struct ncr_reg,r)) +#define INW(r) INW_OFF (offsetof(struct ncr_reg,r)) +#define INL(r) INL_OFF (offsetof(struct ncr_reg,r)) + +#define OUTB(r, val) OUTB_OFF (offsetof(struct ncr_reg,r), (val)) +#define OUTW(r, val) OUTW_OFF (offsetof(struct ncr_reg,r), (val)) +#define OUTL(r, val) OUTL_OFF (offsetof(struct ncr_reg,r), (val)) + +/* + * Set bit field ON, OFF + */ + +#define OUTONB(r, m) OUTB(r, INB(r) | (m)) +#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m)) +#define OUTONW(r, m) OUTW(r, INW(r) | (m)) +#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m)) +#define OUTONL(r, m) OUTL(r, INL(r) | (m)) +#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m)) + +/* + * We normally want the chip to have a consistent view + * of driver internal data structures when we restart it. + * Thus these macros. + */ +#define OUTL_DSP(v) \ + do { \ + MEMORY_BARRIER(); \ + OUTL (nc_dsp, (v)); \ + } while (0) + +#define OUTONB_STD() \ + do { \ + MEMORY_BARRIER(); \ + OUTONB (nc_dcntl, (STD|NOCOM)); \ + } while (0) + + /* ** NCR53C8XX Device Ids */ @@ -486,6 +691,10 @@ #define PCI_DEVICE_ID_NCR_53C895A 0x12 #endif +#ifndef PCI_DEVICE_ID_NCR_53C875A +#define PCI_DEVICE_ID_NCR_53C875A 0x13 +#endif + #ifndef PCI_DEVICE_ID_NCR_53C1510D #define PCI_DEVICE_ID_NCR_53C1510D 0xa #endif @@ -525,15 +734,16 @@ #define FE_PFEN (1<<12) /* Prefetch enable */ #define FE_LDSTR (1<<13) /* Load/Store supported */ #define FE_RAM (1<<14) /* On chip RAM present */ -#define FE_CLK80 (1<<15) /* Board clock is 80 MHz */ +#define FE_VARCLK (1<<15) /* SCSI lock may vary */ #define FE_RAM8K (1<<16) /* On chip RAM sized 8Kb */ -#define FE_64BIT (1<<17) /* Supports 64-bit addressing */ +#define FE_64BIT (1<<17) /* Have a 64-bit PCI interface */ #define FE_IO256 (1<<18) /* Requires full 256 bytes in PCI space */ #define FE_NOPM (1<<19) /* Scripts handles phase mismatch */ #define FE_LEDC (1<<20) /* Hardware control of LED */ #define FE_DIFF (1<<21) /* Support Differential SCSI */ #define FE_ULTRA3 (1<<22) /* Ultra-3 80Mtrans/sec */ #define FE_66MHZ (1<<23) /* 66MHz PCI Support */ +#define FE_DAC (1<<24) /* Support DAC cycles (64 bit addressing) */ #define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) #define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80) @@ -574,35 +784,23 @@ FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF} \ , \ {PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, \ - FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} \ + FE_ULTRA|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} \ , \ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|\ - FE_RAM|FE_DIFF} \ - , \ - {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_DIFF} \ - , \ - {PCI_DEVICE_ID_NCR_53C875, 0x1f, "876", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_DIFF} \ + FE_WIDE|FE_ULTRA|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ + FE_RAM|FE_DIFF|FE_VARCLK} \ , \ - {PCI_DEVICE_ID_NCR_53C875, 0x2f, "875E", 6, 16, 5, \ + {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 6, 16, 5, \ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_DIFF} \ - , \ - {PCI_DEVICE_ID_NCR_53C875, 0xff, "876", 6, 16, 5, \ - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_DIFF} \ + FE_RAM|FE_DIFF|FE_VARCLK} \ , \ {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5, \ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM} \ + FE_RAM|FE_VARCLK} \ , \ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 6, 16, 5, \ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_DIFF} \ + FE_RAM|FE_DIFF|FE_VARCLK} \ , \ {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ @@ -610,23 +808,28 @@ , \ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 6, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC} \ + FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC} \ , \ {PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a", 6, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC} \ + FE_RAM|FE_RAM8K|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC} \ + , \ + {PCI_DEVICE_ID_NCR_53C875A, 0xff, "875a", 6, 31, 7, \ + FE_WIDE|FE_ULTRA|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ + FE_RAM|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC} \ , \ {PCI_DEVICE_ID_NCR_53C1510D, 0xff, "1510D", 7, 31, 7, \ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ FE_RAM|FE_IO256} \ , \ - {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010", 6, 62, 7, \ + {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010-33", 6, 62, 7, \ FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3} \ + FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3} \ , \ - {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010_66", 6, 62, 7, \ + {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66", 6, 62, 7, \ FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \ - FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3|FE_66MHZ} \ + FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3| \ + FE_66MHZ} \ } /* @@ -662,7 +865,6 @@ u_char scsi_parity; u_char disconnection; u_char special_features; - u_char ultra_scsi; u_char force_sync_nego; u_char reverse_probe; u_char pci_fix_up; @@ -696,15 +898,14 @@ SCSI_NCR_SETUP_SCSI_PARITY, \ SCSI_NCR_SETUP_DISCONNECTION, \ SCSI_NCR_SETUP_SPECIAL_FEATURES, \ - SCSI_NCR_SETUP_ULTRA_SCSI, \ SCSI_NCR_SETUP_FORCE_SYNC_NEGO, \ 0, \ 0, \ 1, \ - 1, \ + 0, \ SCSI_NCR_SETUP_DEFAULT_TAGS, \ SCSI_NCR_SETUP_DEFAULT_SYNC, \ - 0x0200, \ + 0x00, \ 7, \ SCSI_NCR_SETUP_LED_PIN, \ 1, \ @@ -727,7 +928,6 @@ { \ 0, \ 1, \ - 0, \ 0, \ 0, \ 0, \ diff -u --recursive --new-file v2.4.2/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.4.2/linux/drivers/sound/Config.in Wed Feb 21 18:20:34 2001 +++ linux/drivers/sound/Config.in Tue Mar 6 19:28:32 2001 @@ -6,7 +6,7 @@ # Prompt user for primary drivers. -dep_tristate ' C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND +dep_tristate ' C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then bool ' Enable S/PDIF loop for CMI8738' CONFIG_SOUND_CMPCI_SPDIFLOOP bool ' Enable 4 channel mode for CMI8738' CONFIG_SOUND_CMPCI_4CH diff -u --recursive --new-file v2.4.2/linux/drivers/sound/awe_wave.c linux/drivers/sound/awe_wave.c --- v2.4.2/linux/drivers/sound/awe_wave.c Wed Feb 21 18:20:34 2001 +++ linux/drivers/sound/awe_wave.c Fri Mar 2 11:12:11 2001 @@ -206,7 +206,7 @@ int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */ int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE -static int isapnp = 1; +static int isapnp = -1; #else static int isapnp = 0; #endif @@ -4843,10 +4843,12 @@ if (isapnp) { if (awe_probe_isapnp(&io) < 0) { printk(KERN_ERR "AWE32: No ISAPnP cards found\n"); - return 0; + if (isapnp != -1) + return 0; + } else { + setup_ports(io, 0, 0); + return 1; } - setup_ports(io, 0, 0); - return 1; } #endif /* isapnp */ diff -u --recursive --new-file v2.4.2/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.4.2/linux/drivers/sound/gus_midi.c Sun Nov 12 20:35:35 2000 +++ linux/drivers/sound/gus_midi.c Tue Mar 6 19:28:32 2001 @@ -15,7 +15,7 @@ * Added __init to gus_midi_init() */ -#include "linux/init.h" +#include #include "sound_config.h" #include "gus.h" diff -u --recursive --new-file v2.4.2/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c --- v2.4.2/linux/drivers/sound/i810_audio.c Wed Feb 21 18:20:34 2001 +++ linux/drivers/sound/i810_audio.c Tue Mar 6 19:44:37 2001 @@ -194,8 +194,12 @@ /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ #define NR_AC97 2 +/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */ +/* stream at a minimum for this card to be happy */ static const unsigned sample_size[] = { 1, 2, 2, 4 }; -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; +/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */ +/* values are one less than might be expected */ +static const unsigned sample_shift[] = { -1, 0, 0, 1 }; enum { ICH82801AA = 0, @@ -246,7 +250,8 @@ unsigned char fmt, enable; /* hardware channel */ - struct i810_channel *channel; + struct i810_channel *read_channel; + struct i810_channel *write_channel; /* OSS buffer management stuff */ void *rawbuf; @@ -258,7 +263,7 @@ /* our buffer acts like a circular ring */ unsigned hwptr; /* where dma last started, updated by update_ptr */ unsigned swptr; /* where driver last clear/filled, updated by read/write */ - int count; /* bytes to be comsumed or been generated by dma machine */ + int count; /* bytes to be consumed or been generated by dma machine */ unsigned total_bytes; /* total bytes dmaed by hardware */ unsigned error; /* number of over/underruns */ @@ -313,6 +318,7 @@ /* Function support */ struct i810_channel *(*alloc_pcm_channel)(struct i810_card *); struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *); + struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *); void (*free_pcm_channel)(struct i810_card *, int chan); }; @@ -356,9 +362,6 @@ if(card->channel[1].used==1) return NULL; card->channel[1].used=1; - card->channel[1].offset = 0; - card->channel[1].port = 0x10; - card->channel[1].num=1; return &card->channel[1]; } @@ -367,12 +370,17 @@ if(card->channel[0].used==1) return NULL; card->channel[0].used=1; - card->channel[0].offset = 0; - card->channel[0].port = 0x00; - card->channel[1].num=0; return &card->channel[0]; } +static struct i810_channel *i810_alloc_rec_mic_channel(struct i810_card *card) +{ + if(card->channel[2].used==1) + return NULL; + card->channel[2].used=1; + return &card->channel[2]; +} + static void i810_free_pcm_channel(struct i810_card *card, int channel) { card->channel[channel].used=0; @@ -382,7 +390,7 @@ static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate) { struct dmabuf *dmabuf = &state->dmabuf; - u32 dacp; + u32 dacp, new_rate; struct ac97_codec *codec=state->card->ac97_codec[0]; if(!(state->card->ac97_features&0x0001)) @@ -395,6 +403,7 @@ rate = 48000; if (rate < 8000) rate = 8000; + dmabuf->rate = rate; /* * Adjust for misclocked crap @@ -402,12 +411,6 @@ rate = ( rate * clocking)/48000; - /* Analog codecs can go lower via magic registers but others - might not */ - - if(rate < 8000) - rate = 8000; - if(rate != i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE)) { /* Power down the DAC */ @@ -415,24 +418,25 @@ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200); /* Load the rate and read the effective rate */ i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate); - rate=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE); + new_rate=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE); /* Power it back up */ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp); + if(new_rate != rate) { + dmabuf->rate = (new_rate * 48000)/clocking; + rate = new_rate; + } } - rate=(rate * 48000) / clocking; - dmabuf->rate = rate; #ifdef DEBUG - printk("i810_audio: called i810_set_dac_rate : rate = %d\n", rate); + printk("i810_audio: called i810_set_dac_rate : rate = %d/%d\n", dmabuf->rate, rate); #endif - - return rate; + return dmabuf->rate; } /* set recording sample rate */ static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate) { struct dmabuf *dmabuf = &state->dmabuf; - u32 dacp; + u32 dacp, new_rate; struct ac97_codec *codec=state->card->ac97_codec[0]; if(!(state->card->ac97_features&0x0001)) @@ -445,6 +449,7 @@ rate = 48000; if (rate < 8000) rate = 8000; + dmabuf->rate = rate; /* * Adjust for misclocked crap @@ -452,12 +457,6 @@ rate = ( rate * clocking)/48000; - /* Analog codecs can go lower via magic registers but others - might not */ - - if(rate < 8000) - rate = 8000; - if(rate != i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE)) { /* Power down the ADC */ @@ -465,16 +464,18 @@ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100); /* Load the rate and read the effective rate */ i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate); - rate=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE); + new_rate=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE); /* Power it back up */ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp); + if(new_rate != rate) { + dmabuf->rate = (new_rate * 48000)/clocking; + rate = new_rate; + } } - rate = (rate * 48000) / clocking; - dmabuf->rate = rate; #ifdef DEBUG - printk("i810_audio: called i810_set_adc_rate : rate = %d\n", rate); + printk("i810_audio: called i810_set_adc_rate : rate = %d/%d\n", dmabuf->rate, rate); #endif - return rate; + return dmabuf->rate; } /* prepare channel attributes for playback */ @@ -508,10 +509,18 @@ { struct dmabuf *dmabuf = &state->dmabuf; unsigned int civ, offset; - struct i810_channel *c = dmabuf->channel; + struct i810_channel *c; if (!dmabuf->enable) return 0; + if (dmabuf->enable & DAC_RUNNING) + c = dmabuf->write_channel; + else if (dmabuf->enable & ADC_RUNNING) + c = dmabuf->read_channel; + else { + printk("i810_audio: invalid dmabuf->enable state in get_dma_addr\n"); + return 0; + } do { civ = inb(state->card->iobase+c->port+OFF_CIV); offset = (civ + 1) * (dmabuf->dmasize/SG_LEN) - @@ -523,12 +532,17 @@ return offset; } -static void resync_dma_ptrs(struct i810_state *state) +static void resync_dma_ptrs(struct i810_state *state, int rec) { struct dmabuf *dmabuf = &state->dmabuf; - struct i810_channel *c = dmabuf->channel; + struct i810_channel *c; int offset; - + + if(rec) { + c = dmabuf->read_channel; + } else { + c = dmabuf->write_channel; + } offset = inb(state->card->iobase+c->port+OFF_CIV); offset *= (dmabuf->dmasize/SG_LEN); @@ -597,23 +611,20 @@ spin_lock_irqsave(&card->lock, flags); if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) { - if(!(dmabuf->enable&DAC_RUNNING)) - { - dmabuf->enable |= DAC_RUNNING; - outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR); - } + dmabuf->enable |= DAC_RUNNING; + outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR); } spin_unlock_irqrestore(&card->lock, flags); } -#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) +#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) #define DMABUF_MINORDER 1 /* allocate DMA buffer, playback and recording buffer should be allocated seperately */ static int alloc_dmabuf(struct i810_state *state) { struct dmabuf *dmabuf = &state->dmabuf; - void *rawbuf; + void *rawbuf= NULL; int order; struct page *page, *pend; @@ -664,6 +675,7 @@ static int prog_dmabuf(struct i810_state *state, unsigned rec) { struct dmabuf *dmabuf = &state->dmabuf; + struct i810_channel *c; struct sg_item *sg; unsigned bytepersec; unsigned bufsize; @@ -673,7 +685,7 @@ int i; spin_lock_irqsave(&state->card->lock, flags); - resync_dma_ptrs(state); + resync_dma_ptrs(state, rec); dmabuf->total_bytes = 0; dmabuf->count = dmabuf->error = 0; spin_unlock_irqrestore(&state->card->lock, flags); @@ -684,7 +696,8 @@ return ret; /* FIXME: figure out all this OSS fragment stuff */ - bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt]; + /* sample_shift is for 16 byte samples, add an extra shift for bytes */ + bytepersec = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1); bufsize = PAGE_SIZE << dmabuf->buforder; if (dmabuf->ossfragshift) { if ((1000 << dmabuf->ossfragshift) < bytepersec) @@ -709,44 +722,52 @@ memset(dmabuf->rawbuf, (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80, dmabuf->dmasize); - /* - * Now set up the ring - */ - - sg=&dmabuf->channel->sg[0]; fragsize = bufsize / SG_LEN; - /* - * Load up 32 sg entries and take an interrupt at half - * way (we might want more interrupts later..) + * Now set up the ring */ + if(dmabuf->read_channel) + c = dmabuf->read_channel; + else + c = dmabuf->write_channel; + while(c != NULL) { + sg=&c->sg[0]; + /* + * Load up 32 sg entries and take an interrupt at half + * way (we might want more interrupts later..) + */ - for(i=0;i<32;i++) - { - sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i); - sg->control=(fragsize>>1); - sg->control|=CON_IOC; - sg++; - } + for(i=0;i<32;i++) + { + sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i); + sg->control=(fragsize>>sample_shift[dmabuf->fmt]); + sg->control|=CON_IOC; + sg++; + } + spin_lock_irqsave(&state->card->lock, flags); + outb(2, state->card->iobase+c->port+OFF_CR); /* reset DMA machine */ + outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR); + outb(31, state->card->iobase+c->port+OFF_LVI); + outb(0, state->card->iobase+c->port+OFF_CIV); - spin_lock_irqsave(&state->card->lock, flags); - outb(2, state->card->iobase+dmabuf->channel->port+OFF_CR); /* reset DMA machine */ - outl(virt_to_bus(&dmabuf->channel->sg[0]), state->card->iobase+dmabuf->channel->port+OFF_BDBAR); - outb(16, state->card->iobase+dmabuf->channel->port+OFF_LVI); - outb(0, state->card->iobase+dmabuf->channel->port+OFF_CIV); + if (c == dmabuf->read_channel) { + i810_rec_setup(state); + } else { + i810_play_setup(state); + } + spin_unlock_irqrestore(&state->card->lock, flags); - if (rec) { - i810_rec_setup(state); - } else { - i810_play_setup(state); + if(c != dmabuf->write_channel) + c = dmabuf->write_channel; + else + c = NULL; } - spin_unlock_irqrestore(&state->card->lock, flags); - + /* set the ready flag for the dma buffer */ dmabuf->ready = 1; #ifdef DEBUG - printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, " + printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d,\n\tnumfrag = %d, " "fragsize = %d dmasize = %d\n", dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, dmabuf->fragsize, dmabuf->dmasize); @@ -912,7 +933,6 @@ { int i; -// printk("CHANNEL IRQ .. "); for(i=0;istates[i]; @@ -924,38 +944,35 @@ continue; if(!state->dmabuf.ready) continue; - c=state->dmabuf.channel; + if(state->dmabuf.enable & DAC_RUNNING) + c=state->dmabuf.write_channel; + else + c=state->dmabuf.read_channel; port+=c->port; -// printk("PORT %lX (", port); - status = inw(port + OFF_SR); -// printk("ST%d ", status); - - if(status & DMA_INT_LVI) - { - /* Back to the start */ -// printk("LVI - STOP"); - outb((inb(port+OFF_CIV)-1)&31, port+OFF_LVI); - i810_update_ptr(state); - outb(0, port + OFF_CR); - } if(status & DMA_INT_COMPLETE) { int x; /* Keep the card chasing its tail */ outb(x=((inb(port+OFF_CIV)-1)&31), port+OFF_LVI); i810_update_ptr(state); -// printk("COMP%d ",x); } -// printk(")"); + if(status & DMA_INT_LVI) + { + /* Back to the start */ + i810_update_ptr(state); + outb(0, port + OFF_CR); + } outw(status & DMA_INT_MASK, port + OFF_SR); } -// printk("\n"); } +static u32 jiff = 0; +static u32 jiff_count = 0; + static void i810_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct i810_card *card = (struct i810_card *)dev_id; @@ -964,13 +981,13 @@ spin_lock(&card->lock); status = inl(card->iobase + GLOB_STA); + if(!(status & INT_MASK)) { spin_unlock(&card->lock); return; /* not for us */ } -// printk("Interrupt %X: ", status); if(status & (INT_PO|INT_PI|INT_MC)) i810_channel_interrupt(card); @@ -1003,6 +1020,15 @@ return -ESPIPE; if (dmabuf->mapped) return -ENXIO; + if (dmabuf->enable & DAC_RUNNING) + return -ENODEV; + if (!dmabuf->read_channel) { + dmabuf->ready = 0; + dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); + if (!dmabuf->read_channel) { + return -ENODEV; + } + } if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) @@ -1100,6 +1126,14 @@ return -ESPIPE; if (dmabuf->mapped) return -ENXIO; + if (dmabuf->enable & ADC_RUNNING) + return -ENODEV; + if (!dmabuf->write_channel) { + dmabuf->ready = 0; + dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); + if(!dmabuf->write_channel) + return -ENODEV; + } if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; if (!access_ok(VERIFY_READ, buffer, count)) @@ -1132,8 +1166,8 @@ return ret; } /* Not strictly correct but works */ - tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); - tmo >>= sample_shift[dmabuf->fmt]; + tmo = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1); + tmo = dmabuf->dmasize * HZ / tmo; /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that @@ -1187,22 +1221,27 @@ unsigned int mask = 0; if (file->f_mode & FMODE_WRITE) { + if (!dmabuf->write_channel) + return 0; if (!dmabuf->ready && prog_dmabuf(state, 0)) return 0; poll_wait(file, &dmabuf->wait, wait); - } - if (file->f_mode & FMODE_READ) { + } else { + // don't do both read and write paths or we won't get woke up properly + // when we have a file with both permissions + if (!dmabuf->read_channel) + return 0; if (!dmabuf->ready && prog_dmabuf(state, 1)) return 0; poll_wait(file, &dmabuf->wait, wait); } spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); - if (file->f_mode & FMODE_READ) { + if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) { if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLIN | POLLRDNORM; } - if (file->f_mode & FMODE_WRITE) { + if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING) { if (dmabuf->mapped) { if (dmabuf->count >= (signed)dmabuf->fragsize) mask |= POLLOUT | POLLWRNORM; @@ -1223,11 +1262,19 @@ int ret = -EINVAL; unsigned long size; + /* + * Until we figure out a few problems + */ + lock_kernel(); if (vma->vm_flags & VM_WRITE) { + if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) + goto out; if ((ret = prog_dmabuf(state, 0)) != 0) goto out; } else if (vma->vm_flags & VM_READ) { + if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) + goto out; if ((ret = prog_dmabuf(state, 1)) != 0) goto out; } else @@ -1245,6 +1292,9 @@ goto out; dmabuf->mapped = 1; ret = 0; +#ifdef DEBUG + printk("i810_audio: mmap'ed %d bytes of data space\n", size); +#endif out: unlock_kernel(); return ret; @@ -1277,14 +1327,14 @@ stop_dac(state); synchronize_irq(); dmabuf->ready = 0; - resync_dma_ptrs(state); + resync_dma_ptrs(state, 0); dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->count = dmabuf->total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(state); synchronize_irq(); - resync_dma_ptrs(state); + resync_dma_ptrs(state, 1); dmabuf->ready = 0; dmabuf->swptr = dmabuf->hwptr = 0; dmabuf->count = dmabuf->total_bytes = 0; @@ -1325,23 +1375,23 @@ if (file->f_mode & FMODE_WRITE) { stop_dac(state); dmabuf->ready = 0; - dmabuf->fmt = I810_FMT_STEREO; + dmabuf->fmt |= I810_FMT_STEREO; } if (file->f_mode & FMODE_READ) { stop_adc(state); dmabuf->ready = 0; - dmabuf->fmt = I810_FMT_STEREO; + dmabuf->fmt |= I810_FMT_STEREO; } return 0; case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf(state, 0))) + if (!dmabuf->ready && (val = prog_dmabuf(state, 0))) return val; return put_user(dmabuf->fragsize, (int *)arg); } if (file->f_mode & FMODE_READ) { - if ((val = prog_dmabuf(state, 1))) + if (!dmabuf->ready && (val = prog_dmabuf(state, 1))) return val; return put_user(dmabuf->fragsize, (int *)arg); } @@ -1356,10 +1406,12 @@ if (file->f_mode & FMODE_WRITE) { stop_dac(state); dmabuf->ready = 0; + dmabuf->fmt |= I810_FMT_16BIT; } if (file->f_mode & FMODE_READ) { stop_adc(state); dmabuf->ready = 0; + dmabuf->fmt |= I810_FMT_16BIT; } } return put_user(AFMT_S16_LE, (int *)arg); @@ -1391,6 +1443,7 @@ if (val != 1 && val != 2 && val != 4) return -EINVAL; dmabuf->subdivision = val; + dmabuf->ready = 0; return 0; case SNDCTL_DSP_SETFRAGMENT: @@ -1405,13 +1458,14 @@ dmabuf->ossfragshift = 15; if (dmabuf->ossmaxfrags < 4) dmabuf->ossmaxfrags = 4; + dmabuf->ready = 0; return 0; case SNDCTL_DSP_GETOSPACE: if (!(file->f_mode & FMODE_WRITE)) return -EINVAL; - if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0) + if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); @@ -1425,7 +1479,7 @@ case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) return -EINVAL; - if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0) + if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) return val; spin_lock_irqsave(&state->card->lock, flags); i810_update_ptr(state); @@ -1446,30 +1500,40 @@ case SNDCTL_DSP_GETTRIGGER: val = 0; - if (file->f_mode & FMODE_READ && dmabuf->enable) + if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && dmabuf->enable) + if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING) val |= PCM_ENABLE_OUTPUT; return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: if (get_user(val, (int *)arg)) return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - start_adc(state); - } else - stop_adc(state); + if (file->f_mode & FMODE_READ && val & PCM_ENABLE_INPUT) { + if (dmabuf->enable & DAC_RUNNING) + return -ENODEV; + if (!dmabuf->read_channel) { + dmabuf->ready = 0; + dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); + if (!dmabuf->read_channel) + return -ENODEV; + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + return ret; + start_adc(state); } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; - start_dac(state); - } else - stop_dac(state); + if (file->f_mode & FMODE_WRITE && val & PCM_ENABLE_OUTPUT) { + if (dmabuf->enable & ADC_RUNNING) + return -ENODEV; + if (!dmabuf->write_channel) { + dmabuf->ready = 0; + dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); + if (!dmabuf->write_channel) + return -ENODEV; + } + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + return ret; + start_dac(state); } return 0; @@ -1558,18 +1622,6 @@ return -ENODEV; found_virt: - /* found a free virtual channel, allocate hardware channels */ - if(file->f_mode & FMODE_READ) - dmabuf->channel = card->alloc_rec_pcm_channel(card); - else - dmabuf->channel = card->alloc_pcm_channel(card); - - if (dmabuf->channel == NULL) { - kfree (card->states[i]); - card->states[i] = NULL;; - return -ENODEV; - } - /* initialize the virtual channel */ state->virt = i; state->card = card; @@ -1578,28 +1630,34 @@ init_MUTEX(&state->open_sem); file->private_data = state; + /* allocate hardware channels */ + if(file->f_mode & FMODE_READ) { + if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) { + kfree (card->states[i]); + card->states[i] = NULL;; + return -ENODEV; + } + i810_set_adc_rate(state, 48000); + } + if(file->f_mode & FMODE_WRITE) { + if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) { + kfree (card->states[i]); + card->states[i] = NULL;; + return -ENODEV; + } + i810_set_dac_rate(state, 48000); + } + down(&state->open_sem); /* set default sample format. According to OSS Programmer's Guide /dev/dsp should be default to unsigned 8-bits, mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */ - if (file->f_mode & FMODE_WRITE) { - dmabuf->fmt &= ~I810_FMT_MASK; - dmabuf->fmt |= I810_FMT_16BIT; - dmabuf->ossfragshift = 0; - dmabuf->ossmaxfrags = 0; - dmabuf->subdivision = 0; - i810_set_dac_rate(state, 48000); - } - - if (file->f_mode & FMODE_READ) { - dmabuf->fmt &= ~I810_FMT_MASK; - dmabuf->fmt |= I810_FMT_16BIT; - dmabuf->ossfragshift = 0; - dmabuf->ossmaxfrags = 0; - dmabuf->subdivision = 0; - i810_set_adc_rate(state, 48000); - } + dmabuf->fmt &= ~I810_FMT_MASK; + dmabuf->fmt |= I810_FMT_16BIT; + dmabuf->ossfragshift = 0; + dmabuf->ossmaxfrags = 0; + dmabuf->subdivision = 0; state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&state->open_sem); @@ -1614,29 +1672,33 @@ lock_kernel(); if (file->f_mode & FMODE_WRITE) { - i810_clear_tail(state); - drain_dac(state, file->f_flags & O_NONBLOCK); } /* stop DMA state machine and free DMA buffers/channels */ down(&state->open_sem); - if (file->f_mode & FMODE_WRITE) { + if (dmabuf->enable & DAC_RUNNING) { + i810_clear_tail(state); + drain_dac(state, file->f_flags & O_NONBLOCK); stop_dac(state); dealloc_dmabuf(state); - state->card->free_pcm_channel(state->card, dmabuf->channel->num); } - if (file->f_mode & FMODE_READ) { + if(dmabuf->enable & ADC_RUNNING) { stop_adc(state); dealloc_dmabuf(state); - state->card->free_pcm_channel(state->card, dmabuf->channel->num); + } + if (file->f_mode & FMODE_WRITE) { + state->card->free_pcm_channel(state->card, dmabuf->write_channel->num); + } + if (file->f_mode & FMODE_READ) { + state->card->free_pcm_channel(state->card, dmabuf->read_channel->num); } /* we're covered by the open_sem */ up(&state->open_sem); - kfree(state->card->states[state->virt]); state->card->states[state->virt] = NULL; + kfree(state); unlock_kernel(); return 0; @@ -1688,16 +1750,11 @@ for (card = devs; card != NULL; card = card->next) for (i = 0; i < NR_AC97; i++) if (card->ac97_codec[i] != NULL && - card->ac97_codec[i]->dev_mixer == minor) - goto match; - - if (!card) - return -ENODEV; - - match: - file->private_data = card->ac97_codec[i]; - - return 0; + card->ac97_codec[i]->dev_mixer == minor) { + file->private_data = card->ac97_codec[i]; + return 0; + } + return -ENODEV; } static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, @@ -1788,10 +1845,6 @@ printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n"); else { - /* Enable variable rate mode */ - i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9); - i810_ac97_set(codec,AC97_EXTENDED_STATUS, - i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800); /* power up everything, modify this when implementing power saving */ i810_ac97_set(codec, AC97_POWER_CONTROL, i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); @@ -1804,6 +1857,11 @@ schedule_timeout(HZ/20); } + /* Enable variable rate mode */ + i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9); + i810_ac97_set(codec,AC97_EXTENDED_STATUS, + i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800); + if(!(i810_ac97_get(codec, AC97_EXTENDED_STATUS)&1)) { printk(KERN_WARNING "i810_audio: Codec refused to allow VRA, using 48Khz only.\n"); @@ -1865,7 +1923,17 @@ card->alloc_pcm_channel = i810_alloc_pcm_channel; card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel; + card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel; card->free_pcm_channel = i810_free_pcm_channel; + card->channel[0].offset = 0; + card->channel[0].port = 0x00; + card->channel[0].num=0; + card->channel[1].offset = 0; + card->channel[1].port = 0x10; + card->channel[1].num=1; + card->channel[2].offset = 0; + card->channel[2].port = 0x20; + card->channel[2].num=2; /* claim our iospace and irq */ request_region(card->iobase, 64, card_names[pci_id->driver_data]); @@ -1938,20 +2006,86 @@ remove: i810_remove, }; +static void __init i810_configure_clocking (void) +{ + struct i810_card *card; + struct i810_state *state; + struct dmabuf *dmabuf; + unsigned int i, offset, new_offset; + unsigned long flags; + + card = devs; + /* We could try to set the clocking for multiple cards, but can you even have + * more than one i810 in a machine? Besides, clocking is global, so unless + * someone actually thinks more than one i810 in a machine is possible and + * decides to rewrite that little bit, setting the rate for more than one card + * is a waste of time. + */ + if(card != NULL) { + state = card->states[0] = (struct i810_state *) + kmalloc(sizeof(struct i810_state), GFP_KERNEL); + if (state == NULL) + return; + memset(state, 0, sizeof(struct i810_state)); + dmabuf = &state->dmabuf; + + dmabuf->write_channel = card->alloc_pcm_channel(card); + state->virt = 0; + state->card = card; + state->magic = I810_STATE_MAGIC; + init_waitqueue_head(&dmabuf->wait); + init_MUTEX(&state->open_sem); + dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; + i810_set_dac_rate(state, 48000); + if(prog_dmabuf(state, 0) != 0) { + goto config_out_nodmabuf; + } + if(dmabuf->dmasize < 16384) { + goto config_out; + } + dmabuf->count = dmabuf->dmasize; + save_flags(flags); + cli(); + start_dac(state); + offset = i810_get_dma_addr(state); + mdelay(50); + new_offset = i810_get_dma_addr(state); + stop_dac(state); + outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); + restore_flags(flags); + i = new_offset - offset; + printk("i810_audio: %d bytes in 50 milliseconds\n", i); + i = i / 4 * 20; + if (i > 48500 || i < 47500) { + clocking = clocking * clocking / i; + printk("i810_audio: setting clocking to %d to compensate\n", clocking); + } +config_out_nodmabuf: + dealloc_dmabuf(state); +config_out: + state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num); + kfree(state); + card->states[0] = NULL; + } +} + static int __init i810_init_module (void) { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - if(ftsodell==1) - clocking=41194; - printk(KERN_INFO "Intel 810 + AC97 Audio, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); if (!pci_register_driver(&i810_pci_driver)) { pci_unregister_driver(&i810_pci_driver); return -ENODEV; + } + if(ftsodell != 0) { + printk("i810_audio: ftsodell is now a deprecated option.\n"); + } + if(clocking == 48000) { + i810_configure_clocking(); } return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c --- v2.4.2/linux/drivers/sound/maestro.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/maestro.c Fri Mar 2 11:12:11 2001 @@ -1427,7 +1427,7 @@ apu_set_register(ess, channel, 10, 0x8F08); } - /* clear WP interupts */ + /* clear WP interrupts */ outw(1, ess->card->iobase+0x04); /* enable WP ints */ outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); @@ -1559,7 +1559,7 @@ apu_set_register(ess, channel, 11, route); } - /* clear WP interupts */ + /* clear WP interrupts */ outw(1, ess->card->iobase+0x04); /* enable WP ints */ outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18); @@ -3446,10 +3446,10 @@ printk(KERN_INFO "maestro: not attempting power management.\n"); else { if(!parse_power(card,pcidev)) - printk(KERN_INFO "maestro: no PCI power managment interface found.\n"); + printk(KERN_INFO "maestro: no PCI power management interface found.\n"); else { pci_read_config_dword(pcidev, card->power_regs, &n); - printk(KERN_INFO "maestro: PCI power managment capability: 0x%x\n",n>>16); + printk(KERN_INFO "maestro: PCI power management capability: 0x%x\n",n>>16); } } diff -u --recursive --new-file v2.4.2/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c --- v2.4.2/linux/drivers/sound/maestro3.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/maestro3.c Fri Mar 2 18:38:39 2001 @@ -28,6 +28,9 @@ * Shouts go out to Mike "DJ XPCom" Ang. * * History + * v1.22 - Feb 28 2001 - Zach Brown + * allocate mem at insmod/setup, rather than open + * limit pci dma addresses to 28bit, thanks guys. * v1.21 - Feb 04 2001 - Zach Brown * fix up really dumb notifier -> suspend oops * v1.20 - Jan 30 2001 - Zach Brown @@ -150,7 +153,7 @@ #define M_DEBUG 1 -#define DRIVER_VERSION "1.21" +#define DRIVER_VERSION "1.22" #define M3_MODULE_NAME "maestro3" #define PFX M3_MODULE_NAME ": " @@ -330,6 +333,12 @@ MODULE_DEVICE_TABLE (pci, m3_id_table); +/* + * reports seem to indicate that the m3 is limited + * to 28bit bus addresses. aaaargggh... + */ +#define M3_PCI_DMA_MASK 0x0fffffff + static unsigned ld2(unsigned int x) { @@ -1943,6 +1952,9 @@ static void free_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db) { + if(db->rawbuf == NULL) + return; + DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db); { @@ -1967,7 +1979,7 @@ int minor = MINOR(inode->i_rdev); struct m3_card *c; struct m3_state *s = NULL; - int i, ret = 0; + int i; unsigned char fmtm = ~0, fmts = 0; unsigned long flags; @@ -2013,10 +2025,6 @@ spin_lock_irqsave(&s->lock, flags); if (file->f_mode & FMODE_READ) { - if(allocate_dmabuf(s->card->pcidev, &(s->dma_adc))) { - ret = -ENOMEM; - goto out; - } fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT); if ((minor & 0xf) == SND_DEV_DSP16) fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; @@ -2025,10 +2033,6 @@ set_adc_rate(s, 8000); } if (file->f_mode & FMODE_WRITE) { - if(allocate_dmabuf(s->card->pcidev, &(s->dma_dac))) { - ret = -ENOMEM; - goto out; - } fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT); if ((minor & 0xf) == SND_DEV_DSP16) fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT; @@ -2040,7 +2044,6 @@ s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); MOD_INC_USE_COUNT; -out: up(&s->open_sem); spin_unlock_irqrestore(&s->lock, flags); return 0; @@ -2064,7 +2067,6 @@ m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index); nuke_lists(s->card, &(s->dma_dac)); } - free_dmabuf(s->card->pcidev, &(s->dma_dac)); } if (file->f_mode & FMODE_READ) { stop_adc(s); @@ -2072,7 +2074,6 @@ m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index); nuke_lists(s->card, &(s->dma_adc)); } - free_dmabuf(s->card->pcidev, &(s->dma_adc)); } s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); @@ -2594,8 +2595,8 @@ DPRINTK(DPMOD, "in maestro_install\n"); - if (!pci_dma_supported(pci_dev, 0xffffffff)) { - printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n"); + if (!pci_dma_supported(pci_dev, M3_PCI_DMA_MASK)) { + printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n"); return -ENODEV; } @@ -2604,6 +2605,8 @@ pci_set_master(pci_dev); + pci_dev->dma_mask = M3_PCI_DMA_MASK; + if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) { printk(KERN_WARNING PFX "out of memory\n"); return -ENOMEM; @@ -2681,6 +2684,12 @@ if ((s->dev_audio = register_sound_dsp(&m3_audio_fops, -1)) < 0) { break; } + + if( allocate_dmabuf(card->pcidev, &(s->dma_adc)) || + allocate_dmabuf(card->pcidev, &(s->dma_dac))) { + ret = -ENOMEM; + goto out; + } } if(request_irq(card->irq, m3_interrupt, SA_SHIRQ, card_names[card->card_type], card)) { @@ -2734,8 +2743,12 @@ for(i=0;ichannels[i]; - if(s->dev_audio != -1) - unregister_sound_dsp(s->dev_audio); + if(s->dev_audio < 0) + continue; + + unregister_sound_dsp(s->dev_audio); + free_dmabuf(card->pcidev, &s->dma_adc); + free_dmabuf(card->pcidev, &s->dma_dac); } release_region(card->iobase, 256); diff -u --recursive --new-file v2.4.2/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.4.2/linux/drivers/sound/msnd_pinnacle.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/msnd_pinnacle.c Tue Mar 6 19:44:37 2001 @@ -47,7 +47,9 @@ #include "sound_config.h" #include "sound_firmware.h" #ifdef MSND_CLASSIC +# ifndef __alpha__ # define SLOWIO +# endif #endif #include "msnd.h" #ifdef MSND_CLASSIC @@ -1403,7 +1405,6 @@ return 0; } -#ifdef MODULE static void __exit unload_multisound(void) { release_region(dev.io, dev.numio); @@ -1412,7 +1413,6 @@ unregister_sound_dsp(dev.dsp_minor); msnd_unregister(&dev); } -#endif #ifndef MSND_CLASSIC diff -u --recursive --new-file v2.4.2/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c --- v2.4.2/linux/drivers/sound/opl3sa2.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/opl3sa2.c Fri Mar 2 18:38:39 2001 @@ -806,6 +806,16 @@ #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + +struct isapnp_device_id isapnp_opl3sa2_list[] __initdata = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), + NULL }, + {0} +}; + +MODULE_DEVICE_TABLE(isapnp, isapnp_opl3sa2_list); + static int __init opl3sa2_isapnp_probe(struct address_info* hw_cfg, struct address_info* mss_cfg, struct address_info* mpu_cfg, @@ -908,13 +918,17 @@ &cfg_mpu[card], card) < 0) { if(!opl3sa2_cards_num) - printk(KERN_NOTICE "opl3sa2: No cards found\n"); - break; + printk(KERN_INFO "opl3sa2: No PnP cards found\n"); + if(io == -1) + break; + isapnp=0; + printk(KERN_INFO "opl3sa2: Search for a card at 0x%d.\n", io); + /* Fall through */ } #endif /* If a user wants an I/O then assume they meant it */ - if(!isapnp && io == -1 ) { + if(!isapnp) { if(io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1) { printk(KERN_ERR diff -u --recursive --new-file v2.4.2/linux/drivers/sound/skeleton.c linux/drivers/sound/skeleton.c --- v2.4.2/linux/drivers/sound/skeleton.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/skeleton.c Fri Mar 2 18:38:39 2001 @@ -4,7 +4,7 @@ * (c) 1998 Red Hat Software * * This software may be used and distributed according to the - * terms of the GNU Public License, incorporated herein by + * terms of the GNU General Public License, incorporated herein by * reference. * * This example is designed to be built in the linux/drivers/sound diff -u --recursive --new-file v2.4.2/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.2/linux/drivers/sound/trident.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/trident.c Fri Mar 2 18:38:39 2001 @@ -13,6 +13,7 @@ * Aaron Holtzman * Ollie Lho SiS 7018 Audio Core Support * Ching-Ling Lee ALi 5451 Audio Core Support + * Matt Wu ALi 5451 Audio Core Support * * * This program is free software; you can redistribute it and/or modify @@ -30,6 +31,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * History + * v0.14.7 + * Feb 06 2001 Matt Wu + * Fix ac97 initialization + * Fix bug: an extra tail will be played when playing + * Jan 05 2001 Matt Wu + * Implement multi-channels and S/PDIF in support for ALi 1535+ * v0.14.6 * Nov 1 2000 Ching-Ling Lee * Fix the bug of memory leak when swithing 5.1-channels to 2 channels. @@ -140,12 +147,12 @@ /* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only have 2 SDATA_IN lines (currently) */ -#define NR_AC97 2 +#define NR_AC97 2 /* minor number of /dev/swmodem (temporary, experimental) */ #define SND_DEV_SWMODEM 7 -static const unsigned ali_multi_channels_5_1[] = { ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL}; +static const unsigned ali_multi_channels_5_1[] = { /*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,*/ ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL}; static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; @@ -312,6 +319,10 @@ struct trident_channel *(*alloc_rec_pcm_channel)(struct trident_card *); void (*free_pcm_channel)(struct trident_card *, unsigned int chan); void (*address_interrupt)(struct trident_card *); + + /* Add by Matt Wu 01-05-2001 for spdif in */ + int multi_channel_use_count; + int rec_channel_use_count; }; /* table to map from CHANNELMASK to channel attribute for SiS 7018 */ @@ -327,6 +338,11 @@ DSP_BIND_I2S, DSP_BIND_CENTER_LFE, DSP_BIND_SURR, DSP_BIND_SPDIF }; +/* Add by Matt Wu 01-05-2001 for spdif in */ +static int ali_close_multi_channels(void); +static void ali_delay(struct trident_card *card,int interval); +static void ali_detect_spdif_rate(struct trident_card *card); + static struct trident_card *devs; static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val); @@ -760,6 +776,8 @@ static void trident_rec_setup(struct trident_state *state) { u16 w; + u8 bval; + struct trident_card *card = state->card; struct dmabuf *dmabuf = &state->dmabuf; struct trident_channel *channel = dmabuf->channel; @@ -794,6 +812,18 @@ channel->delta = compute_rate_rec(dmabuf->rate); if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) && (channel->num == ALI_SPDIF_IN_CHANNEL)) { rate = ali_get_spdif_in_rate(card); + if (rate == 0) + { + printk(KERN_WARNING "trident: ALi 5451 S/PDIF input setup error!\n"); + rate = 48000; + } + bval = inb(TRID_REG(card,ALI_SPDIF_CTRL)); + if (bval & 0x10) + { + outb(bval,TRID_REG(card,ALI_SPDIF_CTRL)); + printk(KERN_WARNING "trident: cleared ALi 5451 S/PDIF parity error flag.\n"); + } + if (rate != 48000) channel->delta = ((rate << 12) / dmabuf->rate) & 0x0000ffff; } @@ -959,7 +989,7 @@ static int alloc_dmabuf(struct trident_state *state) { struct dmabuf *dmabuf = &state->dmabuf; - void *rawbuf; + void *rawbuf=NULL; int order; struct page *page, *pend; @@ -1138,11 +1168,13 @@ len = dmabuf->dmasize - swptr; memset(dmabuf->rawbuf + swptr, silence, len); - - spin_lock_irqsave(&state->card->lock, flags); - dmabuf->swptr += len; - dmabuf->count += len; - spin_unlock_irqrestore(&state->card->lock, flags); + if(state->card->pci_id != PCI_DEVICE_ID_ALI_5451) + { + spin_lock_irqsave(&state->card->lock, flags); + dmabuf->swptr += len; + dmabuf->count += len; + spin_unlock_irqrestore(&state->card->lock, flags); + } /* restart the dma machine in case it is halted */ start_dac(state); @@ -1155,6 +1187,7 @@ unsigned long flags; unsigned long tmo; int count; + unsigned long diff = 0; if (dmabuf->mapped || !dmabuf->ready) return 0; @@ -1183,10 +1216,19 @@ /* No matter how much data left in the buffer, we have to wait untill CSO == ESO/2 or CSO == ESO when address engine interrupts */ - tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; + if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) + { + diff = dmabuf->swptr - trident_get_dma_addr(state) + dmabuf->dmasize ; + diff = diff % (dmabuf->dmasize); + tmo = (diff * HZ) / dmabuf->rate; + } + else + { + tmo = (dmabuf->dmasize * HZ) / dmabuf->rate; + } tmo >>= sample_shift[dmabuf->fmt]; +// printk("trident: diff=%d count= %d/%d total=%d tmo=%d hwptr=%d swptr=%d curptr=%d\n",diff,dmabuf->count,dmabuf->dmasize,dmabuf->total_bytes,tmo,dmabuf->hwptr,dmabuf->swptr,trident_get_dma_addr(state)); if (!schedule_timeout(tmo ? tmo : 1) && tmo){ - printk(KERN_ERR "trident: drain_dac, dma timeout?\n"); break; } } @@ -1412,7 +1454,7 @@ if (!ret) ret = -EAGAIN; return ret; } - /* No matter how much space left in the buffer, we have to wait untill + /* No matter how much space left in the buffer, we have to wait until CSO == ESO/2 or CSO == ESO when address engine interrupts */ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); tmo >>= sample_shift[dmabuf->fmt]; @@ -1430,7 +1472,7 @@ dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr); #endif - /* a buffer overrun, we delay the recovery untill next time the + /* a buffer overrun, we delay the recovery until next time the while loop begin and we REALLY have space to record */ } if (signal_pending(current)) { @@ -1512,7 +1554,7 @@ if (!ret) ret = -EAGAIN; return ret; } - /* No matter how much data left in the buffer, we have to wait untill + /* No matter how much data left in the buffer, we have to wait until CSO == ESO/2 or CSO == ESO when address engine interrupts */ lock_set_fmt(state); tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); @@ -1532,7 +1574,7 @@ dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr); #endif - /* a buffer underrun, we delay the recovery untill next time the + /* a buffer underrun, we delay the recovery until next time the while loop begin and we REALLY have data to play */ } if (signal_pending(current)) { @@ -1671,6 +1713,8 @@ count_info cinfo; int val, mapped, ret; + struct trident_card *card = state->card; + VALIDATE_STATE(state); mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) || ((file->f_mode & FMODE_READ) && dmabuf->mapped); @@ -1807,17 +1851,32 @@ state->chans_num = 1; } - if (val >= 2) { + if (val >= 2) + { + dmabuf->fmt |= TRIDENT_FMT_STEREO; if ((val == 6) && (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)) { - ali_setup_multi_channels(state->card, 6); + + if( card->rec_channel_use_count > 0 ) + { + printk("Err: Record is working on the card!\n"); + return -EBUSY; + } + + ret = ali_setup_multi_channels(state->card, 6); + if (ret < 0) { + unlock_set_fmt(state); + return ret; + } down(&state->card->open_sem); ret = ali_allocate_other_states_resources(state, 6); - up(&state->card->open_sem); if (ret < 0) { + up(&state->card->open_sem); unlock_set_fmt(state); return ret; } + state->card->multi_channel_use_count ++; + up(&state->card->open_sem); } else val = 2; /*yield to 2-channels*/ } @@ -2031,10 +2090,20 @@ struct trident_card *card = devs; struct trident_state *state = NULL; struct dmabuf *dmabuf = NULL; - + /* find an avaiable virtual channel (instance of /dev/dsp) */ while (card != NULL) { down(&card->open_sem); + if(file->f_mode & FMODE_READ) + { + /* Skip opens on cards that are in 6 channel mode */ + if (card->multi_channel_use_count > 0) + { + up(&card->open_sem); + card = card->next; + continue; + } + } for (i = 0; i < NR_HW_CH; i++) { if (card->states[i] == NULL) { state = card->states[i] = (struct trident_state *) @@ -2107,6 +2176,7 @@ (CHANNEL_REC|PCM_LR|MONO_MIX); } trident_set_adc_rate(state, 8000); + card->rec_channel_use_count ++; } state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); @@ -2143,16 +2213,29 @@ if (file->f_mode & FMODE_WRITE) { stop_dac(state); lock_set_fmt(state); - if (state->chans_num > 2) - ali_free_other_states_resources(state); + unlock_set_fmt(state); dealloc_dmabuf(state); state->card->free_pcm_channel(state->card, dmabuf->channel->num); + + if (state->chans_num > 2) + { + if( card->multi_channel_use_count-- < 0 ) + card->multi_channel_use_count = 0; + + if (card->multi_channel_use_count == 0) + ali_close_multi_channels(); + + ali_free_other_states_resources(state); + } } if (file->f_mode & FMODE_READ) { stop_adc(state); dealloc_dmabuf(state); state->card->free_pcm_channel(state->card, dmabuf->channel->num); + + if( card->rec_channel_use_count-- < 0 ) + card->rec_channel_use_count = 0; } card->states[state->virt] = NULL; @@ -2295,6 +2378,9 @@ data = ((u32) val) << 16; + if(!card) + BUG(); + address = ALI_AC97_WRITE; mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY; if (codec->id) @@ -2391,11 +2477,29 @@ flag: ALI_SPDIF_OUT_TO_SPDIF_OUT ALI_PCM_TO_SPDIF_OUT */ + static void ali_setup_spdif_out(struct trident_card *card, int flag) { unsigned long spdif; unsigned char ch; + char temp; + struct pci_dev *pci_dev = NULL; + + pci_dev = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev); + if (pci_dev == NULL) + return; + pci_read_config_byte(pci_dev, 0x61, &temp); + temp |= 0x40; + pci_write_config_byte(pci_dev, 0x61, temp); + pci_read_config_byte(pci_dev, 0x7d, &temp); + temp |= 0x01; + pci_write_config_byte(pci_dev, 0x7d, temp); + pci_read_config_byte(pci_dev, 0x7e, &temp); + temp &= (~0x20); + temp |= 0x10; + pci_write_config_byte(pci_dev, 0x7e, temp); + ch = inb(TRID_REG(card, ALI_SCTRL)); outb(ch | ALI_SPDIF_OUT_ENABLE, TRID_REG(card, ALI_SCTRL)); ch = inb(TRID_REG(card, ALI_SPDIF_CTRL)); @@ -2448,112 +2552,207 @@ spdif |= ALI_SPDIF_IN_SUPPORT; outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); - spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)); - spdif |= ALI_SPDIF_IN_CH_STATUS; - outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); - //Set SPDIF IN Rec spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)); spdif |= ALI_SPDIF_IN_CH_ENABLE; outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL)); spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)); + spdif |= ALI_SPDIF_IN_CH_STATUS; + outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); +/* + spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)); spdif |= ALI_SPDIF_IN_FUNC_ENABLE; outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); +*/ } -static unsigned int ali_get_spdif_in_rate(struct trident_card *card) +static void ali_delay(struct trident_card *card,int interval) +{ + unsigned long begintimer,currenttimer; + + begintimer = inl(TRID_REG(card, ALI_STIMER)); + currenttimer = inl(TRID_REG(card, ALI_STIMER)); + + while (currenttimer < begintimer + interval) + currenttimer = inl(TRID_REG(card, ALI_STIMER)); +} + +static void ali_detect_spdif_rate(struct trident_card *card) { - unsigned long spdif, time1, time2; - unsigned count1, count2, count3; - unsigned char R1, R2 = 0; - - outb(0xAA, TRID_REG(card, ALI_SPDIF_CTRL + 1)); - count1 = 0xFFFF; - while(--count1) + u16 wval = 0; + u16 count = 0; + u8 bval = 0, R1 = 0, R2 = 0; + + bval = inb(TRID_REG(card,ALI_SPDIF_CTRL)); + bval |= 0x02; + outb(bval,TRID_REG(card,ALI_SPDIF_CTRL)); + + bval = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1)); + bval |= 0x1F; + outb(bval,TRID_REG(card,ALI_SPDIF_CTRL + 1)); + + while (((R1 < 0x0B )||(R1 > 0x0E)) && (R1 != 0x12) && count <= 50000) { - count2 = 0xffff; - do{ - count3 = 0xffff; - time1 = inl(TRID_REG(card, ALI_STIMER)); - - do{ - time2 = inl(TRID_REG(card, ALI_STIMER)); - }while((count3--) && (time2 <= (time1 + 5))); - if (!count3) { - printk("ali: STimer is stopped! Error!\n"); - return FALSE; - } - R1 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); - }while((count2--) && (!((R1 == 0x0B)||(R1 == 0x0C)||(R1 == 0x0D)||(R1 == 0x0E)||(R1 == 0x12)))); - if (!count2) - continue; + count ++; - count2 = 0xffff; - time1 = inl(TRID_REG(card, ALI_STIMER)); - do{ - time2 = inl(TRID_REG(card, ALI_STIMER)); - }while((count2--) && (time2 <= (time1 + 5))); - if (!count2) - continue; + ali_delay(card, 6); - R2 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); - count2 = 0xffff; - while((--count2) && (R2 != R1)) - { + bval = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1)); + R1 = bval & 0x1F; + } + + if (count > 50000) + { + printk(KERN_WARNING "trident: Error in ali_detect_spdif_rate!\n"); + return; + } + + count = 0; + + while (count <= 50000) + { + count ++; + + ali_delay(card, 6); + + bval = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1)); + R2 = bval & 0x1F; + + if(R2 != R1) R1 = R2; - count3 = 0xffff; - time1 = inl(TRID_REG(card, ALI_STIMER)); - do{ - time2 = inl(TRID_REG(card, ALI_STIMER)); - }while((count3--) && (time2 <= (time1 + 5))); - if (!count3) { - printk("ali: STimer is stopped! Error!\n"); - return FALSE; - } - R2 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1)); - } - if(R2 == R1) + else break; } - if(!count1) { - printk("ali: Can not Detect the sample rate from SPDIF IN!\n"); - return FALSE; + if (count > 50000) + { + printk(KERN_WARNING "trident: Error in ali_detect_spdif_rate!\n"); + return; } - spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)) | ALI_SPDIF_IN_CH_STATUS; - outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL)); + switch (R2) + { + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + wval = inw(TRID_REG(card,ALI_SPDIF_CTRL + 2)); + wval &= 0xE0F0; + wval |= (u16)0x09 << 8 | (u16)0x05; + outw(wval,TRID_REG(card,ALI_SPDIF_CTRL + 2)); + + bval = inb(TRID_REG(card,ALI_SPDIF_CS +3)) & 0xF0; + outb(bval|0x02,TRID_REG(card,ALI_SPDIF_CS + 3)); + break; - /* SPDIF only supprts 48k, 44.1k, 32k */ - switch(R2) { case 0x12: - outw(0x0E08, TRID_REG(card, ALI_SPDIF_CTRL + 2)); - return 32000; - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: + wval = inw(TRID_REG(card,ALI_SPDIF_CTRL + 2)); + wval &= 0xE0F0; + wval |= (u16)0x0E << 8 | (u16)0x08; + outw(wval,TRID_REG(card,ALI_SPDIF_CTRL + 2)); + + bval = inb(TRID_REG(card,ALI_SPDIF_CS +3)) & 0xF0; + outb(bval|0x03,TRID_REG(card,ALI_SPDIF_CS + 3)); + break; + default: - outw(0x0905, TRID_REG(card, ALI_SPDIF_CTRL + 2)); break; } + +} + +static unsigned int ali_get_spdif_in_rate(struct trident_card *card) +{ + u32 dwRate = 0; + u8 bval = 0; + + ali_detect_spdif_rate(card); + + bval = inb(TRID_REG(card,ALI_SPDIF_CTRL)); + bval &= 0x7F; + bval |= 0x40; + outb(bval,TRID_REG(card,ALI_SPDIF_CTRL)); + + bval = inb(TRID_REG(card,ALI_SPDIF_CS + 3)); + bval &= 0x0F; + + switch (bval) + { + case 0: + dwRate = 44100; + break; + case 1: + dwRate = 48000; + break; + case 2: + dwRate = 32000; + break; + default: + // Error occurs + break; + } + + return dwRate; - spdif = inb(TRID_REG(card, ALI_SPDIF_CS + 3)) & 0xf; - if (spdif == 0) - return 44100; - else return 48000; +} + +static int ali_close_multi_channels(void) +{ + char temp = 0; + struct pci_dev *pci_dev = NULL; + + pci_dev = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev); + if (pci_dev == NULL) + return -1; + temp = 0x80; + pci_write_config_byte(pci_dev, 0x59, ~temp); + + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, pci_dev); + if (pci_dev == NULL) + return -1; + + temp = 0x20; + pci_write_config_byte(pci_dev, 0xB8, ~temp); + + return 0; } static int ali_setup_multi_channels(struct trident_card *card, int chan_nums) { unsigned long dwValue; - + char temp = 0; + struct pci_dev *pci_dev = NULL; + + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev); + if (pci_dev == NULL) + return -1; + temp = 0x80; + pci_write_config_byte(pci_dev, 0x59, temp); + + pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, pci_dev); + if (pci_dev == NULL) + return -1; + temp = 0x20; + pci_write_config_byte(pci_dev, (int)0xB8,(u8) temp); if (chan_nums == 6) { dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000; outl(dwValue, TRID_REG(card, ALI_SCTRL)); + mdelay(4); + dwValue = inl(TRID_REG(card, ALI_SCTRL)); + if (dwValue & 0x2000000) { + ali_ac97_set(card->ac97_codec[0], 0x02, 8080); + ali_ac97_set(card->ac97_codec[0], 0x36, 0); + ali_ac97_set(card->ac97_codec[0], 0x38, 0); + ali_ac97_set(card->ac97_codec[1], 0x36, 0); + ali_ac97_set(card->ac97_codec[1], 0x38, 0); + ali_ac97_set(card->ac97_codec[1], 0x02, 0); + ali_ac97_set(card->ac97_codec[1], 0x18, 0x0808); + ali_ac97_set(card->ac97_codec[1], 0x74, 0x3); + return 1; + } } - return 1; + return -EINVAL; } static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel) @@ -2746,7 +2945,7 @@ } /* no more free channels avaliable */ - printk(KERN_ERR "ali: no more channels available on Bank A.\n"); +// printk(KERN_ERR "ali: no more channels available on Bank A.\n"); return NULL; } @@ -2769,7 +2968,7 @@ } /* no free recordable channels avaliable */ - printk(KERN_ERR "ali: no recordable channels available on Bank A.\n"); +// printk(KERN_ERR "ali: no recordable channels available on Bank A.\n"); return NULL; } @@ -2778,9 +2977,6 @@ unsigned char ch_st_sel; unsigned short status_rate; -#ifdef DEBUG - printk("ali: spdif out rate =%d\n", rate); -#endif switch(rate) { case 44100: status_rate = 0; @@ -2803,9 +2999,6 @@ ch_st_sel &= (~0x80); //select left outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL)); outw(status_rate | 0x10, TRID_REG(card, ALI_SPDIF_CS + 2)); -#ifdef DEBUG - printk("ali: SPDIF_CS=%lxh\n", inl(TRID_REG(card, ALI_SPDIF_CS))); -#endif } static void ali_address_interrupt(struct trident_card *card) @@ -2822,6 +3015,7 @@ if ((channel_mask = 1 << channel) & mask) { mask &= ~channel_mask; trident_ack_channel_interrupt(card, channel); + udelay(100); state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE; trident_update_ptr(state); } @@ -2986,7 +3180,7 @@ /* OSS /dev/mixer file operation methods */ static int trident_open_mixdev(struct inode *inode, struct file *file) { - int i; + int i = 0; int minor = MINOR(inode->i_rdev); struct trident_card *card = devs; @@ -3033,10 +3227,17 @@ switch (card->pci_id) { case PCI_DEVICE_ID_ALI_5451: + outl(0x80000000,TRID_REG(card, ALI_GLOBAL_CONTROL)); + outl(0x00000000,TRID_REG(card, 0xa4)); + outl(0xffffffff,TRID_REG(card, 0x98)); + outl(0x00000000,TRID_REG(card, 0xa8)); + outb(0x10, TRID_REG(card, 0x22)); ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); - outl(ready_2nd | PCMOUT | SECONDARY_ID, TRID_REG(card, ALI_SCTRL)); + ready_2nd &= 0x3fff; + outl(ready_2nd | PCMOUT | 0x8000, TRID_REG(card, ALI_SCTRL)); ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); ready_2nd &= SI_AC97_SECONDARY_READY; +// printk("codec 2 ready flag= %lx\n", ready_2nd); break; case PCI_DEVICE_ID_SI_7018: /* disable AC97 GPIO interrupt */ @@ -3097,11 +3298,11 @@ return num_ac97+1; } - return num_ac97; + return 1/*num_ac97*/; } /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ + until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { unsigned long iobase; @@ -3167,6 +3368,10 @@ card->address_interrupt = ali_address_interrupt; + /* Added by Matt Wu 01-05-2001 for spdif in */ + card->multi_channel_use_count = 0; + card->rec_channel_use_count = 0; + /* ALi SPDIF OUT function */ if(card->revision == ALI_5451_V02) { ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT); @@ -3203,7 +3408,7 @@ kfree(card); return -ENODEV; } - /* initilize AC97 codec and register /dev/mixer */ + /* initialize AC97 codec and register /dev/mixer */ if (trident_ac97_init(card) <= 0) { unregister_sound_dsp(card->dev_audio); release_region(iobase, 256); diff -u --recursive --new-file v2.4.2/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c --- v2.4.2/linux/drivers/sound/via82cxxx_audio.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/via82cxxx_audio.c Fri Mar 2 11:02:15 2001 @@ -15,7 +15,7 @@ */ -#define VIA_VERSION "1.1.14a" +#define VIA_VERSION "1.1.14b" #include @@ -282,6 +282,8 @@ unsigned rev_h : 1; + int locked_rate : 1; + struct semaphore syscall_sem; struct semaphore open_sem; @@ -508,10 +510,16 @@ static int via_set_rate (struct ac97_codec *ac97, struct via_channel *chan, unsigned rate) { + struct via_info *card = ac97->private_data; int rate_reg; DPRINTK ("ENTER, rate = %d\n", rate); + if (card->locked_rate) { + chan->rate = 48000; + goto out; + } + if (rate > 48000) rate = 48000; if (rate < 4000) rate = 4000; @@ -535,6 +543,13 @@ */ chan->rate = via_ac97_read_reg (ac97, rate_reg); + if (chan->rate == 0) { + card->locked_rate = 1; + chan->rate = 48000; + printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); + } + +out: DPRINTK ("EXIT, returning rate %d Hz\n", chan->rate); return chan->rate; } @@ -1421,15 +1436,19 @@ /* WARNING: this line is magic. Remove this * and things break. */ /* enable variable rate, variable rate MIC ADC */ - tmp16 = via_ac97_read_reg (&card->ac97, 0x2A); - via_ac97_write_reg (&card->ac97, 0x2A, tmp16 | (1<<0)); - - pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8); - if ((tmp8 & (VIA_CR41_AC97_ENABLE | VIA_CR41_AC97_RESET)) == 0) { - printk (KERN_ERR PFX "cannot enable AC97 controller, aborting\n"); - DPRINTK ("EXIT, tmp8=%X, returning -ENODEV\n", tmp8); - return -ENODEV; - } + /* + * If we cannot enable VRA, we have a locked-rate codec. + * We try again to enable VRA before assuming so, however. + */ + tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); + if ((tmp16 & 1) == 0) { + via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); + tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); + if ((tmp16 & 1) == 0) { + card->locked_rate = 1; + printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); + } + } DPRINTK ("EXIT, returning 0\n"); return 0; @@ -1478,8 +1497,8 @@ } /* enable variable rate, variable rate MIC ADC */ - tmp16 = via_ac97_read_reg (&card->ac97, 0x2A); - via_ac97_write_reg (&card->ac97, 0x2A, tmp16 | (1<<0)); + tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS); + via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); DPRINTK ("EXIT, returning 0\n"); return 0; diff -u --recursive --new-file v2.4.2/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.4.2/linux/drivers/sound/wavfront.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/wavfront.c Fri Mar 2 11:12:11 2001 @@ -94,7 +94,7 @@ #ifdef CONFIG_SMP #define LOOPS_PER_TICK cpu_data[smp_processor_id()].loops_per_jiffy #else -#define LOOPS_PER_TICK loops_per_sec +#define LOOPS_PER_TICK loops_per_jiffy #endif #endif @@ -693,7 +693,7 @@ /*********************************************************************** WaveFront: data munging -Things here are wierd. All data written to the board cannot +Things here are weird. All data written to the board cannot have its most significant bit set. Any data item with values potentially > 0x7F (127) must be split across multiple bytes. @@ -702,7 +702,7 @@ that is represented on the x86 side as an array of bytes. The most efficient approach to handling both cases seems to be to use 2 different functions for munging and 2 for de-munging. This avoids -wierd casting and worrying about bit-level offsets. +weird casting and worrying about bit-level offsets. **********************************************************************/ @@ -1213,7 +1213,7 @@ shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset), shptr, 4); - /* This one is truly wierd. What kind of wierdo decided that in + /* This one is truly weird. What kind of weirdo decided that in a system dominated by 16 and 32 bit integers, they would use a just 12 bits ? */ @@ -3069,7 +3069,7 @@ This code was developed using DOSEMU. The Turtle Beach SETUPSND utility was run with I/O tracing in DOSEMU enabled, and a reconstruction of the port I/O done, using the Yamaha faxback document as a guide - to add more logic to the code. Its really pretty wierd. + to add more logic to the code. Its really pretty weird. There was an alternative approach of just dumping the whole I/O sequence as a series of port/value pairs and a simple loop diff -u --recursive --new-file v2.4.2/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c --- v2.4.2/linux/drivers/sound/ymfpci.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/ymfpci.c Tue Mar 6 19:28:32 2001 @@ -95,34 +95,6 @@ MODULE_DEVICE_TABLE(pci, ymf_id_tbl); /* - * Mindlessly copied from cs46xx XXX - */ -static inline unsigned ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* * common I/O routines */ @@ -347,7 +319,6 @@ { struct ymf_dmabuf *dmabuf; int w_16; - unsigned bytepersec; unsigned bufsize; unsigned long flags; int redzone; @@ -367,20 +338,16 @@ if ((ret = alloc_dmabuf(dmabuf))) return ret; - bytepersec = state->format.rate << state->format.shift; - /* * Create fake fragment sizes and numbers for OSS ioctls. + * Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT. */ bufsize = PAGE_SIZE << dmabuf->buforder; - if (dmabuf->ossfragshift) { - if ((1000 << dmabuf->ossfragshift) < bytepersec) - dmabuf->fragshift = ld2(bytepersec/1000); - else - dmabuf->fragshift = dmabuf->ossfragshift; - } else { - /* lets hand out reasonable big ass buffers by default */ - dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + /* lets hand out reasonable big ass buffers by default */ + dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2); + if (dmabuf->ossfragshift > 3 && + dmabuf->ossfragshift < dmabuf->fragshift) { + dmabuf->fragshift = dmabuf->ossfragshift; } dmabuf->numfrag = bufsize >> dmabuf->fragshift; while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) { @@ -390,9 +357,6 @@ dmabuf->fragsize = 1 << dmabuf->fragshift; dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; - /* - * Import what Doom might have set with SNDCTL_DSD_SETFRAGMENT. - */ if (dmabuf->ossmaxfrags >= 2 && dmabuf->ossmaxfrags < dmabuf->numfrag) { dmabuf->numfrag = dmabuf->ossmaxfrags; dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift; @@ -1726,8 +1690,6 @@ dmabuf->ossfragshift = 4; if (dmabuf->ossfragshift > 15) dmabuf->ossfragshift = 15; - if (dmabuf->ossmaxfrags < 4) - dmabuf->ossmaxfrags = 4; return 0; case SNDCTL_DSP_GETOSPACE: @@ -1879,7 +1841,7 @@ static int ymf_open(struct inode *inode, struct file *file) { struct list_head *list; - ymfpci_t *unit; + ymfpci_t *unit = NULL; int minor; struct ymf_state *state; int err; @@ -2370,9 +2332,9 @@ int err; - if (pci_enable_device(pcidev) < 0) { + if ((err = pci_enable_device(pcidev)) != 0) { printk(KERN_ERR "ymfpci: pci_enable_device failed\n"); - return -ENODEV; + return err; } if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) { diff -u --recursive --new-file v2.4.2/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c --- v2.4.2/linux/drivers/telephony/ixj.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/telephony/ixj.c Fri Mar 2 18:38:39 2001 @@ -6300,6 +6300,7 @@ { return 0; } +#endif /* CONFIG_PCMCIA */ #if defined(CONFIG_ISAPNP) extern __inline__ int ixj_probe_isa(int *cnt) @@ -6448,7 +6449,6 @@ return 0; } #endif /* CONFIG_ISAPNP */ -#endif /* CONFIG_PCMCIA */ #if defined(CONFIG_PCI) int __init ixj_probe_pci(int *cnt) diff -u --recursive --new-file v2.4.2/linux/drivers/usb/inode.c linux/drivers/usb/inode.c --- v2.4.2/linux/drivers/usb/inode.c Thu Sep 7 08:38:06 2000 +++ linux/drivers/usb/inode.c Fri Mar 2 13:47:21 2001 @@ -596,7 +596,7 @@ return NULL; } -static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, 0); +static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE); /* --------------------------------------------------------------------- */ @@ -691,6 +691,7 @@ return ret; if ((ret = register_filesystem(&usbdevice_fs_type))) usb_deregister(&usbdevfs_driver); + kern_mount(&usbdevice_fs_type); #ifdef CONFIG_PROC_FS /* create mount point for usbdevfs */ usbdir = proc_mkdir("usb", proc_bus); @@ -702,6 +703,7 @@ { usb_deregister(&usbdevfs_driver); unregister_filesystem(&usbdevice_fs_type); + kern_umount(usbdevice_fs_type.kern_mnt); #ifdef CONFIG_PROC_FS if (usbdir) remove_proc_entry("usb", proc_bus); diff -u --recursive --new-file v2.4.2/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.4.2/linux/drivers/usb/printer.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/printer.c Fri Mar 2 17:50:22 2001 @@ -1,5 +1,5 @@ /* - * printer.c Version 0.6 + * printer.c Version 0.8 * * Copyright (c) 1999 Michael Gee * Copyright (c) 1999 Pavel Machek @@ -17,7 +17,8 @@ * v0.4 - fixes in unidirectional mode * v0.5 - add DEVICE_ID string support * v0.6 - never time out - * v0.? - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com) + * v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com) + * v0.8 - add devfs support */ /* @@ -45,6 +46,7 @@ #include #include #include +#include #undef DEBUG #include @@ -78,6 +80,7 @@ struct usblp { struct usb_device *dev; /* USB device */ + devfs_handle_t devfs; /* devfs device */ struct urb readurb, writeurb; /* The urbs */ wait_queue_head_t wait; /* Zzzzz ... */ int readcount; /* Counter for reads */ @@ -90,6 +93,8 @@ /* first 2 bytes are (big-endian) length */ }; +extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ + static struct usblp *usblp_table[USBLP_MINORS]; /* Quirks: various printer quirks are handled by this table & its flags. */ @@ -245,6 +250,7 @@ return 0; } + devfs_unregister(usblp->devfs); usblp_table[usblp->minor] = NULL; kfree(usblp->device_id_string); kfree(usblp); @@ -454,6 +460,16 @@ return 0; } +static struct file_operations usblp_fops = { + owner: THIS_MODULE, + read: usblp_read, + write: usblp_write, + poll: usblp_poll, + ioctl: usblp_ioctl, + open: usblp_open, + release: usblp_release, +}; + static void *usblp_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id) { @@ -464,6 +480,7 @@ int alts = dev->actconfig->interface[ifnum].act_altsetting; int length, err; char *buf; + char name[6]; /* If a bidirectional interface exists, use it. */ for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) { @@ -573,6 +590,17 @@ usblp_check_status(usblp, 0); #endif + sprintf(name, "lp%d", minor); + + /* Create with perms=664 */ + usblp->devfs = devfs_register(usb_devfs_handle, name, + DEVFS_FL_DEFAULT, USB_MAJOR, + USBLP_MINOR_BASE + minor, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | + S_IWGRP, &usblp_fops, NULL); + if (usblp->devfs == NULL) + err("usblp%d: device node registration failed", minor); + info("usblp%d: USB %sdirectional printer dev %d if %d alt %d", minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts); @@ -600,19 +628,10 @@ kfree(usblp->device_id_string); + devfs_unregister(usblp->devfs); usblp_table[usblp->minor] = NULL; kfree(usblp); } - -static struct file_operations usblp_fops = { - owner: THIS_MODULE, - read: usblp_read, - write: usblp_write, - poll: usblp_poll, - ioctl: usblp_ioctl, - open: usblp_open, - release: usblp_release, -}; static struct usb_device_id usblp_ids [] = { { USB_INTERFACE_INFO(7, 1, 1) }, diff -u --recursive --new-file v2.4.2/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c --- v2.4.2/linux/drivers/usb/scanner.c Thu Jan 4 13:15:32 2001 +++ linux/drivers/usb/scanner.c Fri Mar 2 17:50:22 2001 @@ -1,7 +1,7 @@ /* -*- linux-c -*- */ /* - * Driver for USB Scanners (linux-2.4.0test1-ac7) + * Driver for USB Scanners (linux-2.4.0) * * Copyright (C) 1999, 2000 David E. Nelson * @@ -208,6 +208,26 @@ * - Added the Epson Expression1600 ID's. Thanks to Karl Heinz * Kremer . * + * 0.4.5 2/28/2001 + * - Added Mustek ID's (BearPaw 2400, 1200 CU Plus, BearPaw 1200F). + * Thanks to Henning Meier-Geinitz . + * - Added read_timeout module parameter to override RD_NAK_TIMEOUT + * when read()'ing from devices. + * - Stalled pipes are now checked and cleared with + * usb_clear_halt() for the read_scanner() function. This should + * address the "funky result: -32" error messages. + * - Removed Microtek scanner ID's. Microtek scanners are now + * supported via the drivers/usb/microtek.c driver. + * - Added scanner specific read timeout's. + * - Return status errors are NEGATIVE!!! This should address the + * "funky result: -110" error messages. + * - Replaced USB_ST_TIMEOUT with ETIMEDOUT. + * - rd_nak was still defined in MODULE_PARM. It's been updated with + * read_timeout. Thanks to Mark W. Webb for + * reporting this bug. + * - Added Epson Perfection 1640SU and 1640SU Photo. Thanks to + * Jean-Luc . + * * TODO * * - Performance @@ -235,8 +255,7 @@ * System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner * 300 dpi scan of the entire bed * 24 Bit Color ~ 70 secs - 3.6 Mbit/sec - * 8 Bit Gray ~ 17 secs - 4.2 Mbit/sec - */ + * 8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */ /* * Scanner definitions, macros, module info, @@ -244,81 +263,6 @@ */ #include "scanner.h" -/* Table of scanners that may work with this driver */ -static struct usb_device_id scanner_device_ids [] = { - /* Acer */ - { USB_DEVICE(0x04a5, 0x2060) }, /* Prisa Acerscan 620U & 640U (!)*/ - { USB_DEVICE(0x04a5, 0x2040) }, /* Prisa AcerScan 620U (!) */ - { USB_DEVICE(0x04a5, 0x2022) }, /* Vuego Scan Brisa 340U */ - /* Agfa */ - { USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */ - { USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */ - { USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/ - { USB_DEVICE(0x06bd, 0x0100) }, /* SnapScan Touch */ - /* Colorado -- See Primax/Colorado below */ - /* Epson -- See Seiko/Epson below */ - /* Genius */ - { USB_DEVICE(0x0458, 0x2001) }, /* ColorPage-Vivid Pro */ - /* Hewlett Packard */ - { USB_DEVICE(0x03f0, 0x0205) }, /* 3300C */ - { USB_DEVICE(0x03f0, 0x0101) }, /* 4100C */ - { USB_DEVICE(0x03f0, 0x0105) }, /* 4200C */ - { USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */ - { USB_DEVICE(0x03f0, 0x0401) }, /* 5200C */ - { USB_DEVICE(0x03f0, 0x0701) }, /* 5300C */ - { USB_DEVICE(0x03f0, 0x0201) }, /* 6200C */ - { USB_DEVICE(0x03f0, 0x0601) }, /* 6300C */ - /* iVina */ - { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */ - /* Microtek */ - { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */ - { USB_DEVICE(0x05da, 0x0094) }, /* Phantom 336CX - C3 */ - { USB_DEVICE(0x05da, 0x00a0) }, /* Phantom 336CX - C3 #2 */ - { USB_DEVICE(0x05da, 0x009a) }, /* Phantom C6 */ - { USB_DEVICE(0x05da, 0x00a3) }, /* ScanMaker V6USL */ - { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */ - { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */ - /* Mustek */ - { USB_DEVICE(0x055f, 0x0001) }, /* 1200 CU */ - { USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 */ - { USB_DEVICE(0x055f, 0x0002) }, /* 600 CU */ - { USB_DEVICE(0x055f, 0x0003) }, /* 1200 USB */ - { USB_DEVICE(0x055f, 0x0006) }, /* 1200 UB */ - /* Primax/Colorado */ - { USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */ - { USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */ - { USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */ - { USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */ - { USB_DEVICE(0x0461, 0x0302) }, /* G2-300 #2 */ - { USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */ - { USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */ - { USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */ - { USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */ - { USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 */ - { USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */ - { USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */ - /* Seiko/Epson Corp. */ - { USB_DEVICE(0x04b8, 0x0101) }, /* Perfection 636U and 636Photo */ - { USB_DEVICE(0x04b8, 0x0103) }, /* Perfection 610 */ - { USB_DEVICE(0x04b8, 0x0104) }, /* Perfection 1200U and 1200Photo*/ - { USB_DEVICE(0x04b8, 0x0106) }, /* Stylus Scan 2500 */ - { USB_DEVICE(0x04b8, 0x0107) }, /* Expression 1600 */ - /* Umax */ - { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */ - { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */ - { USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */ - /* Visioneer */ - { USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */ - { USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */ - { USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */ - { USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */ - { USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */ - { USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, scanner_device_ids); - static void irq_scanner(struct urb *urb) @@ -475,9 +419,9 @@ result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ); dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial); - if (result == USB_ST_TIMEOUT) { /* NAK -- shouldn't happen */ + if (result == -ETIMEDOUT) { /* NAK -- shouldn't happen */ warn("write_scanner: NAK recieved."); - ret = -ETIME; + ret = result; break; } else if (result < 0) { /* We should not get any I/O errors */ warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result); @@ -559,7 +503,7 @@ this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; - result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, RD_NAK_TIMEOUT); + result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, scn->rd_nak_timeout); dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count); /* @@ -576,23 +520,35 @@ * Ctrl-C's are acted upon in a reasonable amount of time. */ - if (result == USB_ST_TIMEOUT && !partial) { /* Timeout - and no - data */ - if (--rd_expire <= 0) { - warn("read_scanner(%d): excessive NAK's received", scn_minor); - ret = -ETIME; - break; - } else { - interruptible_sleep_on_timeout(&scn->rd_wait_q, RD_NAK_TIMEOUT); - continue; + if (result == -ETIMEDOUT) { /* NAK */ + if (!partial) { /* No data */ + if (--rd_expire <= 0) { /* Give it up */ + warn("read_scanner(%d): excessive NAK's received", scn_minor); + ret = result; + break; + } else { /* Keep trying to read data */ + interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout); + continue; + } + } else { /* Timeout w/ some data */ + goto data_recvd; } + } + + if (result == -EPIPE) { /* No hope */ + if(usb_clear_halt(dev, scn->bulk_in_ep)) { + err("read_scanner(%d): Failure to clear endpoint halt condition (%d).", scn_minor, ret); + } + ret = result; + break; } else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) { warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result); ret = -EIO; break; } + data_recvd: + #ifdef RD_DATA_DUMP if (partial) { unsigned char cnt, cnt_max; @@ -826,6 +782,26 @@ return NULL; } dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf); + + + switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */ + case 0x04b8: /* Seiko/Epson */ + scn->rd_nak_timeout = HZ * 40; + break; + case 0x055f: /* Mustek */ + case 0x0400: /* Another Mustek */ + case 0x0ff5: /* And yet another Mustek */ + scn->rd_nak_timeout = HZ * 1; + default: + scn->rd_nak_timeout = RD_NAK_TIMEOUT; + } + + + if (read_timeout > 0) { /* User specified read timeout overrides everything */ + info("probe_scanner: User specified USB read timeout - %d", read_timeout); + scn->rd_nak_timeout = read_timeout; + } + scn->bulk_in_ep = have_bulk_in; scn->bulk_out_ep = have_bulk_out; diff -u --recursive --new-file v2.4.2/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h --- v2.4.2/linux/drivers/usb/scanner.h Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/scanner.h Fri Mar 2 17:50:22 2001 @@ -1,5 +1,5 @@ /* - * Driver for USB Scanners (linux-2.4.0test1-ac7) + * Driver for USB Scanners (linux-2.4.0) * * Copyright (C) 1999, 2000 David E. Nelson * @@ -36,7 +36,7 @@ #include -static __s32 vendor=-1, product=-1; +static __s32 vendor=-1, product=-1, read_timeout=0; MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson"); MODULE_DESCRIPTION("USB Scanner Driver"); @@ -47,6 +47,9 @@ MODULE_PARM(product, "i"); MODULE_PARM_DESC(product, "User specified USB idProduct"); +MODULE_PARM(read_timeout, "i"); +MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds"); + /* Enable to activate the ioctl interface. This is mainly meant for */ /* development purposes until an ioctl number is officially registered */ @@ -56,6 +59,85 @@ // #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */ // #define WR_DATA_DUMP /* DEBUG does not have to be defined. */ +static struct usb_device_id scanner_device_ids [] = { + /* Acer */ + { USB_DEVICE(0x04a5, 0x2060) }, /* Prisa Acerscan 620U & 640U (!)*/ + { USB_DEVICE(0x04a5, 0x2040) }, /* Prisa AcerScan 620U (!) */ + { USB_DEVICE(0x04a5, 0x2022) }, /* Vuego Scan Brisa 340U */ + /* Agfa */ + { USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */ + { USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */ + { USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/ + { USB_DEVICE(0x06bd, 0x0100) }, /* SnapScan Touch */ + /* Colorado -- See Primax/Colorado below */ + /* Epson -- See Seiko/Epson below */ + /* Genius */ + { USB_DEVICE(0x0458, 0x2001) }, /* ColorPage-Vivid Pro */ + /* Hewlett Packard */ + { USB_DEVICE(0x03f0, 0x0205) }, /* 3300C */ + { USB_DEVICE(0x03f0, 0x0101) }, /* 4100C */ + { USB_DEVICE(0x03f0, 0x0105) }, /* 4200C */ + { USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */ + { USB_DEVICE(0x03f0, 0x0401) }, /* 5200C */ + // { USB_DEVICE(0x03f0, 0x0701) }, /* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */ + { USB_DEVICE(0x03f0, 0x0201) }, /* 6200C */ + { USB_DEVICE(0x03f0, 0x0601) }, /* 6300C */ + /* iVina */ + { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */ + /* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */ + // { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */ + // { USB_DEVICE(0x05da, 0x0094) }, /* Phantom 336CX - C3 */ + // { USB_DEVICE(0x05da, 0x00a0) }, /* Phantom 336CX - C3 #2 */ + // { USB_DEVICE(0x05da, 0x009a) }, /* Phantom C6 */ + // { USB_DEVICE(0x05da, 0x00a3) }, /* ScanMaker V6USL */ + // { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */ + // { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */ + /* Mustek */ + { USB_DEVICE(0x055f, 0x0001) }, /* 1200 CU */ + { USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 */ + { USB_DEVICE(0x055f, 0x0002) }, /* 600 CU */ + { USB_DEVICE(0x055f, 0x0003) }, /* 1200 USB */ + { USB_DEVICE(0x055f, 0x0006) }, /* 1200 UB */ + { USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */ + { USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */ + { USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */ + /* Primax/Colorado */ + { USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */ + { USB_DEVICE(0x0461, 0x0380) }, /* G2-600 #1 */ + { USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */ + { USB_DEVICE(0x0461, 0x0381) }, /* ReadyScan 636i */ + { USB_DEVICE(0x0461, 0x0302) }, /* G2-300 #2 */ + { USB_DEVICE(0x0461, 0x0382) }, /* G2-600 #2 */ + { USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */ + { USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */ + { USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */ + { USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 */ + { USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */ + { USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */ + /* Seiko/Epson Corp. */ + { USB_DEVICE(0x04b8, 0x0101) }, /* Perfection 636U and 636Photo */ + { USB_DEVICE(0x04b8, 0x0103) }, /* Perfection 610 */ + { USB_DEVICE(0x04b8, 0x0104) }, /* Perfection 1200U and 1200Photo*/ + { USB_DEVICE(0x04b8, 0x0106) }, /* Stylus Scan 2500 */ + { USB_DEVICE(0x04b8, 0x0107) }, /* Expression 1600 */ + { USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */ + { USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */ + /* Umax */ + { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */ + { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */ + { USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */ + /* Visioneer */ + { USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */ + { USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */ + { USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */ + { USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */ + { USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */ + { USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */ + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, scanner_device_ids); + #define IS_EP_BULK(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0) #define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) #define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) @@ -73,7 +155,7 @@ #define OBUF_SIZE 4096 /* read_scanner timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */ -#define RD_NAK_TIMEOUT (10*HZ) /* Number of X seconds to wait */ +#define RD_NAK_TIMEOUT (10*HZ) /* Default number of X seconds to wait */ #define RD_EXPIRE 12 /* Number of attempts to wait X seconds */ @@ -90,12 +172,13 @@ unsigned int ifnum; /* Interface number of the USB device */ kdev_t scn_minor; /* Scanner minor - used in disconnect() */ unsigned char button; /* Front panel buffer */ - char isopen; /* Not zero if the device is open */ + char isopen; /* Not zero if the device is open */ char present; /* Not zero if device is present */ char *obuf, *ibuf; /* transfer buffers */ char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */ wait_queue_head_t rd_wait_q; /* read timeouts */ struct semaphore gen_lock; /* lock to prevent concurrent reads or writes */ + unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */ }; static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */}; diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c --- v2.4.2/linux/drivers/usb/serial/keyspan.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/keyspan.c Fri Mar 2 17:50:22 2001 @@ -839,9 +839,6 @@ p_priv = (struct keyspan_port_private *)(port->private); /* Set some sane defaults */ - p_priv->baud = 9600; - p_priv->cflag = CREAD | CLOCAL; - p_priv->flow_control = flow_none; p_priv->rts_state = 1; p_priv->dtr_state = 1; @@ -854,16 +851,8 @@ dbg(__FUNCTION__ " submit urb %d failed (%d)", i, err); } } -/* Now done in startup routine - if (atomic_inc_return(&s_priv->active_count) == 1) { - s_priv->instat_urb->dev = serial->dev; - if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) { - dbg(__FUNCTION__ " submit instat urb failed %d", err); - } - } -*/ - keyspan_send_setup(port); + keyspan_set_termios(port, NULL); return (0); } diff -u --recursive --new-file v2.4.2/linux/drivers/usb/storage/usb.h linux/drivers/usb/storage/usb.h --- v2.4.2/linux/drivers/usb/storage/usb.h Sat Feb 3 19:51:30 2001 +++ linux/drivers/usb/storage/usb.h Wed Mar 7 16:58:09 2001 @@ -181,7 +181,7 @@ extern struct semaphore us_list_semaphore; /* The structure which defines our driver */ -struct usb_driver usb_storage_driver; +extern struct usb_driver usb_storage_driver; /* Function to fill an inquiry response. See usb.c for details */ extern void fill_inquiry_response(struct us_data *us, diff -u --recursive --new-file v2.4.2/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c --- v2.4.2/linux/drivers/usb/usb-uhci.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/usb-uhci.c Sat Mar 3 10:55:48 2001 @@ -2945,10 +2945,9 @@ /* Search for the IO base address.. */ for (i = 0; i < 6; i++) { - unsigned int io_addr = dev->resource[i].start; - unsigned int io_size = - dev->resource[i].end - dev->resource[i].start + 1; - if (!(dev->resource[i].flags & IORESOURCE_IO)) + unsigned int io_addr = pci_resource_start(dev, i); + unsigned int io_size = pci_resource_len(dev, i); + if (!(pci_resource_flags(dev,i) & IORESOURCE_IO)) continue; /* Is it already in use? */ diff -u --recursive --new-file v2.4.2/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.4.2/linux/drivers/usb/usb.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/usb.c Fri Mar 2 17:50:21 2001 @@ -153,7 +153,9 @@ down(&driver->serialize); driver->disconnect(dev, interface->private_data); up(&driver->serialize); - usb_driver_release_interface(driver, interface); + /* if driver->disconnect didn't release the interface */ + if (interface->driver) + usb_driver_release_interface(driver, interface); /* * This will go through the list looking for another * driver that can handle the device @@ -349,6 +351,7 @@ * * Creates a USB host controller bus structure with the specified * usb_operations and initializes all the necessary internal objects. + * (For use only by USB Host Controller Drivers.) * * If no memory is available, NULL is returned. * @@ -382,6 +385,7 @@ * usb_free_bus - frees the memory used by a bus structure * @bus: pointer to the bus to free * + * (For use only by USB Host Controller Drivers.) */ void usb_free_bus(struct usb_bus *bus) { @@ -395,6 +399,7 @@ * usb_register_bus - registers the USB host controller with the usb core * @bus: pointer to the bus to register * + * (For use only by USB Host Controller Drivers.) */ void usb_register_bus(struct usb_bus *bus) { @@ -415,6 +420,12 @@ info("new USB bus registered, assigned bus number %d", bus->busnum); } +/** + * usb_deregister_bus - deregisters the USB host controller + * @bus: pointer to the bus to deregister + * + * (For use only by USB Host Controller Drivers.) + */ void usb_deregister_bus(struct usb_bus *bus) { info("USB bus %d deregistered", bus->busnum); @@ -502,56 +513,69 @@ } -/* usb_match_id searches an array of usb_device_id's and returns - the first one that matches the device and interface. - - Parameters: - "id" is an array of usb_device_id's is terminated by an entry - containing all zeroes. - - "dev" and "interface" are the device and interface for which - a match is sought. - - If no match is found or if the "id" pointer is NULL, then - usb_match_id returns NULL. - - - What constitutes a match: - - A zero in any element of a usb_device_id entry is a wildcard - (i.e., that field always matches). For there to be a match, - *every* nonzero element of the usb_device_id must match the - provided device and interface in. The comparison is for equality, - except for one pair of fields: usb_match_id.bcdDevice_{lo,hi} define - an inclusive range that dev->descriptor.bcdDevice must be in. - - If interface->altsettings does not exist (i.e., there are no - interfaces defined), then bInterface{Class,SubClass,Protocol} - only match if they are all zeroes. - - - What constitutes a good "usb_device_id"? - - The match algorithm is very simple, so that intelligence in - driver selection must come from smart driver id records. - Unless you have good reasons to use another selection policy, - provide match elements only in related groups: - - * device specifiers (vendor and product IDs; and maybe - a revision range for that product); - * generic device specs (class/subclass/protocol); - * interface specs (class/subclass/protocol). - - Within those groups, work from least specific to most specific. - For example, don't give a product version range without vendor - and product IDs. - - "driver_info" is not considered by the kernel matching algorithm, - but you can create a wildcard "matches anything" usb_device_id - as your driver's "modules.usbmap" entry if you provide only an - id with a nonzero "driver_info" field. -*/ - +/** + * usb_match_id - find first usb_device_id matching device or interface + * @dev: the device whose descriptors are considered when matching + * @interface: the interface of interest + * @id: array of usb_device_id structures, terminated by zero entry + * + * usb_match_id searches an array of usb_device_id's and returns + * the first one matching the device or interface, or null. + * This is used when binding (or rebinding) a driver to an interface. + * Most USB device drivers will use this indirectly, through the usb core, + * but some layered driver frameworks use it directly. + * These device tables are exported with MODULE_DEVICE_TABLE, through + * modutils and "modules.usbmap", to support the driver loading + * functionality of USB hotplugging. + * + * What Matches: + * + * The "match_flags" element in a usb_device_id controls which + * members are used. If the corresponding bit is set, the + * value in the device_id must match its corresponding member + * in the device or interface descriptor, or else the device_id + * does not match. + * + * "driver_info" is normally used only by device drivers, + * but you can create a wildcard "matches anything" usb_device_id + * as a driver's "modules.usbmap" entry if you provide an id with + * only a nonzero "driver_info" field. If you do this, the USB device + * driver's probe() routine should use additional intelligence to + * decide whether to bind to the specified interface. + * + * What Makes Good usb_device_id Tables: + * + * The match algorithm is very simple, so that intelligence in + * driver selection must come from smart driver id records. + * Unless you have good reasons to use another selection policy, + * provide match elements only in related groups, and order match + * specifiers from specific to general. Use the macros provided + * for that purpose if you can. + * + * The most specific match specifiers use device descriptor + * data. These are commonly used with product-specific matches; + * the USB_DEVICE macro lets you provide vendor and product IDs, + * and you can also matche against ranges of product revisions. + * These are widely used for devices with application or vendor + * specific bDeviceClass values. + * + * Matches based on device class/subclass/protocol specifications + * are slightly more general; use the USB_DEVICE_INFO macro, or + * its siblings. These are used with single-function devices + * where bDeviceClass doesn't specify that each interface has + * its own class. + * + * Matches based on interface class/subclass/protocol are the + * most general; they let drivers bind to any interface on a + * multiple-function device. Use the USB_INTERFACE_INFO + * macro, or its siblings, to match class-per-interface style + * devices (as recorded in bDeviceClass). + * + * Within those groups, remember that not all combinations are + * meaningful. For example, don't give a product version range + * without vendor and product IDs; or specify a protocol without + * its associated class and subclass. + */ const struct usb_device_id * usb_match_id(struct usb_device *dev, struct usb_interface *interface, const struct usb_device_id *id) @@ -827,7 +851,7 @@ call_policy (char *verb, struct usb_device *dev) { } -#endif /* KMOD */ +#endif /* CONFIG_HOTPLUG */ /* @@ -1639,7 +1663,9 @@ down(&driver->serialize); driver->disconnect(dev, interface->private_data); up(&driver->serialize); - usb_driver_release_interface(driver, interface); + /* if driver->disconnect didn't release the interface */ + if (interface->driver) + usb_driver_release_interface(driver, interface); } } } diff -u --recursive --new-file v2.4.2/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c --- v2.4.2/linux/drivers/video/clgenfb.c Wed Feb 21 18:20:37 2001 +++ linux/drivers/video/clgenfb.c Tue Mar 6 19:28:33 2001 @@ -1,7 +1,7 @@ /* * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets * - * Copyright 1999,2000 Jeff Garzik + * Copyright 1999-2001 Jeff Garzik * * Contributors (thanks, all!) * diff -u --recursive --new-file v2.4.2/linux/drivers/video/fbcmap.c linux/drivers/video/fbcmap.c --- v2.4.2/linux/drivers/video/fbcmap.c Tue Mar 7 10:52:41 2000 +++ linux/drivers/video/fbcmap.c Fri Mar 2 18:38:39 2001 @@ -3,6 +3,9 @@ * * Created 15 Jun 1997 by Geert Uytterhoeven * + * 2001 - Documented with DocBook + * - Brad Douglas + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. @@ -73,9 +76,18 @@ }; - /* - * Allocate a colormap - */ +/** + * fb_alloc_cmap - allocate a colormap + * @cmap: frame buffer colormap structure + * @len: length of @cmap + * @transp: boolean, 1 if there is transparency, 0 otherwise + * + * Allocates memory for a colormap @cmap. @len is the + * number of entries in the palette. + * + * Returns -1 errno on error, or zero on success. + * + */ int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp) { @@ -113,9 +125,20 @@ } - /* - * Copy a colormap - */ +/** + * fb_copy_cmap - copy a colormap + * @from: frame buffer colormap structure + * @to: frame buffer colormap structure + * @fsfromto: determine copy method + * + * Copy contents of colormap from @from to @to. + * + * @fsfromto accepts the following integer parameters: + * 0: memcpy function + * 1: copy_from_user() function to copy from userspace + * 2: copy_to_user() function to copy to userspace + * + */ void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto) { @@ -159,9 +182,18 @@ } - /* - * Get the colormap for a screen - */ +/** + * fb_get_cmap - get a colormap + * @cmap: frame buffer colormap + * @kspc: boolean, 0 copy local, 1 put_user() function + * @getcolreg: pointer to a function to get a color register + * @info: frame buffer info structure + * + * Get a colormap @cmap for a screen of device @info. + * + * Returns negative errno on error, or zero on success. + * + */ int fb_get_cmap(struct fb_cmap *cmap, int kspc, int (*getcolreg)(u_int, u_int *, u_int *, u_int *, u_int *, @@ -205,9 +237,17 @@ } - /* - * Set the colormap for a screen - */ +/** + * fb_set_cmap - set the colormap + * @cmap: frame buffer colormap structure + * @kspc: boolean, 0 copy local, 1 get_user() function + * @info: frame buffer info structure + * + * Sets the colormap @cmap for a screen of device @info. + * + * Returns negative errno on error, or zero on success. + * + */ int fb_set_cmap(struct fb_cmap *cmap, int kspc, int (*setcolreg)(u_int, u_int, u_int, u_int, u_int, @@ -253,9 +293,16 @@ } - /* - * Get the default colormap for a specific screen depth - */ +/** + * fb_default_cmap - get default colormap + * @len: size of palette for a depth + * + * Gets the default colormap for a specific screen depth. @len + * is the size of the palette for a particular screen depth. + * + * Returns pointer to a frame buffer colormap structure. + * + */ struct fb_cmap *fb_default_cmap(int len) { @@ -269,9 +316,12 @@ } - /* - * Invert all default colormaps - */ +/** + * fb_invert_cmaps - invert all defaults colormaps + * + * Invert all default colormaps. + * + */ void fb_invert_cmaps(void) { diff -u --recursive --new-file v2.4.2/linux/drivers/video/fbgen.c linux/drivers/video/fbgen.c --- v2.4.2/linux/drivers/video/fbgen.c Wed Jul 26 11:08:41 2000 +++ linux/drivers/video/fbgen.c Fri Mar 2 18:38:39 2001 @@ -3,6 +3,9 @@ * * Created 3 Jan 1998 by Geert Uytterhoeven * + * 2001 - Documented with DocBook + * - Brad Douglas + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. @@ -25,9 +28,18 @@ /* ---- `Generic' versions of the frame buffer device operations ----------- */ - /* - * Get the Fixed Part of the Display - */ +/** + * fbgen_get_fix - get fixed part of display + * @fix: fb_fix_screeninfo structure + * @con: virtual console number + * @info: frame buffer info structure + * + * Get the fixed information part of the display and place it + * into @fix for virtual console @con on device @info. + * + * Returns negative errno on error, or zero on success. + * + */ int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) { @@ -48,9 +60,18 @@ } - /* - * Get the User Defined Part of the Display - */ +/** + * fbgen_get_var - get user defined part of display + * @var: fb_var_screeninfo structure + * @con: virtual console number + * @info: frame buffer info structure + * + * Get the user defined part of the display and place it into @var + * for virtual console @con on device @info. + * + * Returns negative errno on error, or zero for success. + * + */ int fbgen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -67,9 +88,18 @@ } - /* - * Set the User Defined Part of the Display - */ +/** + * fbgen_set_var - set the user defined part of display + * @var: fb_var_screeninfo user defined part of the display + * @con: virtual console number + * @info: frame buffer info structure + * + * Set the user defined part of the display as dictated by @var + * for virtual console @con on device @info. + * + * Returns negative errno on error, or zero for success. + * + */ int fbgen_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { @@ -105,9 +135,19 @@ } - /* - * Get the Colormap - */ +/** + * fbgen_get_cmap - get the colormap + * @cmap: frame buffer colormap structure + * @kspc: boolean, 0 copy local, 1 put_user() function + * @con: virtual console number + * @info: frame buffer info structure + * + * Gets the colormap for virtual console @con and places it into + * @cmap for device @info. + * + * Returns negative errno on error, or zero for success. + * + */ int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) @@ -128,9 +168,19 @@ } - /* - * Set the Colormap - */ +/** + * fbgen_set_cmap - set the colormap + * @cmap: frame buffer colormap structure + * @kspc: boolean, 0 copy local, 1 get_user() function + * @con: virtual console number + * @info: frame buffer info structure + * + * Sets the colormap @cmap for virtual console @con on + * device @info. + * + * Returns negative errno on error, or zero for success. + * + */ int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) @@ -152,11 +202,20 @@ } - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ +/** + * fbgen_pan_display - pan or wrap the display + * @var: frame buffer user defined part of display + * @con: virtual console number + * @info: frame buffer info structure + * + * Pan or wrap virtual console @con for device @info. + * + * This call looks only at xoffset, yoffset and the + * FB_VMODE_YWRAP flag in @var. + * + * Returns negative errno on error, or zero for success. + * + */ int fbgen_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) @@ -193,9 +252,18 @@ /* ---- Helper functions --------------------------------------------------- */ - /* - * Change the video mode - */ +/** + * fbgen_do_set_var - change the video mode + * @var: frame buffer user defined part of display + * @isactive: boolean, 0 inactive, 1 active + * @info: generic frame buffer info structure + * + * Change the video mode settings for device @info. If @isactive + * is non-zero, the changes will be activated immediately. + * + * Return negative errno on error, or zero for success. + * + */ int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info_gen *info) @@ -215,6 +283,15 @@ } +/** + * fbgen_set_disp - set generic display + * @con: virtual console number + * @info: generic frame buffer info structure + * + * Sets a display on virtual console @con for device @info. + * + */ + void fbgen_set_disp(int con, struct fb_info_gen *info) { struct fbgen_hwswitch *fbhw = info->fbhw; @@ -254,9 +331,15 @@ } - /* - * Install the current colormap - */ +/** + * fbgen_install_cmap - install the current colormap + * @con: virtual console number + * @info: generic frame buffer info structure + * + * Installs the current colormap for virtual console @con on + * device @info. + * + */ void fbgen_install_cmap(int con, struct fb_info_gen *info) { @@ -272,9 +355,18 @@ } - /* - * Update the `var' structure (called by fbcon.c) - */ +/** + * fbgen_update_var - update user defined part of display + * @con: virtual console number + * @info: frame buffer info structure + * + * Updates the user defined part of the display ('var' + * structure) on virtual console @con for device @info. + * This function is called by fbcon.c. + * + * Returns negative errno on error, or zero for success. + * + */ int fbgen_update_var(int con, struct fb_info *info) { @@ -290,9 +382,16 @@ } - /* - * Switch to a different virtual console - */ +/** + * fbgen_switch - switch to a different virtual console. + * @con: virtual console number + * @info: frame buffer info structure + * + * Switch to virtuall console @con on device @info. + * + * Returns zero. + * + */ int fbgen_switch(int con, struct fb_info *info) { @@ -311,9 +410,14 @@ } - /* - * Blank the screen - */ +/** + * fbgen_blank - blank the screen + * @blank: boolean, 0 unblank, 1 blank + * @info: frame buffer info structure + * + * Blank the screen on device @info. + * + */ void fbgen_blank(int blank, struct fb_info *info) { diff -u --recursive --new-file v2.4.2/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- v2.4.2/linux/drivers/video/fbmem.c Wed Feb 21 18:20:37 2001 +++ linux/drivers/video/fbmem.c Fri Mar 2 18:38:39 2001 @@ -3,6 +3,9 @@ * * Copyright (C) 1994 Martin Schaller * + * 2001 - Documented with DocBook + * - Brad Douglas + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. @@ -115,6 +118,8 @@ extern int sisfb_setup(char*); extern int stifb_init(void); extern int stifb_setup(char*); +extern int radeonfb_init(void); +extern int radeonfb_setup(char*); static struct { const char *name; @@ -167,6 +172,9 @@ #ifdef CONFIG_FB_RIVA { "riva", rivafb_init, rivafb_setup }, #endif +#ifdef CONFIG_FB_RADEON + { "radeon", radeonfb_init, radeonfb_setup }, +#endif #ifdef CONFIG_FB_CONTROL { "controlfb", control_init, control_setup }, #endif @@ -683,6 +691,17 @@ static devfs_handle_t devfs_handle; + +/** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure + * + * Registers a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ + int register_framebuffer(struct fb_info *fb_info) { @@ -732,6 +751,17 @@ return 0; } + +/** + * unregister_framebuffer - releases a frame buffer device + * @fb_info: frame buffer info structure + * + * Unregisters a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ + int unregister_framebuffer(struct fb_info *fb_info) { @@ -752,6 +782,16 @@ return 0; } + +/** + * fbmem_init - init frame buffer subsystem + * + * Initialize the frame buffer subsystem. + * + * NOTE: This function is _only_ to be called by drivers/char/mem.c. + * + */ + void __init fbmem_init(void) { @@ -781,9 +821,18 @@ fb_drivers[i].init(); } - /* - * Command line options - */ + +/** + * video_setup - process command line options + * @options: string of options + * + * Process command line options for frame buffer subsystem. + * + * NOTE: This function is a __setup and __init function. + * + * Returns zero. + * + */ int __init video_setup(char *options) { diff -u --recursive --new-file v2.4.2/linux/drivers/video/fonts.c linux/drivers/video/fonts.c --- v2.4.2/linux/drivers/video/fonts.c Tue Jul 11 15:35:51 2000 +++ linux/drivers/video/fonts.c Fri Mar 2 18:38:39 2001 @@ -4,6 +4,9 @@ * Created 1995 by Geert Uytterhoeven * Rewritten 1998 by Martin Mares * + * 2001 - Documented with DocBook + * - Brad Douglas + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. @@ -61,9 +64,17 @@ #error No fonts configured. #endif - /* - * Find a font with a specific name - */ + +/** + * fbcon_find_font - find a font + * @name: string name of a font + * + * Find a specified font with string name @name. + * + * Returns %NULL if no font found, or a pointer to the + * specified font. + * + */ struct fbcon_font_desc *fbcon_find_font(char *name) { @@ -76,9 +87,18 @@ } - /* - * Get the default font for a specific screen size - */ +/** + * fbcon_get_default_font - get default font + * @xres: screen size of X + * @yres: screen size of Y + * + * Get the default font for a specified screen size. + * Dimensions are in pixels. + * + * Returns %NULL if no font is found, or a pointer to the + * chosen font. + * + */ struct fbcon_font_desc *fbcon_get_default_font(int xres, int yres) { diff -u --recursive --new-file v2.4.2/linux/drivers/video/macmodes.c linux/drivers/video/macmodes.c --- v2.4.2/linux/drivers/video/macmodes.c Mon Nov 27 17:11:26 2000 +++ linux/drivers/video/macmodes.c Fri Mar 2 18:38:39 2001 @@ -7,6 +7,9 @@ * - Ani Joshi * - Brad Douglas * + * 2001 - Documented with DocBook + * - Brad Douglas + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. @@ -203,12 +206,39 @@ }; +/** + * console_getmode - get current mode + * @mode: virtual console mode structure + * + * Populates @mode with the current mode held in the global + * display_info structure. + * + * Note, this function is only for XPMAC compatibility. + * + * Returns zero. + */ + int console_getmode(struct vc_mode *mode) { *mode = display_info; return 0; } + +/** + * console_setmode - sets current console mode + * @mode: virtual console mode structure + * @doit: boolean, 0 test mode, 1 test and activate mode + * + * Sets @mode for all virtual consoles if @doit is non-zero, + * otherwise, test a mode for validity. + * + * Note, this function is only for XPMAC compatibility. + * + * Returns negative errno on error, or zero for success. + * + */ + int console_setmode(struct vc_mode *mode, int doit) { struct fb_var_screeninfo var; @@ -255,6 +285,23 @@ return 0; } + +/** + * console_setcmap - sets palette color map for console + * @n_entries: number of entries in the palette (max 16) + * @red: value for red component of palette + * @green: value for green component of palette + * @blue: value for blue component of palette + * + * Sets global palette_cmap structure and activates the palette + * on the current console. + * + * Note, this function is only for XPMAC compatibility. + * + * Returns negative errno on error, or zero for success. + * + */ + int console_setcmap(int n_entries, unsigned char *red, unsigned char *green, unsigned char *blue) { @@ -285,6 +332,21 @@ return 0; } + +/** + * console_powermode - sets monitor power mode + * @mode: power state to set + * + * Sets power state as dictated by @mode. + * + * Note that this function is only for XPMAC compatibility and + * doesn't do much. + * + * Returns 0 for %VC_POWERMODE_INQUIRY, -EINVAL for VESA power + * settings, or -ENIXIO on failure. + * + */ + int console_powermode(int mode) { if (mode == VC_POWERMODE_INQUIRY) @@ -297,9 +359,18 @@ #endif /* CONFIG_FB_COMPAT_XPMAC */ - /* - * Convert a MacOS vmode/cmode pair to a frame buffer video mode structure - */ +/** + * mac_vmode_to_var - converts vmode/cmode pair to var structure + * @vmode: MacOS video mode + * @cmode: MacOS color mode + * @var: frame buffer video mode structure + * + * Converts a MacOS vmode/cmode pair to a frame buffer video + * mode structure. + * + * Returns negative errno on error, or zero for success. + * + */ int mac_vmode_to_var(int vmode, int cmode, struct fb_var_screeninfo *var) { @@ -370,9 +441,18 @@ } - /* - * Convert a frame buffer video mode structure to a MacOS vmode/cmode pair - */ +/** + * mac_var_to_vmode - convert var structure to MacOS vmode/cmode pair + * @var: frame buffer video mode structure + * @vmode: MacOS video mode + * @cmode: MacOS color mode + * + * Converts a frame buffer video mode structure to a MacOS + * vmode/cmode pair. + * + * Returns negative errno on error, or zero for success. + * + */ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, int *cmode) @@ -406,9 +486,16 @@ } - /* - * Convert a Mac monitor sense number to a MacOS vmode number - */ +/** + * mac_map_monitor_sense - Convert monitor sense to vmode + * @sense: Macintosh monitor sense number + * + * Converts a Macintosh monitor sense number to a MacOS + * vmode number. + * + * Returns MacOS vmode video mode number. + * + */ int mac_map_monitor_sense(int sense) { @@ -421,12 +508,25 @@ } - /* - * Find a suitable video mode - * - * If the name of the wanted mode begins with `mac', use the Mac video - * mode database, else fall back to the standard video mode database. - */ +/** + * mac_find_mode - find a video mode + * @var: frame buffer user defined part of display + * @info: frame buffer info structure + * @mode_option: video mode name (see mac_modedb[]) + * @default_bpp: default color depth in bits per pixel + * + * Finds a suitable video mode. Tries to set mode specified + * by @mode_option. If the name of the wanted mode begins with + * 'mac', the Mac video mode database will be used, otherwise it + * will fall back to the standard video mode database. + * + * Note: Function marked as __init and can only be used during + * system boot. + * + * Returns error code from fb_find_mode (see fb_find_mode + * function). + * + */ int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, const char *mode_option, unsigned int default_bpp) diff -u --recursive --new-file v2.4.2/linux/drivers/video/modedb.c linux/drivers/video/modedb.c --- v2.4.2/linux/drivers/video/modedb.c Thu Mar 23 10:07:42 2000 +++ linux/drivers/video/modedb.c Fri Mar 2 18:38:39 2001 @@ -3,6 +3,9 @@ * * Copyright (C) 1999 Geert Uytterhoeven * + * 2001 - Documented with DocBook + * - Brad Douglas + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. @@ -276,6 +279,20 @@ return MINOR(current->tty->device) - 1; } + +/** + * __fb_try_mode - test a video mode + * @var: frame buffer user defined part of display + * @info: frame buffer info structure + * @mode: frame buffer video mode structure + * @bpp: color depth in bits per pixel + * + * Tries a video mode to test it's validity for device @info. + * + * Returns 1 on success. + * + */ + int __fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, const struct fb_videomode *mode, unsigned int bpp) { @@ -306,21 +323,37 @@ } - /* - * - * Find a suitable video mode - * - * Valid mode specifiers (mode_option): - * - * x[-][@] - * [-][@] - * - * with , , and decimal numbers and a - * string - * - * The passed struct fb_var_screeninfo is _not_ cleared! This allows you - * to supply values for e.g. the grayscale and accel_flags fields. - */ +/** + * fb_find_mode - finds a valid video mode + * @var: frame buffer user defined part of display + * @info: frame buffer info structure + * @mode_option: string video mode to find + * @db: video mode database + * @dbsize: size of @db + * @default_mode: default video mode to fall back to + * @default_bpp: default color depth in bits per pixel + * + * Finds a suitable video mode, starting with the specified mode + * in @mode_option with fallback to @default_mode. If + * @default_mode fails, all modes in the video mode database will + * be tried. + * + * Valid mode specifiers for @mode_option: + * + * x[-][@] or + * [-][@] + * + * with , , and decimal numbers and + * a string. + * + * NOTE: The passed struct @var is _not_ cleared! This allows you + * to supply values for e.g. the grayscale and accel_flags fields. + * + * Returns zero for failure, 1 if using specified @mode_option, + * 2 if using specified @mode_option with an ignored refresh rate, + * 3 if default mode is used, 4 if fall back to any valid mode. + * + */ int __init fb_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, const char *mode_option, diff -u --recursive --new-file v2.4.2/linux/drivers/video/sis/sis_301.h linux/drivers/video/sis/sis_301.h --- v2.4.2/linux/drivers/video/sis/sis_301.h Sun Nov 12 20:40:42 2000 +++ linux/drivers/video/sis/sis_301.h Tue Mar 6 19:28:33 2001 @@ -3,7 +3,7 @@ USHORT SetFlag,RVBHCFACT,RVBHCMAX,VGAVT,VGAHT,VT,HT,VGAVDE,VGAHDE; USHORT VDE,HDE,RVBHRS,NewFlickerMode,RY1COE,RY2COE,RY3COE,RY4COE; -;USHORT LCDResInfo,LCDTypeInfo,LCDInfo; +extern USHORT LCDResInfo,LCDTypeInfo,LCDInfo; USHORT VCLKLen; USHORT LCDHDES,LCDVDES; diff -u --recursive --new-file v2.4.2/linux/fs/Makefile linux/fs/Makefile --- v2.4.2/linux/fs/Makefile Sat Feb 3 19:51:30 2001 +++ linux/fs/Makefile Fri Mar 2 15:16:59 2001 @@ -7,7 +7,7 @@ O_TARGET := fs.o -export-objs := filesystems.o +export-objs := filesystems.o dcache.o mod-subdirs := nls obj-y := open.o read_write.o devices.o file_table.o buffer.o \ diff -u --recursive --new-file v2.4.2/linux/fs/adfs/super.c linux/fs/adfs/super.c --- v2.4.2/linux/fs/adfs/super.c Wed Feb 21 18:20:38 2001 +++ linux/fs/adfs/super.c Fri Mar 2 11:12:11 2001 @@ -385,6 +385,12 @@ sb->u.adfs_sb.s_size = adfs_discsize(dr, sb->s_blocksize_bits); sb->u.adfs_sb.s_version = dr->format_version; sb->u.adfs_sb.s_log2sharesize = dr->log2sharesize; + + /* + * Max file size is 2Gb + */ + + sb->s_maxbytes = MAX_NON_LFS; sb->u.adfs_sb.s_map = adfs_read_map(sb, dr); if (!sb->u.adfs_sb.s_map) diff -u --recursive --new-file v2.4.2/linux/fs/affs/super.c linux/fs/affs/super.c --- v2.4.2/linux/fs/affs/super.c Wed Feb 21 18:20:38 2001 +++ linux/fs/affs/super.c Fri Mar 2 11:12:11 2001 @@ -415,6 +415,12 @@ s->s_flags |= MS_NODEV | MS_NOSUID; + /* + * Max file size is 2Gb + */ + + s->s_maxbytes = MAX_NON_LFS; + /* Keep super block in cache */ bb = affs_bread(dev,root_block,s->s_blocksize); if (!bb) diff -u --recursive --new-file v2.4.2/linux/fs/bfs/inode.c linux/fs/bfs/inode.c --- v2.4.2/linux/fs/bfs/inode.c Tue Nov 28 22:43:39 2000 +++ linux/fs/bfs/inode.c Fri Mar 2 11:12:11 2001 @@ -250,6 +250,7 @@ set_blocksize(dev, BFS_BSIZE); s->s_blocksize = BFS_BSIZE; s->s_blocksize_bits = BFS_BSIZE_BITS; + s->s_maxbytes = MAX_NON_LFS; bh = bread(dev, 0, BFS_BSIZE); if(!bh) diff -u --recursive --new-file v2.4.2/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- v2.4.2/linux/fs/binfmt_aout.c Wed Feb 21 18:20:38 2001 +++ linux/fs/binfmt_aout.c Tue Mar 6 19:44:37 2001 @@ -342,7 +342,7 @@ error = bprm->file->f_op->read(bprm->file, (char *)text_addr, ex.a_text+ex.a_data, &pos); - if (error < 0) { + if ((signed long)error < 0) { send_sig(SIGKILL, current, 0); return error; } diff -u --recursive --new-file v2.4.2/linux/fs/buffer.c linux/fs/buffer.c --- v2.4.2/linux/fs/buffer.c Wed Feb 21 18:20:38 2001 +++ linux/fs/buffer.c Tue Mar 6 19:28:35 2001 @@ -2750,7 +2750,7 @@ tsk->session = 1; tsk->pgrp = 1; - strcpy(tsk->comm, "kupdate"); + strcpy(tsk->comm, "kupdated"); /* sigstop and sigcont will stop and wakeup kupdate */ spin_lock_irq(&tsk->sigmask_lock); diff -u --recursive --new-file v2.4.2/linux/fs/coda/inode.c linux/fs/coda/inode.c --- v2.4.2/linux/fs/coda/inode.c Fri Dec 29 14:07:57 2000 +++ linux/fs/coda/inode.c Fri Mar 2 11:12:11 2001 @@ -141,6 +141,7 @@ sb->s_magic = CODA_SUPER_MAGIC; sb->s_dev = dev; sb->s_op = &coda_super_operations; + sb->s_maxbytes = MAX_NON_LFS; /* get root fid from Venus: this needs the root inode */ error = venus_rootfid(sb, &fid); diff -u --recursive --new-file v2.4.2/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c --- v2.4.2/linux/fs/cramfs/inode.c Fri Dec 29 14:07:57 2000 +++ linux/fs/cramfs/inode.c Fri Mar 2 11:12:11 2001 @@ -194,9 +194,9 @@ /* Set it all up.. */ sb->s_op = &cramfs_ops; - sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); + sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); + sb->s_maxbytes = MAX_NON_LFS; retval = sb; - out: return retval; } diff -u --recursive --new-file v2.4.2/linux/fs/dcache.c linux/fs/dcache.c --- v2.4.2/linux/fs/dcache.c Wed Feb 21 18:20:38 2001 +++ linux/fs/dcache.c Wed Mar 7 16:53:48 2001 @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -223,8 +224,7 @@ atomic_inc(&dentry->d_count); if (atomic_read(&dentry->d_count) == 1) { dentry_stat.nr_unused--; - list_del(&dentry->d_lru); - INIT_LIST_HEAD(&dentry->d_lru); /* make "list_empty()" work */ + list_del_init(&dentry->d_lru); } return dentry; } @@ -413,8 +413,7 @@ if (atomic_read(&dentry->d_count)) continue; dentry_stat.nr_unused--; - list_del(tmp); - INIT_LIST_HEAD(tmp); + list_del_init(tmp); prune_one_dentry(dentry); goto repeat; } @@ -656,6 +655,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode) { + if (!list_empty(&entry->d_alias)) BUG(); spin_lock(&dcache_lock); if (inode) list_add(&entry->d_alias, &inode->i_dentry); @@ -744,58 +744,48 @@ /** * d_validate - verify dentry provided from insecure source - * @dentry: The dentry alleged to be valid - * @dparent: The parent dentry + * @dentry: The dentry alleged to be valid child of @dparent + * @dparent: The parent dentry (known to be valid) * @hash: Hash of the dentry * @len: Length of the name * * An insecure source has sent us a dentry, here we verify it and dget() it. * This is used by ncpfs in its readdir implementation. * Zero is returned in the dentry is invalid. - * - * NOTE: This function does _not_ dereference the pointers before we have - * validated them. We can test the pointer values, but we - * must not actually use them until we have found a valid - * copy of the pointer in kernel space.. */ -int d_validate(struct dentry *dentry, struct dentry *dparent, - unsigned int hash, unsigned int len) +int d_validate(struct dentry *dentry, struct dentry *dparent) { + unsigned long dent_addr = (unsigned long) dentry; + unsigned long min_addr = PAGE_OFFSET; + unsigned long align_mask = 0x0F; struct list_head *base, *lhp; - int valid = 1; - spin_lock(&dcache_lock); - if (dentry != dparent) { - base = d_hash(dparent, hash); - lhp = base; - while ((lhp = lhp->next) != base) { - if (dentry == list_entry(lhp, struct dentry, d_hash)) { - __dget_locked(dentry); - goto out; - } - } - } else { - /* - * Special case: local mount points don't live in - * the hashes, so we search the super blocks. - */ - struct super_block *sb = sb_entry(super_blocks.next); + if (dent_addr < min_addr) + goto out; + if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry)) + goto out; + if (dent_addr & align_mask) + goto out; + if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 + + sizeof(struct dentry)))) + goto out; - for (; sb != sb_entry(&super_blocks); - sb = sb_entry(sb->s_list.next)) { - if (!sb->s_dev) - continue; - if (sb->s_root == dentry) { - __dget_locked(dentry); - goto out; - } + if (dentry->d_parent != dparent) + goto out; + + spin_lock(&dcache_lock); + lhp = base = d_hash(dparent, dentry->d_name.hash); + while ((lhp = lhp->next) != base) { + if (dentry == list_entry(lhp, struct dentry, d_hash)) { + __dget_locked(dentry); + spin_unlock(&dcache_lock); + return 1; } } - valid = 0; -out: spin_unlock(&dcache_lock); - return valid; +out: + return 0; } /* @@ -848,6 +838,7 @@ void d_rehash(struct dentry * entry) { struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash); + if (!list_empty(&entry->d_hash)) BUG(); spin_lock(&dcache_lock); list_add(&entry->d_hash, list); spin_unlock(&dcache_lock); @@ -922,8 +913,7 @@ list_add(&dentry->d_hash, &target->d_hash); /* Unhash the target: dput() will then get rid of it */ - list_del(&target->d_hash); - INIT_LIST_HEAD(&target->d_hash); + list_del_init(&target->d_hash); list_del(&dentry->d_child); list_del(&target->d_child); @@ -1250,6 +1240,7 @@ /* SLAB cache for buffer_head structures */ kmem_cache_t *bh_cachep; +EXPORT_SYMBOL(bh_cachep); void __init vfs_caches_init(unsigned long mempages) { diff -u --recursive --new-file v2.4.2/linux/fs/efs/super.c linux/fs/efs/super.c --- v2.4.2/linux/fs/efs/super.c Wed Jun 21 10:10:02 2000 +++ linux/fs/efs/super.c Fri Mar 2 11:12:11 2001 @@ -178,6 +178,8 @@ s->s_magic = EFS_SUPER_MAGIC; s->s_blocksize = EFS_BLOCKSIZE; s->s_blocksize_bits = EFS_BLOCKSIZE_BITS; + s->s_maxbytes = MAX_NON_LFS; + if (!(s->s_flags & MS_RDONLY)) { #ifdef DEBUG printk(KERN_INFO "EFS: forcing read-only mode\n"); diff -u --recursive --new-file v2.4.2/linux/fs/hfs/super.c linux/fs/hfs/super.c --- v2.4.2/linux/fs/hfs/super.c Wed Feb 21 18:20:39 2001 +++ linux/fs/hfs/super.c Fri Mar 2 11:12:11 2001 @@ -436,6 +436,7 @@ goto bail1; } + s->s_maxbytes = MAX_NON_LFS; s->s_magic = HFS_SUPER_MAGIC; s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS; s->s_blocksize = HFS_SECTOR_SIZE; diff -u --recursive --new-file v2.4.2/linux/fs/hpfs/super.c linux/fs/hpfs/super.c --- v2.4.2/linux/fs/hpfs/super.c Tue Sep 5 14:07:30 2000 +++ linux/fs/hpfs/super.c Fri Mar 2 11:12:11 2001 @@ -427,6 +427,7 @@ s->s_blocksize = 512; s->s_blocksize_bits = 9; s->s_op = &hpfs_sops; + s->s_maxbytes = MAX_NON_LFS; s->s_hpfs_root = superblock->root; s->s_hpfs_fs_size = superblock->n_sectors; diff -u --recursive --new-file v2.4.2/linux/fs/inode.c linux/fs/inode.c --- v2.4.2/linux/fs/inode.c Wed Feb 21 18:20:39 2001 +++ linux/fs/inode.c Fri Mar 2 15:16:59 2001 @@ -613,6 +613,7 @@ inode->i_bdev = NULL; inode->i_data.a_ops = &empty_aops; inode->i_data.host = inode; + inode->i_data.gfp_mask = GFP_HIGHUSER; inode->i_mapping = &inode->i_data; } diff -u --recursive --new-file v2.4.2/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.4.2/linux/fs/isofs/inode.c Wed Feb 21 18:20:39 2001 +++ linux/fs/isofs/inode.c Fri Mar 2 11:12:11 2001 @@ -616,7 +616,7 @@ #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (h_pri->volume_set_size) != 1) goto out_no_support; -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size); @@ -625,7 +625,7 @@ #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (pri->volume_set_size) != 1) goto out_no_support; -#endif IGNORE_WRONG_MULTI_VOLUME_SPECS +#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */ s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size); @@ -662,6 +662,11 @@ Rock Ridge extensions) */ s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; + + /* Set this for reference. Its not currently used except on write + which we don't have .. */ + + s->s_maxbytes = MAX_NON_LFS; /* RDE: data zone now byte offset! */ diff -u --recursive --new-file v2.4.2/linux/fs/jffs/inode-v23.c linux/fs/jffs/inode-v23.c --- v2.4.2/linux/fs/jffs/inode-v23.c Wed Feb 21 18:20:39 2001 +++ linux/fs/jffs/inode-v23.c Fri Mar 2 11:12:11 2001 @@ -10,8 +10,8 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: inode-v23.c,v 1.43 2000/08/22 08:00:22 dwmw2 Exp $ - * + * $Id: inode-v23.c,v 1.43.2.6 2001/01/09 00:32:48 dwmw2 Exp $ + * + sb_maxbytes / generic_file_open() fixes for 2.4.0-ac4 * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB @@ -84,6 +84,7 @@ sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->u.generic_sbp = (void *) 0; + sb->s_maxbytes = 0xFFFFFFFF; /* Build the file system. */ if (jffs_build_fs(sb) < 0) { diff -u --recursive --new-file v2.4.2/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v2.4.2/linux/fs/minix/inode.c Wed Feb 21 18:20:39 2001 +++ linux/fs/minix/inode.c Fri Mar 2 11:12:11 2001 @@ -259,6 +259,9 @@ minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data); minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data); + + s->s_maxbytes = MAX_NON_LFS; + /* set up enough so that it can read an inode */ s->s_op = &minix_sops; root_inode = iget(s, MINIX_ROOT_INO); diff -u --recursive --new-file v2.4.2/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c --- v2.4.2/linux/fs/ncpfs/dir.c Wed Feb 21 18:20:39 2001 +++ linux/fs/ncpfs/dir.c Wed Mar 7 16:53:48 2001 @@ -326,56 +326,15 @@ return res; } -/* most parts from nfsd_d_validate() */ -static int -ncp_d_validate(struct dentry *dentry) -{ - unsigned long dent_addr = (unsigned long) dentry; - unsigned long min_addr = PAGE_OFFSET; - unsigned long align_mask = 0x0F; - unsigned int len; - int valid = 0; - - if (dent_addr < min_addr) - goto bad_addr; - if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry)) - goto bad_addr; - if ((dent_addr & ~align_mask) != dent_addr) - goto bad_align; - if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 + - sizeof(struct dentry)))) - goto bad_addr; - /* - * Looks safe enough to dereference ... - */ - len = dentry->d_name.len; - if (len > NCP_MAXPATHLEN) - goto out; - /* - * Note: d_validate doesn't dereference the parent pointer ... - * just combines it with the name hash to find the hash chain. - */ - valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len); -out: - return valid; - -bad_addr: - PRINTK("ncp_d_validate: invalid address %lx\n", dent_addr); - goto out; -bad_align: - PRINTK("ncp_d_validate: unaligned address %lx\n", dent_addr); - goto out; -} - static struct dentry * ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) { struct dentry *dent = dentry; struct list_head *next; - if (ncp_d_validate(dent)) { - if (dent->d_parent == parent && - (unsigned long)dent->d_fsdata == fpos) { + if (d_validate(dent, parent)) { + if (dent->d_name.len <= NCP_MAXPATHLEN && + (unsigned long)dent->d_fsdata == fpos) { if (!dent->d_inode) { dput(dent); dent = NULL; @@ -580,6 +539,7 @@ struct ncp_cache_control ctl = *ctrl; struct qstr qname; int valid = 0; + int hashed = 0; ino_t ino = 0; __u8 __name[256]; @@ -602,9 +562,11 @@ newdent = d_alloc(dentry, &qname); if (!newdent) goto end_advance; - } else + } else { + hashed = 1; memcpy((char *) newdent->d_name.name, qname.name, newdent->d_name.len); + } if (!newdent->d_inode) { entry->opened = 0; @@ -612,7 +574,9 @@ newino = ncp_iget(inode->i_sb, entry); if (newino) { newdent->d_op = &ncp_dentry_operations; - d_add(newdent, newino); + d_instantiate(newdent, newino); + if (!hashed) + d_rehash(newdent); } } else ncp_update_inode2(newdent->d_inode, entry); diff -u --recursive --new-file v2.4.2/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c --- v2.4.2/linux/fs/ncpfs/inode.c Wed Feb 21 18:20:39 2001 +++ linux/fs/ncpfs/inode.c Fri Mar 2 11:12:11 2001 @@ -327,6 +327,7 @@ else default_bufsize = 1024; + sb->s_maxbytes = MAX_NON_LFS; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = NCP_SUPER_MAGIC; diff -u --recursive --new-file v2.4.2/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c --- v2.4.2/linux/fs/ncpfs/mmap.c Wed Feb 21 18:20:39 2001 +++ linux/fs/ncpfs/mmap.c Fri Mar 2 15:15:12 2001 @@ -43,7 +43,7 @@ int bufsize; int pos; - page = alloc_page(GFP_HIGHMEM); /* ncpfs has nothing against GFP_HIGHMEM + page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages as long as recvmsg and memset works on it */ if (!page) return page; diff -u --recursive --new-file v2.4.2/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.4.2/linux/fs/nfs/dir.c Wed Feb 21 18:20:40 2001 +++ linux/fs/nfs/dir.c Fri Mar 2 15:20:50 2001 @@ -321,7 +321,7 @@ desc->page = NULL; } - page = page_cache_alloc(); + page = alloc_page(GFP_HIGHUSER); if (!page) { status = -ENOMEM; goto out; diff -u --recursive --new-file v2.4.2/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.4.2/linux/fs/nfs/inode.c Wed Feb 21 18:20:40 2001 +++ linux/fs/nfs/inode.c Fri Mar 2 11:12:11 2001 @@ -434,6 +434,11 @@ if (server->namelen == 0 || server->namelen > maxlen) server->namelen = maxlen; + if(version == 2) + sb->s_maxbytes = MAX_NON_LFS; + else + sb->s_maxbytes = ~0ULL; /* Unlimited on NFSv3 */ + /* Fire up the writeback cache */ if (nfs_reqlist_alloc(server) < 0) { printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n"); diff -u --recursive --new-file v2.4.2/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c --- v2.4.2/linux/fs/nfsd/nfsproc.c Wed Feb 21 18:20:40 2001 +++ linux/fs/nfsd/nfsproc.c Mon Mar 12 18:14:55 2001 @@ -196,7 +196,7 @@ struct iattr *attr = &argp->attrs; struct inode *inode; struct dentry *dchild; - int nfserr, type, mode, rdonly = 0; + int nfserr, type, mode; dev_t rdev = NODEV; dprintk("nfsd: CREATE %s %s\n", @@ -207,13 +207,7 @@ if (nfserr) goto done; /* must fh_put dirfhp even on error */ - /* Check for MAY_WRITE separately. */ - nfserr = nfsd_permission(dirfhp->fh_export, dirfhp->fh_dentry, - MAY_WRITE); - if (nfserr == nfserr_rofs) { - rdonly = 1; /* Non-fatal error for echo > /dev/null */ - } else if (nfserr) - goto done; + /* Check for MAY_WRITE in nfsd_create if necessary */ nfserr = nfserr_acces; if (!argp->len) @@ -257,10 +251,25 @@ * else assume a file */ if (inode) { type = inode->i_mode & S_IFMT; - if (type == S_IFCHR || type == S_IFBLK) { + switch(type) { + case S_IFCHR: + case S_IFBLK: /* reserve rdev for later checking */ attr->ia_size = inode->i_rdev; attr->ia_valid |= ATTR_SIZE; + + /* FALLTHROUGH */ + case S_IFIFO: + /* this is probably a permission check.. + * at least IRIX implements perm checking on + * echo thing > device-special-file-or-pipe + * by does a CREATE with type==0 + */ + nfserr = nfsd_permission(newfhp->fh_export, + newfhp->fh_dentry, + MAY_WRITE); + if (nfserr && nfserr != nfserr_rofs) + goto out_unlock; } } else type = S_IFREG; @@ -272,11 +281,6 @@ type = S_IFREG; mode = 0; /* ??? */ } - - /* This is for "echo > /dev/null" a la SunOS. Argh. */ - nfserr = nfserr_rofs; - if (rdonly && (!inode || type == S_IFREG)) - goto out_unlock; attr->ia_valid |= ATTR_MODE; attr->ia_mode = mode; diff -u --recursive --new-file v2.4.2/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.4.2/linux/fs/nfsd/vfs.c Wed Feb 21 18:20:40 2001 +++ linux/fs/nfsd/vfs.c Mon Mar 12 18:13:28 2001 @@ -737,27 +737,24 @@ * nice and simple solution (IMHO), and it seems to * work:-) */ - if (EX_WGATHER(exp) && (atomic_read(&inode->i_writecount) > 1 - || (last_ino == inode->i_ino && last_dev == inode->i_dev))) { -#if 0 - interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000); -#else - dprintk("nfsd: write defer %d\n", current->pid); -/* FIXME: Olaf commented this out [gam3] */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((HZ+99)/100); - current->state = TASK_RUNNING; - dprintk("nfsd: write resume %d\n", current->pid); -#endif - } + if (EX_WGATHER(exp)) { + if (atomic_read(&inode->i_writecount) > 1 + || (last_ino == inode->i_ino && last_dev == inode->i_dev)) { + dprintk("nfsd: write defer %d\n", current->pid); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ+99)/100); + current->state = TASK_RUNNING; + dprintk("nfsd: write resume %d\n", current->pid); + } - if (inode->i_state & I_DIRTY) { - dprintk("nfsd: write sync %d\n", current->pid); - nfsd_sync(&file); - } + if (inode->i_state & I_DIRTY) { + dprintk("nfsd: write sync %d\n", current->pid); + nfsd_sync(&file); + } #if 0 - wake_up(&inode->i_wait); + wake_up(&inode->i_wait); #endif + } last_ino = inode->i_ino; last_dev = inode->i_dev; } diff -u --recursive --new-file v2.4.2/linux/fs/proc/inode.c linux/fs/proc/inode.c --- v2.4.2/linux/fs/proc/inode.c Fri Nov 17 16:51:47 2000 +++ linux/fs/proc/inode.c Fri Mar 2 11:12:12 2001 @@ -188,6 +188,8 @@ s->s_blocksize_bits = 10; s->s_magic = PROC_SUPER_MAGIC; s->s_op = &proc_sops; + s->s_maxbytes = MAX_NON_LFS; + root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); if (!root_inode) goto out_no_root; diff -u --recursive --new-file v2.4.2/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c --- v2.4.2/linux/fs/qnx4/inode.c Wed Feb 21 18:20:40 2001 +++ linux/fs/qnx4/inode.c Fri Mar 2 11:12:12 2001 @@ -369,6 +369,7 @@ } s->s_op = &qnx4_sops; s->s_magic = QNX4_SUPER_MAGIC; + s->s_maxbytes = MAX_NON_LFS; #ifndef CONFIG_QNX4FS_RW s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ #endif diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/dir.c linux/fs/reiserfs/dir.c --- v2.4.2/linux/fs/reiserfs/dir.c Sat Feb 3 19:51:31 2001 +++ linux/fs/reiserfs/dir.c Fri Mar 2 10:06:47 2001 @@ -51,12 +51,16 @@ int windex ; struct reiserfs_transaction_handle th ; + lock_kernel(); + journal_begin(&th, dentry->d_inode->i_sb, 1) ; windex = push_journal_writer("dir_fsync") ; reiserfs_prepare_for_journal(th.t_super, SB_BUFFER_WITH_SB(th.t_super), 1) ; journal_mark_dirty(&th, dentry->d_inode->i_sb, SB_BUFFER_WITH_SB (dentry->d_inode->i_sb)) ; pop_journal_writer(windex) ; journal_end_sync(&th, dentry->d_inode->i_sb, 1) ; + + unlock_kernel(); return ret ; } diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c --- v2.4.2/linux/fs/reiserfs/fix_node.c Sat Feb 3 19:51:31 2001 +++ linux/fs/reiserfs/fix_node.c Fri Mar 2 18:38:39 2001 @@ -840,7 +840,7 @@ /* Get new buffers for storing new nodes that are created while balancing. - * Returns: SCHEDULE_OCCURED - schedule occured while the function worked; + * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; * NO_DISK_SPACE - no disk space. */ @@ -1077,7 +1077,7 @@ * Calculate left/right common parent of the current node and L[h]/R[h]. * Calculate left/right delimiting key position. * Returns: PATH_INCORRECT - path in the tree is not correct; - SCHEDULE_OCCURRED - schedule occured while the function worked; + SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_far_parent (struct tree_balance * p_s_tb, @@ -1198,7 +1198,7 @@ * S[n_path_offset] and L[n_path_offset]/R[n_path_offset]: F[n_path_offset], FL[n_path_offset], * FR[n_path_offset], CFL[n_path_offset], CFR[n_path_offset]. * Calculate numbers of left and right delimiting keys position: lkey[n_path_offset], rkey[n_path_offset]. - * Returns: SCHEDULE_OCCURRED - schedule occured while the function worked; + * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_parents (struct tree_balance * p_s_tb, int n_h) @@ -1340,7 +1340,7 @@ * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1678,7 +1678,7 @@ * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1848,7 +1848,7 @@ * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1951,7 +1951,7 @@ * h current level of the node; * inum item number in S[h]; * mode d - delete, c - cut. - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1985,7 +1985,7 @@ * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste, d - delete, c - cut. - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -2075,7 +2075,7 @@ /* Using lnum[n_h] and rnum[n_h] we should determine what neighbors * of S[n_h] we * need in order to balance S[n_h], and get them if necessary. - * Returns: SCHEDULE_OCCURRED - schedule occured while the function worked; + * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_neighbors( diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c --- v2.4.2/linux/fs/reiserfs/inode.c Sat Feb 3 19:51:31 2001 +++ linux/fs/reiserfs/inode.c Fri Mar 2 18:38:39 2001 @@ -771,6 +771,7 @@ ** flush unbh before the transaction commits */ reiserfs_add_page_to_flush_list(&th, inode, unbh) ; + mark_buffer_dirty(unbh) ; //inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode); @@ -1260,7 +1261,7 @@ retval = search_item (sb, &key, path); if (retval == IO_ERROR) { reiserfs_warning ("vs-13080: reiserfs_new_directory: " - "i/o failure occured creating new directory\n"); + "i/o failure occurred creating new directory\n"); return -EIO; } if (retval == ITEM_FOUND) { @@ -1296,7 +1297,7 @@ retval = search_item (sb, &key, path); if (retval == IO_ERROR) { reiserfs_warning ("vs-13080: reiserfs_new_symlinik: " - "i/o failure occured creating new symlink\n"); + "i/o failure occurred creating new symlink\n"); return -EIO; } if (retval == ITEM_FOUND) { diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c --- v2.4.2/linux/fs/reiserfs/stree.c Sat Feb 3 19:51:31 2001 +++ linux/fs/reiserfs/stree.c Fri Mar 2 18:38:39 2001 @@ -734,7 +734,7 @@ return IO_ERROR; } - /* It is possible that schedule occured. We must check whether the key + /* It is possible that schedule occurred. We must check whether the key to search is still in the tree rooted from the current buffer. If not then repeat search from the root. */ if ( fs_changed (fs_gen, p_s_sb) && @@ -1438,7 +1438,6 @@ if ( p_s_un_bh ) { int off; - int block_off ; char *data ; /* We are in direct2indirect conversion, so move tail contents @@ -1452,7 +1451,8 @@ ** the unformatted node, which might schedule, meaning we'd have to ** loop all the way back up to the start of the while loop. ** - ** The unformatted node is prepared and logged after the do_balance. + ** The unformatted node must be dirtied later on. We can't be + ** sure here if the entire tail has been deleted yet. ** ** p_s_un_bh is from the page cache (all unformatted nodes are ** from the page cache) and might be a highmem page. So, we @@ -1463,25 +1463,13 @@ data = page_address(p_s_un_bh->b_page) ; off = ((le_ih_k_offset (&s_ih) - 1) & (PAGE_CACHE_SIZE - 1)); - block_off = off & (p_s_un_bh->b_size - 1) ; memcpy(data + off, B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value); - - /* clear out the rest of the block past the end of the file. */ - if (block_off + n_ret_value < p_s_un_bh->b_size) { - memset(data + off + n_ret_value, 0, - p_s_un_bh->b_size - block_off - n_ret_value) ; - } } /* Perform balancing after all resources have been collected at once. */ do_balance(&s_del_balance, NULL, NULL, M_DELETE); - /* see comment above for why this is after the do_balance */ - if (p_s_un_bh) { - mark_buffer_dirty(p_s_un_bh) ; - } - /* Return deleted body length */ return n_ret_value; } @@ -1521,7 +1509,7 @@ retval = search_item (th->t_super, &cpu_key, &path); if (retval == IO_ERROR) { reiserfs_warning ("vs-: reiserfs_delete_solid_item: " - "i/o failure occured trying to delete %K\n", &cpu_key); + "i/o failure occurred trying to delete %K\n", &cpu_key); break; } if (retval != ITEM_FOUND) { @@ -1869,7 +1857,7 @@ retval = search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path); if (retval == IO_ERROR) { reiserfs_warning ("vs-5657: reiserfs_do_truncate: " - "i/o failure occured trying to truncate %K\n", &s_item_key); + "i/o failure occurred trying to truncate %K\n", &s_item_key); return; } if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) { diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/super.c linux/fs/reiserfs/super.c --- v2.4.2/linux/fs/reiserfs/super.c Sat Feb 3 19:51:31 2001 +++ linux/fs/reiserfs/super.c Fri Mar 2 11:12:12 2001 @@ -1,5 +1,14 @@ /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README + * + * Trivial changes by Alan Cox to add the LFS fixes + * + * Trivial Changes: + * Rights granted to Hans Reiser to redistribute under other terms providing + * he accepts all liability including but not limited to patent, fitness + * for purpose, and direct or indirect claims arising from failure to perform. + * + * NO WARRANTY */ #ifdef __KERNEL__ @@ -483,6 +492,7 @@ SB_BUFFER_WITH_SB (s) = bh; SB_DISK_SUPER_BLOCK (s) = rs; s->s_op = &reiserfs_sops; + s->s_maxbytes = 0xFFFFFFFF; /* 4Gig */ return 0; } diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c --- v2.4.2/linux/fs/reiserfs/tail_conversion.c Wed Feb 21 18:20:40 2001 +++ linux/fs/reiserfs/tail_conversion.c Wed Feb 28 19:21:58 2001 @@ -32,6 +32,7 @@ struct super_block * sb = inode->i_sb; struct buffer_head *up_to_date_bh ; struct item_head * p_le_ih = PATH_PITEM_HEAD (path); + unsigned long total_tail = 0 ; struct cpu_key end_key; /* Key to search for the last byte of the converted item. */ struct item_head ind_ih; /* new indirect item to be inserted or @@ -121,10 +122,19 @@ n_retval = reiserfs_delete_item (th, path, &end_key, inode, up_to_date_bh) ; + total_tail += n_retval ; if (tail_size == n_retval) // done: file does not have direct items anymore break; + } + /* if we've copied bytes from disk into the page, we need to zero + ** out the unused part of the block (it was not up to date before) + ** the page is still kmapped (by whoever called reiserfs_get_block) + */ + if (up_to_date_bh) { + unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1); + memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ; } inode->u.reiserfs_i.i_first_direct_byte = U32_MAX; diff -u --recursive --new-file v2.4.2/linux/fs/romfs/inode.c linux/fs/romfs/inode.c --- v2.4.2/linux/fs/romfs/inode.c Wed Feb 21 18:20:40 2001 +++ linux/fs/romfs/inode.c Fri Mar 2 11:12:12 2001 @@ -110,6 +110,9 @@ set_blocksize(dev, ROMBSIZE); s->s_blocksize = ROMBSIZE; s->s_blocksize_bits = ROMBSBITS; + s->u.generic_sbp = (void *) 0; + s->s_maxbytes = 0xFFFFFFFF; + bh = bread(dev, 0, ROMBSIZE); if (!bh) { /* XXX merge with other printk? */ diff -u --recursive --new-file v2.4.2/linux/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog --- v2.4.2/linux/fs/smbfs/ChangeLog Wed Feb 21 18:20:40 2001 +++ linux/fs/smbfs/ChangeLog Tue Mar 6 19:14:59 2001 @@ -1,9 +1,22 @@ ChangeLog for smbfs. +2001-03-06 Urban Widmark + + * cache.c: d_add on hashed dentries corrupts d_hash list and + causes loops in d_lookup. Inherited bug. :) + * inode.c: tail -f fix for non-readonly opened files + (related to the smb_proc_open change). + * inode.c: tail -f fix for fast size changes with the same mtime. + +2001-03-02 Michael Kockelkorn + + * proc.c: fix smb_proc_open to allow open being called more than once + with different modes (O_RDONLY -> O_WRONLY) without closing. + 2001-02-10 Urban Widmark - * dir.c: replace non-bigmem safe cache with cache code from ncpfs - and fix some other bigmem bugs in smbfs. + * dir.c, cache.c: replace non-bigmem safe cache with cache code + from ncpfs and fix some other bigmem bugs in smbfs. * inode.c: root dentry not properly initialized * proc.c, sock.c: adjust max parameters & max data to follow max_xmit lots of servers were having find_next trouble with this. diff -u --recursive --new-file v2.4.2/linux/fs/smbfs/cache.c linux/fs/smbfs/cache.c --- v2.4.2/linux/fs/smbfs/cache.c Wed Feb 21 18:20:40 2001 +++ linux/fs/smbfs/cache.c Wed Mar 7 16:53:48 2001 @@ -71,47 +71,6 @@ spin_unlock(&dcache_lock); } - -static int -smb_d_validate(struct dentry *dentry) -{ - unsigned long dent_addr = (unsigned long) dentry; - unsigned long min_addr = PAGE_OFFSET; - unsigned long align_mask = 0x0F; - unsigned int len; - int valid = 0; - - if (dent_addr < min_addr) - goto bad_addr; - if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry)) - goto bad_addr; - if ((dent_addr & ~align_mask) != dent_addr) - goto bad_align; - if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 + - sizeof(struct dentry)))) - goto bad_addr; - /* - * Looks safe enough to dereference ... - */ - len = dentry->d_name.len; - if (len > SMB_MAXPATHLEN) - goto out; - /* - * Note: d_validate doesn't dereference the parent pointer ... - * just combines it with the name hash to find the hash chain. - */ - valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len); -out: - return valid; - -bad_addr: - printk(KERN_ERR "smb_d_validate: invalid address %lx\n", dent_addr); - goto out; -bad_align: - printk(KERN_ERR "smb_d_validate: unaligned address %lx\n", dent_addr); - goto out; -} - /* * dget, but require that fpos and parent matches what the dentry contains. * dentry is not known to be a valid pointer at entry. @@ -122,8 +81,8 @@ struct dentry *dent = dentry; struct list_head *next; - if (smb_d_validate(dent)) { - if (dent->d_parent == parent && + if (d_validate(dent, parent)) { + if (dent->d_name.len <= SMB_MAXPATHLEN && (unsigned long)dent->d_fsdata == fpos) { if (!dent->d_inode) { dput(dent); @@ -167,6 +126,7 @@ struct inode *newino, *inode = dentry->d_inode; struct smb_cache_control ctl = *ctrl; int valid = 0; + int hashed = 0; ino_t ino = 0; qname->hash = full_name_hash(qname->name, qname->len); @@ -181,9 +141,11 @@ newdent = d_alloc(dentry, qname); if (!newdent) goto end_advance; - } else + } else { + hashed = 1; memcpy((char *) newdent->d_name.name, qname->name, newdent->d_name.len); + } if (!newdent->d_inode) { smb_renew_times(newdent); @@ -191,7 +153,9 @@ newino = smb_iget(inode->i_sb, entry); if (newino) { smb_new_dentry(newdent); - d_add(newdent, newino); + d_instantiate(newdent, newino); + if (!hashed) + d_rehash(newdent); } } else smb_set_inode_attr(newdent->d_inode, entry); diff -u --recursive --new-file v2.4.2/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v2.4.2/linux/fs/smbfs/inode.c Wed Feb 21 18:20:40 2001 +++ linux/fs/smbfs/inode.c Tue Mar 6 19:14:59 2001 @@ -161,17 +161,15 @@ struct smb_fattr fattr; error = smb_proc_getattr(dentry, &fattr); - if (!error) - { + if (!error) { smb_renew_times(dentry); /* * Check whether the type part of the mode changed, * and don't update the attributes if it did. */ - if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) + if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) { smb_set_inode_attr(inode, &fattr); - else - { + } else { /* * Big trouble! The inode has become a new object, * so any operations attempted on it are invalid. @@ -212,18 +210,11 @@ struct smb_sb_info *s = server_from_dentry(dentry); struct inode *inode = dentry->d_inode; time_t last_time; + loff_t last_sz; int error = 0; DEBUG1("smb_revalidate_inode\n"); - /* - * If this is a file opened with write permissions, - * the inode will be up-to-date. - */ lock_kernel(); - if (S_ISREG(inode->i_mode) && smb_is_open(inode)) { - if (inode->u.smbfs_i.access != SMB_O_RDONLY) - goto out; - } /* * Check whether we've recently refreshed the inode. @@ -236,11 +227,13 @@ /* * Save the last modified time, then refresh the inode. - * (Note: a size change should have a different mtime.) + * (Note: a size change should have a different mtime, + * or same mtime but different size.) */ last_time = inode->i_mtime; + last_sz = inode->i_size; error = smb_refresh_inode(dentry); - if (error || inode->i_mtime != last_time) { + if (error || inode->i_mtime != last_time || inode->i_size != last_sz) { VERBOSE("%s/%s changed, old=%ld, new=%ld\n", DENTRY_PATH(dentry), (long) last_time, (long) inode->i_mtime); @@ -399,6 +392,7 @@ sb->s_magic = SMB_SUPER_MAGIC; sb->s_flags = 0; sb->s_op = &smb_sops; + sb->s_maxbytes = MAX_NON_LFS; /* client support missing */ sb->u.smbfs_sb.mnt = NULL; sb->u.smbfs_sb.sock_file = NULL; diff -u --recursive --new-file v2.4.2/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v2.4.2/linux/fs/smbfs/proc.c Wed Feb 21 18:20:40 2001 +++ linux/fs/smbfs/proc.c Tue Mar 6 19:14:59 2001 @@ -950,7 +950,10 @@ #if 0 /* FIXME: why is this code not in? below we fix it so that a caller wanting RO doesn't get RW. smb_revalidate_inode does some - optimization based on access mode. tail -f needs it to be correct. */ + optimization based on access mode. tail -f needs it to be correct. + + We must open rw since we don't do the open if called a second time + with different 'wish'. Is that not supported by smb servers? */ if (!(wish & (O_WRONLY | O_RDWR))) mode = read_only; #endif @@ -989,8 +992,6 @@ /* smb_vwv2 has mtime */ /* smb_vwv4 has size */ ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK); - if (!(wish & (O_WRONLY | O_RDWR))) - ino->u.smbfs_i.access = SMB_O_RDONLY; ino->u.smbfs_i.open = server->generation; out: @@ -1008,23 +1009,20 @@ int result; result = -ENOENT; - if (!inode) - { + if (!inode) { printk(KERN_ERR "smb_open: no inode for dentry %s/%s\n", DENTRY_PATH(dentry)); goto out; } - if (!smb_is_open(inode)) - { + if (!smb_is_open(inode)) { struct smb_sb_info *server = SMB_SERVER(inode); smb_lock_server(server); result = 0; if (!smb_is_open(inode)) result = smb_proc_open(server, dentry, wish); smb_unlock_server(server); - if (result) - { + if (result) { PARANOIA("%s/%s open failed, result=%d\n", DENTRY_PATH(dentry), result); goto out; diff -u --recursive --new-file v2.4.2/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.4.2/linux/fs/sysv/inode.c Mon Dec 4 19:00:09 2000 +++ linux/fs/sysv/inode.c Fri Mar 2 11:12:12 2001 @@ -365,6 +365,7 @@ panic("sysv fs: bad i-node size"); set_blocksize(dev,BLOCK_SIZE); sb->sv_block_base = 0; + sb->s_maxbytes = MAX_NON_LFS; /* Try to read Xenix superblock */ if ((bh = bread(dev, 1, BLOCK_SIZE)) != NULL) { diff -u --recursive --new-file v2.4.2/linux/fs/udf/super.c linux/fs/udf/super.c --- v2.4.2/linux/fs/udf/super.c Wed Feb 21 18:20:40 2001 +++ linux/fs/udf/super.c Fri Mar 2 11:12:12 2001 @@ -1415,7 +1415,7 @@ iput(inode); goto error_out; } - + sb->s_maxbytes = ~0ULL; return sb; error_out: diff -u --recursive --new-file v2.4.2/linux/fs/ufs/super.c linux/fs/ufs/super.c --- v2.4.2/linux/fs/ufs/super.c Wed Feb 21 18:20:40 2001 +++ linux/fs/ufs/super.c Fri Mar 2 11:12:12 2001 @@ -489,6 +489,12 @@ if (!uspi) goto failed; + /* Set a 2Gig file limit. Some UFS variants need to override + this but as I don't know which I'll let those in the know loosen + the rules */ + + sb->s_maxbytes = MAX_NON_LFS; + switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) { case UFS_MOUNT_UFSTYPE_44BSD: UFSD(("ufstype=44bsd\n")) diff -u --recursive --new-file v2.4.2/linux/fs/ufs/truncate.c linux/fs/ufs/truncate.c --- v2.4.2/linux/fs/ufs/truncate.c Tue Sep 5 14:07:30 2000 +++ linux/fs/ufs/truncate.c Tue Mar 6 19:44:37 2001 @@ -160,7 +160,7 @@ frag_to_free = tmp; free_count = uspi->s_fpb; } -next2: +next2:; } if (free_count > 0) @@ -261,7 +261,7 @@ } inode->i_blocks -= uspi->s_nspb; mark_inode_dirty(inode); -next: +next:; } if (free_count > 0) { diff -u --recursive --new-file v2.4.2/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c --- v2.4.2/linux/fs/umsdos/emd.c Wed Nov 8 19:01:34 2000 +++ linux/fs/umsdos/emd.c Tue Mar 6 19:44:37 2001 @@ -16,8 +16,7 @@ #include #include #include - -#include +#include static void copy_entry(struct umsdos_dirent *p, struct umsdos_dirent *q) { diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v2.4.2/linux/include/asm-alpha/io.h Wed Feb 21 18:20:41 2001 +++ linux/include/asm-alpha/io.h Fri Mar 2 11:12:07 2001 @@ -455,6 +455,23 @@ #define isa_memcpy_fromio(a,b,c) memcpy_fromio((a),__ioremap(b),(c)) #define isa_memcpy_toio(a,b,c) memcpy_toio(__ioremap(a),(b),(c)) +static inline int +isa_check_signature(unsigned long io_addr, const unsigned char *signature, + int length) +{ + int retval = 0; + do { + if (isa_readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } while (length); + retval = 1; +out: + return retval; +} + /* * The Alpha Jensen hardware for some rather strange reason puts diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h --- v2.4.2/linux/include/asm-alpha/machvec.h Thu Mar 2 11:35:17 2000 +++ linux/include/asm-alpha/machvec.h Fri Mar 2 11:12:07 2001 @@ -21,7 +21,7 @@ struct linux_hose_info; struct pci_dev; struct pci_ops; -struct pci_controler; +struct pci_controller; struct alpha_machine_vector { @@ -40,7 +40,7 @@ unsigned long min_io_address; unsigned long min_mem_address; - void (*mv_pci_tbi)(struct pci_controler *hose, + void (*mv_pci_tbi)(struct pci_controller *hose, dma_addr_t start, dma_addr_t end); unsigned int (*mv_inb)(unsigned long); diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/pci.h linux/include/asm-alpha/pci.h --- v2.4.2/linux/include/asm-alpha/pci.h Tue Jul 18 22:58:28 2000 +++ linux/include/asm-alpha/pci.h Fri Mar 2 11:12:07 2001 @@ -16,10 +16,10 @@ struct resource; struct pci_iommu_arena; -/* A controler. Used to manage multiple PCI busses. */ +/* A controller. Used to manage multiple PCI busses. */ -struct pci_controler { - struct pci_controler *next; +struct pci_controller { + struct pci_controller *next; struct pci_bus *bus; struct resource *io_space; struct resource *mem_space; diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h --- v2.4.2/linux/include/asm-alpha/semaphore.h Tue Nov 14 11:12:08 2000 +++ linux/include/asm-alpha/semaphore.h Fri Mar 2 11:12:07 2001 @@ -12,6 +12,7 @@ #include #include #include /* __builtin_expect */ +#include #define DEBUG_SEMAPHORE 0 #define DEBUG_RW_SEMAPHORE 0 diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h --- v2.4.2/linux/include/asm-alpha/smp.h Tue Jan 2 16:45:37 2001 +++ linux/include/asm-alpha/smp.h Fri Mar 2 11:30:15 2001 @@ -57,6 +57,7 @@ #define smp_processor_id() (current->processor) extern unsigned long cpu_present_mask; +#define cpu_online_map cpu_present_mask #endif /* CONFIG_SMP */ diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/bits.h linux/include/asm-arm/arch-integrator/bits.h --- v2.4.2/linux/include/asm-arm/arch-integrator/bits.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/bits.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,61 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* DO NOT EDIT!! - this file automatically generated + * from .s file by awk -f s2h.awk + */ +/* Bit field defintions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __bits_h +#define __bits_h 1 + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#endif + +/* END */ diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/dma.h linux/include/asm-arm/arch-integrator/dma.h --- v2.4.2/linux/include/asm-arm/arch-integrator/dma.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/dma.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,28 @@ +/* + * linux/include/asm-arm/arch-integrator/dma.h + * + * Copyright (C) 1997,1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H + +#define MAX_DMA_ADDRESS 0xffffffff + +#define MAX_DMA_CHANNELS 0 + +#endif /* _ASM_ARCH_DMA_H */ + diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/hardware.h linux/include/asm-arm/arch-integrator/hardware.h --- v2.4.2/linux/include/asm-arm/arch-integrator/hardware.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/hardware.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,57 @@ +/* + * linux/include/asm-arm/arch-integrator/hardware.h + * + * This file contains the hardware definitions of the Integrator. + * + * Copyright (C) 1999 ARM Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +/* + * Where in virtual memory the IO devices (timers, system controllers + * and so on) + */ +#define IO_BASE 0xF0000000 // VA of IO +#define IO_SIZE 0x0B000000 // How much? +#define IO_START INTEGRATOR_HDR_BASE // PA of IO + +/* + * Similar to above, but for PCI addresses (memory, IO, Config and the + * V3 chip itself). WARNING: this has to mirror definitions in platform.h + */ +#define PCI_MEMORY_VADDR 0xe8000000 +#define PCI_CONFIG_VADDR 0xec000000 +#define PCI_V3_VADDR 0xed000000 +#define PCI_IO_VADDR 0xee000000 + +#define PCIO_BASE PCI_IO_VADDR +#define PCIMEM_BASE PCI_MEMORY_VADDR + +/* macro to get at IO space when running virtually */ +#define IO_ADDRESS(x) (((x) >> 4) + IO_BASE) + +#define pcibios_assign_all_busses() 1 + +#define PCIBIOS_MIN_IO 0x6000 +#define PCIBIOS_MIN_MEM 0x00100000 + +#endif + diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/io.h linux/include/asm-arm/arch-integrator/io.h --- v2.4.2/linux/include/asm-arm/arch-integrator/io.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/io.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,46 @@ +/* + * linux/include/asm-arm/arch-integrator/io.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffff + +#define __io(a) (PCI_IO_VADDR + (a)) +#define __mem_pci(a) ((unsigned long)(a)) +#define __mem_isa(a) (PCI_MEMORY_VADDR + (unsigned long)(a)) + +/* + * Generic virtual read/write + */ +#define __arch_getw(a) (*(volatile unsigned short *)(a)) +#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) + +/* + * Validate the pci memory address for ioremap. + */ +#define iomem_valid_addr(iomem,size) \ + ((iomem) > 0 && (iomem) + (size) <= 0x20000000) + +/* + * Convert PCI memory space to a CPU physical address + */ +#define iomem_to_phys(iomem) ((iomem) + PHYS_PCI_MEM_BASE) + +#endif diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/irq.h linux/include/asm-arm/arch-integrator/irq.h --- v2.4.2/linux/include/asm-arm/arch-integrator/irq.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/irq.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,20 @@ +/* + * linux/include/asm-arm/arch-integrator/irq.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define fixup_irq(i) (i) diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/irqs.h linux/include/asm-arm/arch-integrator/irqs.h --- v2.4.2/linux/include/asm-arm/arch-integrator/irqs.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/irqs.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,134 @@ +/* + * linux/include/asm-arm/arch-integrator/irqs.h + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Use the integrator definitions */ +#include + +/* + * IRQ interrupts definitions are the same the INT definitions + * held within platform.h + */ +#define IRQ_SOFTINT INT_SOFTINT +#define IRQ_UARTINT0 INT_UARTINT0 +#define IRQ_UARTINT1 INT_UARTINT1 +#define IRQ_KMIINT0 INT_KMIINT0 +#define IRQ_KMIINT1 INT_KMIINT1 +#define IRQ_TIMERINT0 INT_TIMERINT0 +#define IRQ_TIMERINT1 INT_TIMERINT1 +#define IRQ_TIMERINT2 INT_TIMERINT2 +#define IRQ_RTCINT INT_RTCINT +#define IRQ_EXPINT0 INT_EXPINT0 +#define IRQ_EXPINT1 INT_EXPINT1 +#define IRQ_EXPINT2 INT_EXPINT2 +#define IRQ_EXPINT3 INT_EXPINT3 +#define IRQ_PCIINT0 INT_PCIINT0 +#define IRQ_PCIINT1 INT_PCIINT1 +#define IRQ_PCIINT2 INT_PCIINT2 +#define IRQ_PCIINT3 INT_PCIINT3 +#define IRQ_V3INT INT_V3INT +#define IRQ_CPINT0 INT_CPINT0 +#define IRQ_CPINT1 INT_CPINT1 +#define IRQ_LBUSTIMEOUT INT_LBUSTIMEOUT +#define IRQ_APCINT INT_APCINT + +#define IRQMASK_SOFTINT INTMASK_SOFTINT +#define IRQMASK_UARTINT0 INTMASK_UARTINT0 +#define IRQMASK_UARTINT1 INTMASK_UARTINT1 +#define IRQMASK_KMIINT0 INTMASK_KMIINT0 +#define IRQMASK_KMIINT1 INTMASK_KMIINT1 +#define IRQMASK_TIMERINT0 INTMASK_TIMERINT0 +#define IRQMASK_TIMERINT1 INTMASK_TIMERINT1 +#define IRQMASK_TIMERINT2 INTMASK_TIMERINT2 +#define IRQMASK_RTCINT INTMASK_RTCINT +#define IRQMASK_EXPINT0 INTMASK_EXPINT0 +#define IRQMASK_EXPINT1 INTMASK_EXPINT1 +#define IRQMASK_EXPINT2 INTMASK_EXPINT2 +#define IRQMASK_EXPINT3 INTMASK_EXPINT3 +#define IRQMASK_PCIINT0 INTMASK_PCIINT0 +#define IRQMASK_PCIINT1 INTMASK_PCIINT1 +#define IRQMASK_PCIINT2 INTMASK_PCIINT2 +#define IRQMASK_PCIINT3 INTMASK_PCIINT3 +#define IRQMASK_V3INT INTMASK_V3INT +#define IRQMASK_CPINT0 INTMASK_CPINT0 +#define IRQMASK_CPINT1 INTMASK_CPINT1 +#define IRQMASK_LBUSTIMEOUT INTMASK_LBUSTIMEOUT +#define IRQMASK_APCINT INTMASK_APCINT + +/* + * FIQ interrupts definitions are the same the INT definitions. + */ +#define FIQ_SOFTINT INT_SOFTINT +#define FIQ_UARTINT0 INT_UARTINT0 +#define FIQ_UARTINT1 INT_UARTINT1 +#define FIQ_KMIINT0 INT_KMIINT0 +#define FIQ_KMIINT1 INT_KMIINT1 +#define FIQ_TIMERINT0 INT_TIMERINT0 +#define FIQ_TIMERINT1 INT_TIMERINT1 +#define FIQ_TIMERINT2 INT_TIMERINT2 +#define FIQ_RTCINT INT_RTCINT +#define FIQ_EXPINT0 INT_EXPINT0 +#define FIQ_EXPINT1 INT_EXPINT1 +#define FIQ_EXPINT2 INT_EXPINT2 +#define FIQ_EXPINT3 INT_EXPINT3 +#define FIQ_PCIINT0 INT_PCIINT0 +#define FIQ_PCIINT1 INT_PCIINT1 +#define FIQ_PCIINT2 INT_PCIINT2 +#define FIQ_PCIINT3 INT_PCIINT3 +#define FIQ_V3INT INT_V3INT +#define FIQ_CPINT0 INT_CPINT0 +#define FIQ_CPINT1 INT_CPINT1 +#define FIQ_LBUSTIMEOUT INT_LBUSTIMEOUT +#define FIQ_APCINT INT_APCINT + +#define FIQMASK_SOFTINT INTMASK_SOFTINT +#define FIQMASK_UARTINT0 INTMASK_UARTINT0 +#define FIQMASK_UARTINT1 INTMASK_UARTINT1 +#define FIQMASK_KMIINT0 INTMASK_KMIINT0 +#define FIQMASK_KMIINT1 INTMASK_KMIINT1 +#define FIQMASK_TIMERINT0 INTMASK_TIMERINT0 +#define FIQMASK_TIMERINT1 INTMASK_TIMERINT1 +#define FIQMASK_TIMERINT2 INTMASK_TIMERINT2 +#define FIQMASK_RTCINT INTMASK_RTCINT +#define FIQMASK_EXPINT0 INTMASK_EXPINT0 +#define FIQMASK_EXPINT1 INTMASK_EXPINT1 +#define FIQMASK_EXPINT2 INTMASK_EXPINT2 +#define FIQMASK_EXPINT3 INTMASK_EXPINT3 +#define FIQMASK_PCIINT0 INTMASK_PCIINT0 +#define FIQMASK_PCIINT1 INTMASK_PCIINT1 +#define FIQMASK_PCIINT2 INTMASK_PCIINT2 +#define FIQMASK_PCIINT3 INTMASK_PCIINT3 +#define FIQMASK_V3INT INTMASK_V3INT +#define FIQMASK_CPINT0 INTMASK_CPINT0 +#define FIQMASK_CPINT1 INTMASK_CPINT1 +#define FIQMASK_LBUSTIMEOUT INTMASK_LBUSTIMEOUT +#define FIQMASK_APCINT INTMASK_APCINT + +/* + * Misc. interrupt definitions + */ +#define IRQ_KEYBDINT INT_KMIINT0 +#define IRQ_MOUSEINT INT_KMIINT1 + +#define IRQMASK_KEYBDINT INTMASK_KMIINT0 +#define IRQMASK_MOUSEINT INTMASK_KMIINT1 + +#define NR_IRQS (MAXIRQNUM + 1) + diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/keyboard.h linux/include/asm-arm/arch-integrator/keyboard.h --- v2.4.2/linux/include/asm-arm/arch-integrator/keyboard.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/keyboard.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,45 @@ +/* + * linux/include/asm-arm/arch-integrator/keyboard.h + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Keyboard driver definitions for the Integrator architecture + */ +#include + +#define NR_SCANCODES 128 + +extern unsigned char kmi_kbd_sysrq_xlate[NR_SCANCODES]; + +extern int kmi_kbd_setkeycode(u_int scancode, u_int keycode); +extern int kmi_kbd_getkeycode(u_int scancode); +extern int kmi_kbd_translate(u_char scancode, u_char *keycode, char raw_mode); +extern char kmi_kbd_unexpected_up(u_char keycode); +extern void kmi_kbd_leds(u_char leds); +extern int kmi_kbd_init(void); + +#define kbd_setkeycode(sc,kc) kmi_kbd_setkeycode(sc,kc) +#define kbd_getkeycode(sc) kmi_kbd_getkeycode(sc) + +#define kbd_translate(sc, kcp, rm) kmi_kbd_translate(sc,kcp,rm) +#define kbd_unexpected_up(kc) kmi_kbd_unexpected_up(kc) +#define kbd_leds(leds) kmi_kbd_leds(leds) +#define kbd_init_hw() kmi_kbd_init() +#define kbd_sysrq_xlate kmi_kbd_sysrq_xlate +#define kbd_disable_irq() disable_irq(IRQ_KMIINT0) +#define kbd_enable_irq() enable_irq(IRQ_KMIINT0) + +#define SYSRQ_KEY 0x54 diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/memory.h linux/include/asm-arm/arch-integrator/memory.h --- v2.4.2/linux/include/asm-arm/arch-integrator/memory.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/memory.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,61 @@ +/* + * linux/include/asm-arm/arch-integrator/mmu.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_MMU_H +#define __ASM_ARCH_MMU_H + +/* + * Task size: 3GB + */ +#define TASK_SIZE (0xc0000000UL) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +/* + * Page offset: 3GB + */ +#define PAGE_OFFSET (0xc0000000UL) +#define PHYS_OFFSET (0x00000000UL) + +/* + * On integrator, the dram is contiguous + */ +#define __virt_to_phys__is_a_macro +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET) +#define __phys_to_virt__is_a_macro +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET) + +/* + * Virtual view <-> DMA view memory address translations + * virt_to_bus: Used to translate the virtual address to an + * address suitable to be passed to set_dma_addr + * bus_to_virt: Used to convert an address for DMA operations + * to an address that the kernel can use. + */ +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) (x - PAGE_OFFSET + INTEGRATOR_HDR0_SDRAM_BASE) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) (x - INTEGRATOR_HDR0_SDRAM_BASE + PAGE_OFFSET) + +#endif diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/param.h linux/include/asm-arm/arch-integrator/param.h --- v2.4.2/linux/include/asm-arm/arch-integrator/param.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/param.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,21 @@ +/* + * linux/include/asm-arm/arch-integrator/param.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define HZ 100 diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/platform.h linux/include/asm-arm/arch-integrator/platform.h --- v2.4.2/linux/include/asm-arm/arch-integrator/platform.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/platform.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,544 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* DO NOT EDIT!! - this file automatically generated + * from .s file by awk -f s2h.awk + */ +/************************************************************************** + * * Copyright İ ARM Limited 1998. All rights reserved. + * ***********************************************************************/ +/* ************************************************************************ + * + * Integrator address map + * + * NOTE: This is a multi-hosted header file for use with uHAL and + * supported debuggers. + * + * $Id: platform.s,v 1.32 2000/02/18 10:51:39 asims Exp $ + * + * ***********************************************************************/ + +#ifndef __address_h +#define __address_h 1 + +/* ======================================================================== + * Integrator definitions + * ======================================================================== + * ------------------------------------------------------------------------ + * Memory definitions + * ------------------------------------------------------------------------ + * Integrator memory map + * + */ +#define INTEGRATOR_BOOT_ROM_LO 0x00000000 +#define INTEGRATOR_BOOT_ROM_HI 0x20000000 +#define INTEGRATOR_BOOT_ROM_BASE INTEGRATOR_BOOT_ROM_HI /* Normal position */ +#define INTEGRATOR_BOOT_ROM_SIZE SZ_512K + +/* + * New Core Modules have different amounts of SSRAM, the amount of SSRAM + * fitted can be found in HDR_STAT. + * + * The symbol INTEGRATOR_SSRAM_SIZE is kept, however this now refers to + * the minimum amount of SSRAM fitted on any core module. + * + * New Core Modules also alias the SSRAM. + * + */ +#define INTEGRATOR_SSRAM_BASE 0x00000000 +#define INTEGRATOR_SSRAM_ALIAS_BASE 0x10800000 +#define INTEGRATOR_SSRAM_SIZE SZ_256K + +#define INTEGRATOR_FLASH_BASE 0x24000000 +#define INTEGRATOR_FLASH_SIZE SZ_32M + +#define INTEGRATOR_MBRD_SSRAM_BASE 0x28000000 +#define INTEGRATOR_MBRD_SSRAM_SIZE SZ_512K + +/* + * SDRAM is a SIMM therefore the size is not known. + * + */ +#define INTEGRATOR_SDRAM_BASE 0x00040000 + +#define INTEGRATOR_SDRAM_ALIAS_BASE 0x80000000 +#define INTEGRATOR_HDR0_SDRAM_BASE 0x80000000 +#define INTEGRATOR_HDR1_SDRAM_BASE 0x90000000 +#define INTEGRATOR_HDR2_SDRAM_BASE 0xA0000000 +#define INTEGRATOR_HDR3_SDRAM_BASE 0xB0000000 + +/* + * Logic expansion modules + * + */ +#define INTEGRATOR_LOGIC_MODULES_BASE 0xC0000000 +#define INTEGRATOR_LOGIC_MODULE0_BASE 0xC0000000 +#define INTEGRATOR_LOGIC_MODULE1_BASE 0xD0000000 +#define INTEGRATOR_LOGIC_MODULE2_BASE 0xE0000000 +#define INTEGRATOR_LOGIC_MODULE3_BASE 0xF0000000 + +/* ------------------------------------------------------------------------ + * Integrator header card registers + * ------------------------------------------------------------------------ + * + */ +#define INTEGRATOR_HDR_ID_OFFSET 0x00 +#define INTEGRATOR_HDR_PROC_OFFSET 0x04 +#define INTEGRATOR_HDR_OSC_OFFSET 0x08 +#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C +#define INTEGRATOR_HDR_STAT_OFFSET 0x10 +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 +#define INTEGRATOR_HDR_SDRAM_OFFSET 0x20 +#define INTEGRATOR_HDR_INIT_OFFSET 0x24 /* CM9x6 */ +#define INTEGRATOR_HDR_IC_OFFSET 0x40 +#define INTEGRATOR_HDR_SPDBASE_OFFSET 0x100 +#define INTEGRATOR_HDR_SPDTOP_OFFSET 0x200 + +#define INTEGRATOR_HDR_BASE 0x10000000 +#define INTEGRATOR_HDR_ID (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_ID_OFFSET) +#define INTEGRATOR_HDR_PROC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_PROC_OFFSET) +#define INTEGRATOR_HDR_OSC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_OSC_OFFSET) +#define INTEGRATOR_HDR_CTRL (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_CTRL_OFFSET) +#define INTEGRATOR_HDR_STAT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_STAT_OFFSET) +#define INTEGRATOR_HDR_LOCK (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_LOCK_OFFSET) +#define INTEGRATOR_HDR_SDRAM (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SDRAM_OFFSET) +#define INTEGRATOR_HDR_INIT (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_INIT_OFFSET) +#define INTEGRATOR_HDR_IC (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_IC_OFFSET) +#define INTEGRATOR_HDR_SPDBASE (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDBASE_OFFSET) +#define INTEGRATOR_HDR_SPDTOP (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDTOP_OFFSET) + +#define INTEGRATOR_HDR_CTRL_LED 0x01 +#define INTEGRATOR_HDR_CTRL_MBRD_DETECH 0x02 +#define INTEGRATOR_HDR_CTRL_REMAP 0x04 +#define INTEGRATOR_HDR_CTRL_RESET 0x08 +#define INTEGRATOR_HDR_CTRL_HIGHVECTORS 0x10 +#define INTEGRATOR_HDR_CTRL_BIG_ENDIAN 0x20 +#define INTEGRATOR_HDR_CTRL_FASTBUS 0x40 +#define INTEGRATOR_HDR_CTRL_SYNC 0x80 + +#define INTEGRATOR_HDR_OSC_CORE_10MHz 0x102 +#define INTEGRATOR_HDR_OSC_CORE_15MHz 0x107 +#define INTEGRATOR_HDR_OSC_CORE_20MHz 0x10C +#define INTEGRATOR_HDR_OSC_CORE_25MHz 0x111 +#define INTEGRATOR_HDR_OSC_CORE_30MHz 0x116 +#define INTEGRATOR_HDR_OSC_CORE_35MHz 0x11B +#define INTEGRATOR_HDR_OSC_CORE_40MHz 0x120 +#define INTEGRATOR_HDR_OSC_CORE_45MHz 0x125 +#define INTEGRATOR_HDR_OSC_CORE_50MHz 0x12A +#define INTEGRATOR_HDR_OSC_CORE_55MHz 0x12F +#define INTEGRATOR_HDR_OSC_CORE_60MHz 0x134 +#define INTEGRATOR_HDR_OSC_CORE_65MHz 0x139 +#define INTEGRATOR_HDR_OSC_CORE_70MHz 0x13E +#define INTEGRATOR_HDR_OSC_CORE_75MHz 0x143 +#define INTEGRATOR_HDR_OSC_CORE_80MHz 0x148 +#define INTEGRATOR_HDR_OSC_CORE_85MHz 0x14D +#define INTEGRATOR_HDR_OSC_CORE_90MHz 0x152 +#define INTEGRATOR_HDR_OSC_CORE_95MHz 0x157 +#define INTEGRATOR_HDR_OSC_CORE_100MHz 0x15C +#define INTEGRATOR_HDR_OSC_CORE_105MHz 0x161 +#define INTEGRATOR_HDR_OSC_CORE_110MHz 0x166 +#define INTEGRATOR_HDR_OSC_CORE_115MHz 0x16B +#define INTEGRATOR_HDR_OSC_CORE_120MHz 0x170 +#define INTEGRATOR_HDR_OSC_CORE_125MHz 0x175 +#define INTEGRATOR_HDR_OSC_CORE_130MHz 0x17A +#define INTEGRATOR_HDR_OSC_CORE_135MHz 0x17F +#define INTEGRATOR_HDR_OSC_CORE_140MHz 0x184 +#define INTEGRATOR_HDR_OSC_CORE_145MHz 0x189 +#define INTEGRATOR_HDR_OSC_CORE_150MHz 0x18E +#define INTEGRATOR_HDR_OSC_CORE_155MHz 0x193 +#define INTEGRATOR_HDR_OSC_CORE_160MHz 0x198 +#define INTEGRATOR_HDR_OSC_CORE_MASK 0x7FF + +#define INTEGRATOR_HDR_OSC_MEM_10MHz 0x10C000 +#define INTEGRATOR_HDR_OSC_MEM_15MHz 0x116000 +#define INTEGRATOR_HDR_OSC_MEM_20MHz 0x120000 +#define INTEGRATOR_HDR_OSC_MEM_25MHz 0x12A000 +#define INTEGRATOR_HDR_OSC_MEM_30MHz 0x134000 +#define INTEGRATOR_HDR_OSC_MEM_33MHz 0x13A000 +#define INTEGRATOR_HDR_OSC_MEM_40MHz 0x148000 +#define INTEGRATOR_HDR_OSC_MEM_50MHz 0x15C000 +#define INTEGRATOR_HDR_OSC_MEM_60MHz 0x170000 +#define INTEGRATOR_HDR_OSC_MEM_66MHz 0x17C000 +#define INTEGRATOR_HDR_OSC_MEM_MASK 0x7FF000 + +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM7x0 0x0 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x0 0x0800000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x6 0x1000000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_CM10x00 0x1800000 +#define INTEGRATOR_HDR_OSC_BUS_MODE_MASK 0x1800000 + +#define INTEGRATOR_HDR_SDRAM_SPD_OK (1 << 5) + + +/* ------------------------------------------------------------------------ + * Integrator system registers + * ------------------------------------------------------------------------ + * + */ + +/* + * System Controller + * + */ +#define INTEGRATOR_SC_ID_OFFSET 0x00 +#define INTEGRATOR_SC_OSC_OFFSET 0x04 +#define INTEGRATOR_SC_CTRLS_OFFSET 0x08 +#define INTEGRATOR_SC_CTRLC_OFFSET 0x0C +#define INTEGRATOR_SC_DEC_OFFSET 0x10 +#define INTEGRATOR_SC_ARB_OFFSET 0x14 +#define INTEGRATOR_SC_PCIENABLE_OFFSET 0x18 +#define INTEGRATOR_SC_LOCK_OFFSET 0x1C + +#define INTEGRATOR_SC_BASE 0x11000000 +#define INTEGRATOR_SC_ID (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ID_OFFSET) +#define INTEGRATOR_SC_OSC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_OSC_OFFSET) +#define INTEGRATOR_SC_CTRLS (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET) +#define INTEGRATOR_SC_CTRLC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET) +#define INTEGRATOR_SC_DEC (INTEGRATOR_SC_BASE + INTEGRATOR_SC_DEC_OFFSET) +#define INTEGRATOR_SC_ARB (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ARB_OFFSET) +#define INTEGRATOR_SC_PCIENABLE (INTEGRATOR_SC_BASE + INTEGRATOR_SC_PCIENABLE_OFFSET) +#define INTEGRATOR_SC_LOCK (INTEGRATOR_SC_BASE + INTEGRATOR_SC_LOCK_OFFSET) + +#define INTEGRATOR_SC_OSC_SYS_10MHz 0x20 +#define INTEGRATOR_SC_OSC_SYS_15MHz 0x34 +#define INTEGRATOR_SC_OSC_SYS_20MHz 0x48 +#define INTEGRATOR_SC_OSC_SYS_25MHz 0x5C +#define INTEGRATOR_SC_OSC_SYS_33MHz 0x7C +#define INTEGRATOR_SC_OSC_SYS_MASK 0xFF + +#define INTEGRATOR_SC_OSC_PCI_25MHz 0x100 +#define INTEGRATOR_SC_OSC_PCI_33MHz 0x0 +#define INTEGRATOR_SC_OSC_PCI_MASK 0x100 + +#define INTEGRATOR_SC_CTRL_SOFTRST (1 << 0) +#define INTEGRATOR_SC_CTRL_nFLVPPEN (1 << 1) +#define INTEGRATOR_SC_CTRL_nFLWP (1 << 2) +#define INTEGRATOR_SC_CTRL_URTS0 (1 << 4) +#define INTEGRATOR_SC_CTRL_UDTR0 (1 << 5) +#define INTEGRATOR_SC_CTRL_URTS1 (1 << 6) +#define INTEGRATOR_SC_CTRL_UDTR1 (1 << 7) + +/* + * External Bus Interface + * + */ +#define INTEGRATOR_EBI_BASE 0x12000000 + +#define INTEGRATOR_EBI_CSR0_OFFSET 0x00 +#define INTEGRATOR_EBI_CSR1_OFFSET 0x04 +#define INTEGRATOR_EBI_CSR2_OFFSET 0x08 +#define INTEGRATOR_EBI_CSR3_OFFSET 0x0C +#define INTEGRATOR_EBI_LOCK_OFFSET 0x20 + +#define INTEGRATOR_EBI_CSR0 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR0_OFFSET) +#define INTEGRATOR_EBI_CSR1 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET) +#define INTEGRATOR_EBI_CSR2 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR2_OFFSET) +#define INTEGRATOR_EBI_CSR3 (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR3_OFFSET) +#define INTEGRATOR_EBI_LOCK (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET) + +#define INTEGRATOR_EBI_8_BIT 0x00 +#define INTEGRATOR_EBI_16_BIT 0x01 +#define INTEGRATOR_EBI_32_BIT 0x02 +#define INTEGRATOR_EBI_WRITE_ENABLE 0x04 +#define INTEGRATOR_EBI_SYNC 0x08 +#define INTEGRATOR_EBI_WS_2 0x00 +#define INTEGRATOR_EBI_WS_3 0x10 +#define INTEGRATOR_EBI_WS_4 0x20 +#define INTEGRATOR_EBI_WS_5 0x30 +#define INTEGRATOR_EBI_WS_6 0x40 +#define INTEGRATOR_EBI_WS_7 0x50 +#define INTEGRATOR_EBI_WS_8 0x60 +#define INTEGRATOR_EBI_WS_9 0x70 +#define INTEGRATOR_EBI_WS_10 0x80 +#define INTEGRATOR_EBI_WS_11 0x90 +#define INTEGRATOR_EBI_WS_12 0xA0 +#define INTEGRATOR_EBI_WS_13 0xB0 +#define INTEGRATOR_EBI_WS_14 0xC0 +#define INTEGRATOR_EBI_WS_15 0xD0 +#define INTEGRATOR_EBI_WS_16 0xE0 +#define INTEGRATOR_EBI_WS_17 0xF0 + + +#define INTEGRATOR_CT_BASE 0x13000000 /* Counter/Timers */ +#define INTEGRATOR_IC_BASE 0x14000000 /* Interrupt Controller */ +#define INTEGRATOR_RTC_BASE 0x15000000 /* Real Time Clock */ +#define INTEGRATOR_UART0_BASE 0x16000000 /* UART 0 */ +#define INTEGRATOR_UART1_BASE 0x17000000 /* UART 1 */ +#define INTEGRATOR_KBD_BASE 0x18000000 /* Keyboard */ +#define INTEGRATOR_MOUSE_BASE 0x19000000 /* Mouse */ + +/* + * LED's & Switches + * + */ +#define INTEGRATOR_DBG_ALPHA_OFFSET 0x00 +#define INTEGRATOR_DBG_LEDS_OFFSET 0x04 +#define INTEGRATOR_DBG_SWITCH_OFFSET 0x08 + +#define INTEGRATOR_DBG_BASE 0x1A000000 +#define INTEGRATOR_DBG_ALPHA (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_ALPHA_OFFSET) +#define INTEGRATOR_DBG_LEDS (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_LEDS_OFFSET) +#define INTEGRATOR_DBG_SWITCH (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_SWITCH_OFFSET) + + +#define INTEGRATOR_GPIO_BASE 0x1B000000 /* GPIO */ + +/* ------------------------------------------------------------------------ + * KMI keyboard/mouse definitions + * ------------------------------------------------------------------------ + */ +/* PS2 Keyboard interface */ +#define KMI0_BASE INTEGRATOR_KBD_BASE + +/* PS2 Mouse interface */ +#define KMI1_BASE INTEGRATOR_MOUSE_BASE + +/* KMI definitions are now in include/asm-arm/hardware/amba_kmi.h -- rmk */ + +/* ------------------------------------------------------------------------ + * Where in the memory map does PCI live? + * ------------------------------------------------------------------------ + * This represents a fairly liberal usage of address space. Even though + * the V3 only has two windows (therefore we need to map stuff on the fly), + * we maintain the same addresses, even if they're not mapped. + * + */ +#define PHYS_PCI_MEM_BASE 0x40000000 /* 512M to xxx */ +/* unused 256M from A0000000-AFFFFFFF might be used for I2O ??? + */ +#define PHYS_PCI_IO_BASE 0x60000000 /* 16M to xxx */ +/* unused (128-16)M from B1000000-B7FFFFFF + */ +#define PHYS_PCI_CONFIG_BASE 0x61000000 /* 16M to xxx */ +/* unused ((128-16)M - 64K) from XXX + */ +#define PHYS_PCI_V3_BASE 0x62000000 + +#define PCI_DRAMSIZE INTEGRATOR_SSRAM_SIZE + +/* 'export' these to UHAL */ +#define UHAL_PCI_IO PCI_IO_BASE +#define UHAL_PCI_MEM PCI_MEM_BASE +#define UHAL_PCI_ALLOC_IO_BASE 0x00004000 +#define UHAL_PCI_ALLOC_MEM_BASE PCI_MEM_BASE +#define UHAL_PCI_MAX_SLOT 20 + +/* ======================================================================== + * Start of uHAL definitions + * ======================================================================== + */ + +/* ------------------------------------------------------------------------ + * Integrator Interrupt Controllers + * ------------------------------------------------------------------------ + * + * Offsets from interrupt controller base + * + * System Controller interrupt controller base is + * + * INTEGRATOR_IC_BASE + (header_number << 6) + * + * Core Module interrupt controller base is + * + * INTEGRATOR_HDR_IC + * + */ +#define IRQ_STATUS 0 +#define IRQ_RAW_STATUS 0x04 +#define IRQ_ENABLE 0x08 +#define IRQ_ENABLE_SET 0x08 +#define IRQ_ENABLE_CLEAR 0x0C + +#define INT_SOFT_SET 0x10 +#define INT_SOFT_CLEAR 0x14 + +#define FIQ_STATUS 0x20 +#define FIQ_RAW_STATUS 0x24 +#define FIQ_ENABLE 0x28 +#define FIQ_ENABLE_SET 0x28 +#define FIQ_ENABLE_CLEAR 0x2C + + +/* ------------------------------------------------------------------------ + * Interrupts + * ------------------------------------------------------------------------ + * + * + * Each Core Module has two interrupts controllers, one on the core module + * itself and one in the system controller on the motherboard. The + * READ_INT macro in target.s reads both interrupt controllers and returns + * a 32 bit bitmask, bits 0 to 23 are interrupts from the system controller + * and bits 24 to 31 are from the core module. + * + * The following definitions relate to the bitmask returned by READ_INT. + * + */ + +/* + * As the interrupt bit definitions for FIQ/IRQ there is a common + * set of definitions prefixed INT/INTMASK. The FIQ/IRQ definitions + * have been left to maintain backwards compatible. + * + */ + +/* + * Interrupt numbers + * + */ +#define INT_SOFTINT 0 +#define INT_UARTINT0 1 +#define INT_UARTINT1 2 +#define INT_KMIINT0 3 +#define INT_KMIINT1 4 +#define INT_TIMERINT0 5 +#define INT_TIMERINT1 6 +#define INT_TIMERINT2 7 +#define INT_RTCINT 8 +#define INT_EXPINT0 9 +#define INT_EXPINT1 10 +#define INT_EXPINT2 11 +#define INT_EXPINT3 12 +#define INT_PCIINT0 13 +#define INT_PCIINT1 14 +#define INT_PCIINT2 15 +#define INT_PCIINT3 16 +#define INT_V3INT 17 +#define INT_CPINT0 18 +#define INT_CPINT1 19 +#define INT_LBUSTIMEOUT 20 +#define INT_APCINT 21 +#define INT_CM_SOFTINT 24 +#define INT_CM_COMMRX 25 +#define INT_CM_COMMTX 26 + +/* + * Interrupt bit positions + * + */ +#define INTMASK_SOFTINT (1 << INT_SOFTINT) +#define INTMASK_UARTINT0 (1 << INT_UARTINT0) +#define INTMASK_UARTINT1 (1 << INT_UARTINT1) +#define INTMASK_KMIINT0 (1 << INT_KMIINT0) +#define INTMASK_KMIINT1 (1 << INT_KMIINT1) +#define INTMASK_TIMERINT0 (1 << INT_TIMERINT0) +#define INTMASK_TIMERINT1 (1 << INT_TIMERINT1) +#define INTMASK_TIMERINT2 (1 << INT_TIMERINT2) +#define INTMASK_RTCINT (1 << INT_RTCINT) +#define INTMASK_EXPINT0 (1 << INT_EXPINT0) +#define INTMASK_EXPINT1 (1 << INT_EXPINT1) +#define INTMASK_EXPINT2 (1 << INT_EXPINT2) +#define INTMASK_EXPINT3 (1 << INT_EXPINT3) +#define INTMASK_PCIINT0 (1 << INT_PCIINT0) +#define INTMASK_PCIINT1 (1 << INT_PCIINT1) +#define INTMASK_PCIINT2 (1 << INT_PCIINT2) +#define INTMASK_PCIINT3 (1 << INT_PCIINT3) +#define INTMASK_V3INT (1 << INT_V3INT) +#define INTMASK_CPINT0 (1 << INT_CPINT0) +#define INTMASK_CPINT1 (1 << INT_CPINT1) +#define INTMASK_LBUSTIMEOUT (1 << INT_LBUSTIMEOUT) +#define INTMASK_APCINT (1 << INT_APCINT) +#define INTMASK_CM_SOFTINT (1 << INT_CM_SOFTINT) +#define INTMASK_CM_COMMRX (1 << INT_CM_COMMRX) +#define INTMASK_CM_COMMTX (1 << INT_CM_COMMTX) + +/* + * INTEGRATOR_CM_INT0 - Interrupt number of first CM interrupt + * INTEGRATOR_SC_VALID_INT - Mask of valid system controller interrupts + * + */ +#define INTEGRATOR_CM_INT0 INT_CM_SOFTINT +#define INTEGRATOR_SC_VALID_INT 0x003FFFFF + +#define MAXIRQNUM 31 +#define MAXFIQNUM 31 +#define MAXSWINUM 31 + +/* ------------------------------------------------------------------------ + * LED's - The header LED is not accessable via the uHAL API + * ------------------------------------------------------------------------ + * + */ +#define GREEN_LED 0x01 +#define YELLOW_LED 0x02 +#define RED_LED 0x04 +#define GREEN_LED_2 0x08 +#define ALL_LEDS 0x0F + +#define LED_BANK INTEGRATOR_DBG_LEDS + +/* + * Memory definitions - run uHAL out of SSRAM. + * + */ +#define uHAL_MEMORY_SIZE INTEGRATOR_SSRAM_SIZE + +/* + * Application Flash + * + */ +#define FLASH_BASE INTEGRATOR_FLASH_BASE +#define FLASH_SIZE INTEGRATOR_FLASH_SIZE +#define FLASH_END (FLASH_BASE + FLASH_SIZE - 1) +#define FLASH_BLOCK_SIZE SZ_128K + +/* + * Boot Flash + * + */ +#define EPROM_BASE INTEGRATOR_BOOT_ROM_HI +#define EPROM_SIZE INTEGRATOR_BOOT_ROM_SIZE +#define EPROM_END (EPROM_BASE + EPROM_SIZE - 1) + +/* + * Clean base - dummy + * + */ +#define CLEAN_BASE EPROM_BASE + +/* + * Timer definitions + * + * Only use timer 1 & 2 + * (both run at 24MHz and will need the clock divider set to 16). + * + * Timer 0 runs at bus frequency and therefore could vary and currently + * uHAL can't handle that. + * + */ + +#define INTEGRATOR_TIMER0_BASE INTEGRATOR_CT_BASE +#define INTEGRATOR_TIMER1_BASE (INTEGRATOR_CT_BASE + 0x100) +#define INTEGRATOR_TIMER2_BASE (INTEGRATOR_CT_BASE + 0x200) + +#define MAX_TIMER 2 +#define MAX_PERIOD 699050 +#define TICKS_PER_uSEC 24 + +/* + * These are useconds NOT ticks. + * + */ +#define mSEC_1 1000 +#define mSEC_5 (mSEC_1 * 5) +#define mSEC_10 (mSEC_1 * 10) +#define mSEC_25 (mSEC_1 * 25) +#define SEC_1 (mSEC_1 * 1000) + +#define INTEGRATOR_CSR_BASE 0x10000000 +#define INTEGRATOR_CSR_SIZE 0x10000000 + +#endif + +/* END */ diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/serial.h linux/include/asm-arm/arch-integrator/serial.h --- v2.4.2/linux/include/asm-arm/arch-integrator/serial.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/serial.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/arch-integrator/serial.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_SERIAL_H +#define __ASM_ARCH_SERIAL_H + +#include +#include + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD (1843200 / 16) + +#define _SER_IRQ0 IRQ_UARTINT0 +#define _SER_IRQ1 IRQ_UARTINT1 + +#define RS_TABLE_SIZE 2 + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + + /* UART CLK PORT IRQ FLAGS */ +#define STD_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, 0x3F8, _SER_IRQ0, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x2F8, _SER_IRQ1, STD_COM_FLAGS }, /* ttyS1 */ + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/sizes.h linux/include/asm-arm/arch-integrator/sizes.h --- v2.4.2/linux/include/asm-arm/arch-integrator/sizes.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/sizes.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,52 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* DO NOT EDIT!! - this file automatically generated + * from .s file by awk -f s2h.awk + */ +/* Size defintions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __sizes_h +#define __sizes_h 1 + +/* handy sizes */ +#define SZ_1K 0x00000400 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + +#endif + +/* END */ diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/system.h linux/include/asm-arm/arch-integrator/system.h --- v2.4.2/linux/include/asm-arm/arch-integrator/system.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/system.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm/arch-integrator/system.h + * + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +#include + +static void arch_idle(void) +{ + /* + * This should do all the clock switching + * and wait for interrupt tricks + */ + cpu_do_idle(0); +} + +extern __inline__ void arch_reset(char mode) +{ + unsigned int hdr_ctrl = (IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET); + unsigned int val; + + /* + * To reset, we hit the on-board reset register + * in the system FPGA + */ + val = __raw_readl(hdr_ctrl); + val |= INTEGRATOR_HDR_CTRL_RESET; + __raw_writel(val, hdr_ctrl); +} + +#endif diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/time.h linux/include/asm-arm/arch-integrator/time.h --- v2.4.2/linux/include/asm-arm/arch-integrator/time.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/time.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,140 @@ +/* + * linux/include/asm-arm/arch-integrator/time.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +/* + * Where is the timer (VA)? + */ +#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000) +#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100) +#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200) +#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) + +/* + * How long is the timer interval? + */ +#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) +#if TIMER_INTERVAL >= 0x100000 +#define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */ +#define TIMER_CTRL 0x88 /* Enable, Clock / 256 */ +#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) +#elif TIMER_INTERVAL >= 0x10000 +#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ +#define TIMER_CTRL 0x84 /* Enable, Clock / 16 */ +#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) +#else +#define TIMER_RELOAD (TIMER_INTERVAL) +#define TIMER_CTRL 0x80 /* Enable */ +#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) +#endif + +/* + * What does it look like? + */ +typedef struct TimerStruct { + unsigned long TimerLoad; + unsigned long TimerValue; + unsigned long TimerControl; + unsigned long TimerClear; +} TimerStruct_t; + +extern unsigned long (*gettimeoffset)(void); + +/* + * Returns number of ms since last clock interrupt. Note that interrupts + * will have been disabled by do_gettimeoffset() + */ +static unsigned long integrator_gettimeoffset(void) +{ + volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE; + unsigned long ticks1, ticks2, status; + + /* + * Get the current number of ticks. Note that there is a race + * condition between us reading the timer and checking for + * an interrupt. We get around this by ensuring that the + * counter has not reloaded between our two reads. + */ + ticks2 = timer1->TimerValue & 0xffff; + do { + ticks1 = ticks2; + status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS); + ticks2 = timer1->TimerValue & 0xffff; + } while (ticks2 > ticks1); + + /* + * Number of ticks since last interrupt. + */ + ticks1 = TIMER_RELOAD - ticks2; + + /* + * Interrupt pending? If so, we've reloaded once already. + */ + if (status & IRQMASK_TIMERINT1) + ticks1 += TIMER_RELOAD; + + /* + * Convert the ticks to usecs + */ + return TICKS2USECS(ticks1); +} + +/* + * IRQ handler for the timer + */ +static void integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + + // ...clear the interrupt + timer1->TimerClear = 1; + + do_leds(); + do_timer(regs); + do_profile(regs); +} + +/* + * Set up timer interrupt, and return the current time in seconds. + */ +extern __inline__ void setup_timer(void) +{ + volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; + volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; + volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; + + timer_irq.handler = integrator_timer_interrupt; + + /* + * Initialise to a known state (all timers off) + */ + timer0->TimerControl = 0; + timer1->TimerControl = 0; + timer2->TimerControl = 0; + + timer1->TimerLoad = TIMER_RELOAD; + timer1->TimerValue = TIMER_RELOAD; + timer1->TimerControl = TIMER_CTRL | 0x40; /* periodic */ + + /* + * Make irqs happen for the system timer + */ + setup_arm_irq(IRQ_TIMERINT1, &timer_irq); + gettimeoffset = integrator_gettimeoffset; +} diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/timex.h linux/include/asm-arm/arch-integrator/timex.h --- v2.4.2/linux/include/asm-arm/arch-integrator/timex.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/timex.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,26 @@ +/* + * linux/include/asm-arm/arch-integrator/timex.h + * + * Integrator architecture timex specifications + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * ?? + */ +#define CLOCK_TICK_RATE (50000000 / 16) diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/uncompress.h linux/include/asm-arm/arch-integrator/uncompress.h --- v2.4.2/linux/include/asm-arm/arch-integrator/uncompress.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/uncompress.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,53 @@ +/* + * linux/include/asm-arm/arch-integrator/uncompress.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define AMBA_UART_DR (*(volatile unsigned char *)0x16000000) +#define AMBA_UART_LCRH (*(volatile unsigned char *)0x16000008) +#define AMBA_UART_LCRM (*(volatile unsigned char *)0x1600000c) +#define AMBA_UART_LCRL (*(volatile unsigned char *)0x16000010) +#define AMBA_UART_CR (*(volatile unsigned char *)0x16000014) +#define AMBA_UART_FR (*(volatile unsigned char *)0x16000018) + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) { + while (AMBA_UART_FR & (1 << 5)); + + AMBA_UART_DR = *s; + + if (*s == '\n') { + while (AMBA_UART_FR & (1 << 5)); + + AMBA_UART_DR = '\r'; + } + s++; + } + while (AMBA_UART_FR & (1 << 3)); +} + +/* + * nothing to do + */ +#define arch_decomp_setup() + +#define arch_decomp_wdog() diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/vmalloc.h linux/include/asm-arm/arch-integrator/vmalloc.h --- v2.4.2/linux/include/asm-arm/arch-integrator/vmalloc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-integrator/vmalloc.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,32 @@ +/* + * linux/include/asm-arm/arch-integrator/vmalloc.h + * + * Copyright (C) 2000 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-sa1100/irq.h linux/include/asm-arm/arch-sa1100/irq.h --- v2.4.2/linux/include/asm-arm/arch-sa1100/irq.h Wed Feb 21 18:20:41 2001 +++ linux/include/asm-arm/arch-sa1100/irq.h Fri Mar 2 11:12:06 2001 @@ -134,7 +134,7 @@ int mask = (1 << GPIO_11_27_IRQ(irq)); if (GPIO_11_27_spurious & mask) { /* - * We don't want to miss an interrupt that would have occured + * We don't want to miss an interrupt that would have occurred * while it was masked. Simulate it if it is the case. */ int state = GPLR; diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/hardware/amba_kmi.h linux/include/asm-arm/hardware/amba_kmi.h --- v2.4.2/linux/include/asm-arm/hardware/amba_kmi.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/amba_kmi.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,92 @@ +/* + * linux/include/asm-arm/hardware/amba_kmi.h + * + * Internal header file for AMBA KMI ports + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * --------------------------------------------------------------------------- + * From ARM PrimeCell(tm) PS2 Keyboard/Mouse Interface (PL050) Technical + * Reference Manual - ARM DDI 0143B - see http://www.arm.com/ + * --------------------------------------------------------------------------- + */ +#ifndef ASM_ARM_HARDWARE_AMBA_KMI_H +#define ASM_ARM_HARDWARE_AMBA_KMI_H + +/* + * KMI control register: + * KMICR_TYPE 0 = PS2/AT mode, 1 = No line control bit mode + * KMICR_RXINTREN 1 = enable RX interrupts + * KMICR_TXINTREN 1 = enable TX interrupts + * KMICR_EN 1 = enable KMI + * KMICR_FD 1 = force KMI data low + * KMICR_FC 1 = force KMI clock low + */ +#define KMICR (KMI_BASE + 0x00) +#define KMICR_TYPE (1 << 5) +#define KMICR_RXINTREN (1 << 4) +#define KMICR_TXINTREN (1 << 3) +#define KMICR_EN (1 << 2) +#define KMICR_FD (1 << 1) +#define KMICR_FC (1 << 0) + +/* + * KMI status register: + * KMISTAT_TXEMPTY 1 = transmitter register empty + * KMISTAT_TXBUSY 1 = currently sending data + * KMISTAT_RXFULL 1 = receiver register ready to be read + * KMISTAT_RXBUSY 1 = currently receiving data + * KMISTAT_RXPARITY parity of last databyte received + * KMISTAT_IC current level of KMI clock input + * KMISTAT_ID current level of KMI data input + */ +#define KMISTAT (KMI_BASE + 0x04) +#define KMISTAT_TXEMPTY (1 << 6) +#define KMISTAT_TXBUSY (1 << 5) +#define KMISTAT_RXFULL (1 << 4) +#define KMISTAT_RXBUSY (1 << 3) +#define KMISTAT_RXPARITY (1 << 2) +#define KMISTAT_IC (1 << 1) +#define KMISTAT_ID (1 << 0) + +/* + * KMI data register + */ +#define KMIDATA (KMI_BASE + 0x08) + +/* + * KMI clock divisor: to generate 8MHz internal clock + * div = (ref / 8MHz) - 1; 0 <= div <= 15 + */ +#define KMICLKDIV (KMI_BASE + 0x0c) + +/* + * KMI interrupt register: + * KMIIR_TXINTR 1 = transmit interrupt asserted + * KMIIR_RXINTR 1 = receive interrupt asserted + */ +#define KMIIR (KMI_BASE + 0x10) +#define KMIIR_TXINTR (1 << 1) +#define KMIIR_RXINTR (1 << 0) + +/* + * The size of the KMI primecell + */ +#define KMI_SIZE (0x100) + +#endif diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/hardware/pci_v3.h linux/include/asm-arm/hardware/pci_v3.h --- v2.4.2/linux/include/asm-arm/hardware/pci_v3.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/hardware/pci_v3.h Fri Mar 2 18:38:39 2001 @@ -88,41 +88,41 @@ /* PCI COMMAND REGISTER bits */ -#define V3_COMMAND_M_FBB_EN BIT9 -#define V3_COMMAND_M_SERR_EN BIT8 -#define V3_COMMAND_M_PAR_EN BIT6 -#define V3_COMMAND_M_MASTER_EN BIT2 -#define V3_COMMAND_M_MEM_EN BIT1 -#define V3_COMMAND_M_IO_EN BIT0 +#define V3_COMMAND_M_FBB_EN (1 << 9) +#define V3_COMMAND_M_SERR_EN (1 << 8) +#define V3_COMMAND_M_PAR_EN (1 << 6) +#define V3_COMMAND_M_MASTER_EN (1 << 2) +#define V3_COMMAND_M_MEM_EN (1 << 1) +#define V3_COMMAND_M_IO_EN (1 << 0) /* SYSTEM REGISTER bits */ -#define V3_SYSTEM_M_RST_OUT BIT15 -#define V3_SYSTEM_M_LOCK BIT14 +#define V3_SYSTEM_M_RST_OUT (1 << 15) +#define V3_SYSTEM_M_LOCK (1 << 14) /* PCI_CFG bits */ -#define V3_PCI_CFG_M_RETRY_EN BIT10 -#define V3_PCI_CFG_M_AD_LOW1 BIT9 -#define V3_PCI_CFG_M_AD_LOW0 BIT8 +#define V3_PCI_CFG_M_RETRY_EN (1 << 10) +#define V3_PCI_CFG_M_AD_LOW1 (1 << 9) +#define V3_PCI_CFG_M_AD_LOW0 (1 << 8) /* PCI_BASE register bits (PCI -> Local Bus) */ #define V3_PCI_BASE_M_ADR_BASE 0xFFF00000 #define V3_PCI_BASE_M_ADR_BASEL 0x000FFF00 -#define V3_PCI_BASE_M_PREFETCH BIT3 -#define V3_PCI_BASE_M_TYPE BIT2+BIT1 -#define V3_PCI_BASE_M_IO BIT0 +#define V3_PCI_BASE_M_PREFETCH (1 << 3) +#define V3_PCI_BASE_M_TYPE (3 << 1) +#define V3_PCI_BASE_M_IO (1 << 0) /* PCI MAP register bits (PCI -> Local bus) */ #define V3_PCI_MAP_M_MAP_ADR 0xFFF00000 -#define V3_PCI_MAP_M_RD_POST_INH BIT15 -#define V3_PCI_MAP_M_ROM_SIZE BIT11+BIT10 -#define V3_PCI_MAP_M_SWAP BIT9+BIT8 +#define V3_PCI_MAP_M_RD_POST_INH (1 << 15) +#define V3_PCI_MAP_M_ROM_SIZE (3 << 10) +#define V3_PCI_MAP_M_SWAP (3 << 8) #define V3_PCI_MAP_M_ADR_SIZE 0x000000F0 -#define V3_PCI_MAP_M_REG_EN BIT1 -#define V3_PCI_MAP_M_ENABLE BIT0 +#define V3_PCI_MAP_M_REG_EN (1 << 1) +#define V3_PCI_MAP_M_ENABLE (1 << 0) /* 9 => 512M window size */ @@ -134,15 +134,15 @@ /* LB_BASE register bits (Local bus -> PCI) */ #define V3_LB_BASE_M_MAP_ADR 0xFFF00000 -#define V3_LB_BASE_M_SWAP BIT9+BIT8 +#define V3_LB_BASE_M_SWAP (3 << 8) #define V3_LB_BASE_M_ADR_SIZE 0x000000F0 -#define V3_LB_BASE_M_PREFETCH BIT3 -#define V3_LB_BASE_M_ENABLE BIT0 +#define V3_LB_BASE_M_PREFETCH (1 << 3) +#define V3_LB_BASE_M_ENABLE (1 << 0) /* LB_MAP register bits (Local bus -> PCI) */ #define V3_LB_MAP_M_MAP_ADR 0xFFF0 #define V3_LB_MAP_M_TYPE 0x000E -#define V3_LB_MAP_M_AD_LOW_EN BIT0 +#define V3_LB_MAP_M_AD_LOW_EN (1 << 0) #endif diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/hardware/serial_amba.h linux/include/asm-arm/hardware/serial_amba.h --- v2.4.2/linux/include/asm-arm/hardware/serial_amba.h Mon Sep 18 15:15:23 2000 +++ linux/include/asm-arm/hardware/serial_amba.h Fri Mar 2 18:38:39 2001 @@ -88,4 +88,7 @@ #define ARM_BAUD_2400 383 #define ARM_BAUD_1200 767 +#define AMBA_UARTRSR_ANY (AMBA_UARTRSR_OE|AMBA_UARTRSR_BE|AMBA_UARTRSR_PE|AMBA_UARTRSR_FE) +#define AMBA_UARTFR_MODEM_ANY (AMBA_UARTFR_DCD|AMBA_UARTFR_DSR|AMBA_UARTFR_CTS) + #endif diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/mach/amba_kmi.h linux/include/asm-arm/mach/amba_kmi.h --- v2.4.2/linux/include/asm-arm/mach/amba_kmi.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/mach/amba_kmi.h Fri Mar 2 18:38:39 2001 @@ -0,0 +1,39 @@ +/* + * linux/include/asm-arm/mach/amba_kmi.h + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +struct kmi_info { + u_int base; + u_int irq; + u_char divisor; + u_char type; + u_char state; + u_char prev_rx; + u_char last_tx; + u_char resend_count; + u_short res; + wait_queue_head_t wait_q; + void (*rx)(struct kmi_info *, u_int val, + struct pt_regs *regs); + char name[8]; +}; + +#define KMI_KEYBOARD 0 +#define KMI_MOUSE 1 + +int register_kmi(struct kmi_info *kmi); diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/param.h linux/include/asm-arm/param.h --- v2.4.2/linux/include/asm-arm/param.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/param.h Tue Mar 6 19:44:35 2001 @@ -28,5 +28,9 @@ /* max length of hostname */ #define MAXHOSTNAMELEN 64 +#ifdef __KERNEL__ +# define CLOCKS_PER_SEC HZ +#endif + #endif diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h --- v2.4.2/linux/include/asm-arm/pgtable.h Tue Nov 7 10:46:04 2000 +++ linux/include/asm-arm/pgtable.h Tue Mar 6 19:44:35 2001 @@ -180,8 +180,6 @@ /* FIXME: this is not correct */ #define kern_addr_valid(addr) (1) -#define io_remap_page_range remap_page_range - #include #endif /* !__ASSEMBLY__ */ diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h --- v2.4.2/linux/include/asm-arm/proc-armv/uaccess.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/proc-armv/uaccess.h Tue Mar 6 19:44:35 2001 @@ -24,7 +24,7 @@ /* We use 33-bit arithmetic here... */ #define __range_ok(addr,size) ({ \ unsigned long flag, sum; \ - __asm__ __volatile__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \ + __asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \ : "=&r" (flag), "=&r" (sum) \ : "r" (addr), "Ir" (size), "0" (current->addr_limit) \ : "cc"); \ @@ -32,7 +32,7 @@ #define __addr_ok(addr) ({ \ unsigned long flag; \ - __asm__ __volatile__("cmp %2, %0; movlo %0, #0" \ + __asm__("cmp %2, %0; movlo %0, #0" \ : "=&r" (flag) \ : "0" (current->addr_limit), "r" (addr) \ : "cc"); \ @@ -57,24 +57,8 @@ #define __put_user_asm_half(x,addr,err) \ ({ \ unsigned long __temp = (unsigned long)(x); \ - __asm__ __volatile__( \ - "1: strbt %1,[%3],#0\n" \ - "2: strbt %2,[%4],#0\n" \ - "3:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "4: mov %0, %5\n" \ - " b 3b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 4b\n" \ - " .long 2b, 4b\n" \ - " .previous" \ - : "=r" (err) \ - : "r" (__temp), "r" (__temp >> 8), \ - "r" (addr), "r" ((int)(addr) + 1), \ - "i" (-EFAULT), "0" (err)); \ + __put_user_asm_byte(__temp, addr, err); \ + __put_user_asm_byte(__temp >> 8, (int)(addr) + 1, err); \ }) #define __put_user_asm_word(x,addr,err) \ @@ -112,26 +96,10 @@ #define __get_user_asm_half(x,addr,err) \ ({ \ - unsigned long __temp; \ - __asm__ __volatile__( \ - "1: ldrbt %1,[%3],#0\n" \ - "2: ldrbt %2,[%4],#0\n" \ - " orr %1, %1, %2, lsl #8\n" \ - "3:\n" \ - " .section .fixup,\"ax\"\n" \ - " .align 2\n" \ - "4: mov %0, %5\n" \ - " mov %1, #0\n" \ - " b 3b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 4b\n" \ - " .long 2b, 4b\n" \ - " .previous" \ - : "=r" (err), "=r" (x), "=&r" (__temp) \ - : "r" (addr), "r" ((int)(addr) + 1), \ - "i" (-EFAULT), "0" (err)); \ + unsigned long __b1, __b2; \ + __get_user_asm_byte(__b1, addr, err); \ + __get_user_asm_byte(__b2, (int)(addr) + 1, err); \ + (x) = __b1 | (__b2 << 8); \ }) diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h --- v2.4.2/linux/include/asm-arm/proc-fns.h Mon Sep 18 15:15:24 2000 +++ linux/include/asm-arm/proc-fns.h Tue Mar 6 19:44:35 2001 @@ -28,7 +28,7 @@ #ifdef CONFIG_CPU_32 # define CPU_INCLUDE_NAME "asm/cpu-multi32.h" -# ifdef CONFIG_CPU_ARM6 +# ifdef CONFIG_CPU_ARM610 # ifdef CPU_NAME # undef MULTI_CPU # define MULTI_CPU @@ -36,7 +36,7 @@ # define CPU_NAME arm6 # endif # endif -# ifdef CONFIG_CPU_ARM7 +# ifdef CONFIG_CPU_ARM710 # ifdef CPU_NAME # undef MULTI_CPU # define MULTI_CPU @@ -44,7 +44,7 @@ # define CPU_NAME arm7 # endif # endif -# ifdef CONFIG_CPU_ARM720 +# ifdef CONFIG_CPU_ARM720T # ifdef CPU_NAME # undef MULTI_CPU # define MULTI_CPU @@ -52,7 +52,7 @@ # define CPU_NAME arm720 # endif # endif -# ifdef CONFIG_CPU_ARM920 +# ifdef CONFIG_CPU_ARM920T # ifdef CPU_NAME # undef MULTI_CPU # define MULTI_CPU diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h --- v2.4.2/linux/include/asm-arm/uaccess.h Tue Aug 29 14:09:15 2000 +++ linux/include/asm-arm/uaccess.h Tue Mar 6 19:44:35 2001 @@ -182,7 +182,8 @@ #define __put_user_nocheck(x,ptr,size) \ ({ \ long __pu_err = 0; \ - __put_user_size((x),(ptr),(size),__pu_err); \ + __typeof__(*(ptr)) *__pu_addr = (ptr); \ + __put_user_size((x),__pu_addr,(size),__pu_err); \ __pu_err; \ }) diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h --- v2.4.2/linux/include/asm-arm/unistd.h Fri Aug 11 14:29:03 2000 +++ linux/include/asm-arm/unistd.h Tue Mar 6 19:44:35 2001 @@ -400,7 +400,6 @@ static inline pid_t waitpid(pid_t pid, int *wait_stat, int options) { - extern long sys_wait4(int, int *, int, struct rusage *); return sys_wait4((int)pid, wait_stat, options, NULL); } @@ -412,7 +411,6 @@ static inline pid_t wait(int * wait_stat) { - extern long sys_wait4(int, int *, int, struct rusage *); return sys_wait4(-1, wait_stat, 0, NULL); } diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/xor.h linux/include/asm-arm/xor.h --- v2.4.2/linux/include/asm-arm/xor.h Sun Nov 12 19:39:51 2000 +++ linux/include/asm-arm/xor.h Tue Mar 6 19:44:35 2001 @@ -1 +1,142 @@ +/* + * linux/include/asm-arm/xor.h + * + * Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + #include + +#define __XOR(a1, a2) a1 ^= a2 + +#define GET_BLOCK_2(dst) \ + __asm__("ldmia %0, {%1, %2}" \ + : "=r" (dst), "=r" (a1), "=r" (a2) \ + : "0" (dst)) + +#define GET_BLOCK_4(dst) \ + __asm__("ldmia %0, {%1, %2, %3, %4}" \ + : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \ + : "0" (dst)) + +#define XOR_BLOCK_2(src) \ + __asm__("ldmia %0!, {%1, %2}" \ + : "=r" (src), "=r" (b1), "=r" (b2) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); + +#define XOR_BLOCK_4(src) \ + __asm__("ldmia %0!, {%1, %2, %3, %4}" \ + : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4) + +#define PUT_BLOCK_2(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2)) + +#define PUT_BLOCK_4(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3, %4, %5}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4)) + +static void +xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + XOR_BLOCK_4(p3); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static void +xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + XOR_BLOCK_2(p5); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static struct xor_block_template xor_block_arm4regs = { + name: "arm4regs", + do_2: xor_arm4regs_2, + do_3: xor_arm4regs_3, + do_4: xor_arm4regs_4, + do_5: xor_arm4regs_5, +}; + +#undef XOR_TRY_TEMPLATES +#define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_arm4regs); \ + xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_32regs); \ + } while (0) diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h --- v2.4.2/linux/include/asm-i386/atomic.h Thu Jan 4 14:50:46 2001 +++ linux/include/asm-i386/atomic.h Wed Mar 7 16:56:35 2001 @@ -23,9 +23,33 @@ #define ATOMIC_INIT(i) { (i) } +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_read(v) ((v)->counter) + +/** + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ #define atomic_set(v,i) (((v)->counter) = (i)) +/** + * atomic_add - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v. Note that the guaranteed useful range + * of an atomic_t is only 24 bits. + */ static __inline__ void atomic_add(int i, atomic_t *v) { __asm__ __volatile__( @@ -34,6 +58,14 @@ :"ir" (i), "m" (v->counter)); } +/** + * atomic_sub - subtract the atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ static __inline__ void atomic_sub(int i, atomic_t *v) { __asm__ __volatile__( @@ -42,6 +74,16 @@ :"ir" (i), "m" (v->counter)); } +/** + * atomic_sub_and_test - test variable then subtract + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v and returns + * true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ static __inline__ int atomic_sub_and_test(int i, atomic_t *v) { unsigned char c; @@ -53,6 +95,13 @@ return c; } +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ static __inline__ void atomic_inc(atomic_t *v) { __asm__ __volatile__( @@ -61,6 +110,13 @@ :"m" (v->counter)); } +/** + * atomic_dec - decrement the atomic variable + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ static __inline__ void atomic_dec(atomic_t *v) { __asm__ __volatile__( @@ -69,6 +125,15 @@ :"m" (v->counter)); } +/** + * atomic_dec_and_test - decrement by 1 and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ static __inline__ int atomic_dec_and_test(atomic_t *v) { unsigned char c; @@ -80,6 +145,15 @@ return c != 0; } +/** + * atomic_inc_and_test - increment by 1 and test + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1 + * and returns true if the result is zero, or false for all + * other cases. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ static __inline__ int atomic_inc_and_test(atomic_t *v) { unsigned char c; @@ -91,6 +165,16 @@ return c != 0; } +/** + * atomic_add_negative - add and test if negative + * @v: pointer of type atomic_t + * @i: integer value to add + * + * Atomically adds @i to @v and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. Note that the guaranteed + * useful range of an atomic_t is only 24 bits. + */ static __inline__ int atomic_add_negative(int i, atomic_t *v) { unsigned char c; diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/highmem.h linux/include/asm-i386/highmem.h --- v2.4.2/linux/include/asm-i386/highmem.h Thu Jan 4 14:50:47 2001 +++ linux/include/asm-i386/highmem.h Wed Mar 7 16:56:35 2001 @@ -2,14 +2,14 @@ * highmem.h: virtual kernel memory mappings for high memory * * Used in CONFIG_HIGHMEM systems for memory pages which - * are not addressable by direct kernel virtual adresses. + * are not addressable by direct kernel virtual addresses. * * Copyright (C) 1999 Gerhard Wichert, Siemens AG * Gerhard.Wichert@pdb.siemens.de * * * Redesigned the x86 32-bit VM architecture to deal with - * up to 16 Terrabyte physical memory. With current x86 CPUs + * up to 16 Terabyte physical memory. With current x86 CPUs * we now support up to 64 Gigabytes physical RAM. * * Copyright (C) 1999 Ingo Molnar diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h --- v2.4.2/linux/include/asm-i386/pci.h Thu Jan 4 14:51:31 2001 +++ linux/include/asm-i386/pci.h Wed Mar 7 16:57:10 2001 @@ -152,6 +152,14 @@ */ extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) { + /* + * we fall back to GFP_DMA when the mask isn't all 1s, + * so we can't guarantee allocations that must be + * within a tighter range than GFP_DMA.. + */ + if(mask < 0x00ffffff) + return 0; + return 1; } diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/string-486.h linux/include/asm-i386/string-486.h --- v2.4.2/linux/include/asm-i386/string-486.h Thu Jan 4 14:50:47 2001 +++ linux/include/asm-i386/string-486.h Wed Mar 7 16:56:35 2001 @@ -352,11 +352,6 @@ #ifdef CONFIG_X86_USE_3DNOW -#include -#include -#include -#include -#include #include /* @@ -365,14 +360,14 @@ static inline void * __constant_memcpy3d(void * to, const void * from, size_t len) { - if(len<512 || in_interrupt()) + if (len < 512) return __memcpy_c(to, from, len); return _mmx_memcpy(to, from, len); } static inline void *__memcpy3d(void *to, const void *from, size_t len) { - if(len<512 || in_interrupt()) + if(len < 512) return __memcpy_g(to, from, len); return _mmx_memcpy(to, from, len); } diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/string.h linux/include/asm-i386/string.h --- v2.4.2/linux/include/asm-i386/string.h Thu Jan 4 14:50:47 2001 +++ linux/include/asm-i386/string.h Wed Mar 7 16:56:35 2001 @@ -287,13 +287,6 @@ #ifdef CONFIG_X86_USE_3DNOW -/* All this just for in_interrupt() ... */ - -#include -#include -#include -#include -#include #include /* @@ -302,14 +295,14 @@ static inline void * __constant_memcpy3d(void * to, const void * from, size_t len) { - if(len<512 || in_interrupt()) + if (len < 512) return __constant_memcpy(to, from, len); return _mmx_memcpy(to, from, len); } extern __inline__ void *__memcpy3d(void *to, const void *from, size_t len) { - if(len<512 || in_interrupt()) + if (len < 512) return __memcpy(to, from, len); return _mmx_memcpy(to, from, len); } diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/pci/bridge.h linux/include/asm-ia64/sn/pci/bridge.h --- v2.4.2/linux/include/asm-ia64/sn/pci/bridge.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/pci/bridge.h Tue Mar 6 19:44:34 2001 @@ -373,7 +373,7 @@ ds:2, /* Data size */ gbr:1, /* GBR enable */ vbpm:1, /* VBPM message */ - error:1, /* Error occured */ + error:1, /* Error occurred */ barr:1, /* Barrier op */ rsvd:8; } berr_st; @@ -693,7 +693,7 @@ #define BRIDGE_INT_ADDR(x) (BRIDGE_INT_ADDR0+(x)*BRIDGE_INT_ADDR_OFF) #define BRIDGE_INT_VIEW 0x000174 /* Interrupt view */ -#define BRIDGE_MULTIPLE_INT 0x00017c /* Multiple interrupt occured */ +#define BRIDGE_MULTIPLE_INT 0x00017c /* Multiple interrupt occurred */ #define BRIDGE_FORCE_ALWAYS0 0x000184 /* Force an interrupt (always)*/ #define BRIDGE_FORCE_ALWAYS_OFF 0x000008 /* Force Always offset */ diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/pci/pcibr_private.h linux/include/asm-ia64/sn/pci/pcibr_private.h --- v2.4.2/linux/include/asm-ia64/sn/pci/pcibr_private.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/pci/pcibr_private.h Tue Mar 6 19:44:34 2001 @@ -328,7 +328,7 @@ #ifdef IRIX toid_t bserr_toutid; /* Timeout started by errintr */ #endif - iopaddr_t bserr_addr; /* Address where error occured */ + iopaddr_t bserr_addr; /* Address where error occurred */ bridgereg_t bserr_intstat; /* interrupts active at error time */ } bs_errinfo; diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/sn1/hubmd.h linux/include/asm-ia64/sn/sn1/hubmd.h --- v2.4.2/linux/include/asm-ia64/sn/sn1/hubmd.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/hubmd.h Tue Mar 6 19:44:34 2001 @@ -2140,7 +2140,7 @@ * corresponds to the valid bit, and bit 1 of each two-bit field * * corresponds to the overrun bit. * * The rule for the valid bit is that it gets set whenever that error * - * occurs, regardless of whether a higher priority error has occured. * + * occurs, regardless of whether a higher priority error has occurred. * * The rule for the overrun bit is that it gets set whenever we are * * unable to record the address information for this particular * * error, due to a previous error of the same or higher priority. * @@ -2221,7 +2221,7 @@ * corresponds to the valid bit, and bit 1 of each two-bit field * * corresponds to the overrun bit. * * The rule for the valid bit is that it gets set whenever that error * - * occurs, regardless of whether a higher priority error has occured. * + * occurs, regardless of whether a higher priority error has occurred. * * The rule for the overrun bit is that it gets set whenever we are * * unable to record the address information for this particular * * error, due to a previous error of the same or higher priority. * diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/sn1/hubmd_next.h linux/include/asm-ia64/sn/sn1/hubmd_next.h --- v2.4.2/linux/include/asm-ia64/sn/sn1/hubmd_next.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/sn1/hubmd_next.h Tue Mar 6 19:44:34 2001 @@ -648,7 +648,7 @@ #define MD_SDIR_MASK 0xffffffff /* When premium mode is on for probing but standard directory memory - is installed, the vaild directory bits depend on the phys. bank */ + is installed, the valid directory bits depend on the phys. bank */ #define MD_PDIR_PROBE_MASK(pb) 0xffffffffffffffff #define MD_SDIR_PROBE_MASK(pb) (0xffff0000ffff << ((pb) ? 16 : 0)) diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/xtalk/xbow.h linux/include/asm-ia64/sn/xtalk/xbow.h --- v2.4.2/linux/include/asm-ia64/sn/xtalk/xbow.h Thu Jan 4 13:00:15 2001 +++ linux/include/asm-ia64/sn/xtalk/xbow.h Tue Mar 6 19:44:34 2001 @@ -494,7 +494,7 @@ typedef union xbw0_status_u { xbowreg_t statusword; struct { - uint32_t mult_err:1, /* Multiple error occured */ + uint32_t mult_err:1, /* Multiple error occurred */ connect_tout:1, /* Connection timeout */ xtalk_err:1, /* Xtalk pkt with error bit */ /* End of Xbridge only */ @@ -524,7 +524,7 @@ /* End of Xbridge only */ xtalk_err:1, /* Xtalk pkt with error bit */ connect_tout:1, /* Connection timeout */ - mult_err:1; /* Multiple error occured */ + mult_err:1; /* Multiple error occurred */ } xbw0_stfield; } xbw0_status_t; diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/system.h linux/include/asm-ia64/system.h --- v2.4.2/linux/include/asm-ia64/system.h Thu Jan 4 12:50:18 2001 +++ linux/include/asm-ia64/system.h Tue Mar 6 19:44:34 2001 @@ -64,7 +64,7 @@ } console_info; __u16 num_pci_vectors; /* number of ACPI derived PCI IRQ's*/ __u64 pci_vectors; /* physical address of PCI data (pci_vector_struct)*/ - __u64 fpswa; /* physical address of the the fpswa interface */ + __u64 fpswa; /* physical address of the fpswa interface */ __u64 initrd_start; __u64 initrd_size; } ia64_boot_param; diff -u --recursive --new-file v2.4.2/linux/include/asm-mips64/smp.h linux/include/asm-mips64/smp.h --- v2.4.2/linux/include/asm-mips64/smp.h Fri Aug 4 16:15:37 2000 +++ linux/include/asm-mips64/smp.h Fri Mar 2 11:30:15 2001 @@ -40,6 +40,7 @@ /* Good enough for toy^Wupto 64 CPU Origins. */ extern unsigned long cpu_present_mask; +#define cpu_online_map cpu_present_mask #endif diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/cpm_8260.h linux/include/asm-ppc/cpm_8260.h --- v2.4.2/linux/include/asm-ppc/cpm_8260.h Sat Nov 11 18:23:10 2000 +++ linux/include/asm-ppc/cpm_8260.h Sat Mar 3 10:52:14 2001 @@ -112,7 +112,7 @@ uint cbd_bufaddr; /* Buffer address in host memory */ } cbd_t; -#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */ +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ #define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ #define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ #define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/highmem.h linux/include/asm-ppc/highmem.h --- v2.4.2/linux/include/asm-ppc/highmem.h Wed Nov 8 19:01:34 2000 +++ linux/include/asm-ppc/highmem.h Sat Mar 3 10:52:14 2001 @@ -4,7 +4,7 @@ * PowerPC version, stolen from the i386 version. * * Used in CONFIG_HIGHMEM systems for memory pages which - * are not addressable by direct kernel virtual adresses. + * are not addressable by direct kernel virtual addresses. * * Copyright (C) 1999 Gerhard Wichert, Siemens AG * Gerhard.Wichert@pdb.siemens.de diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h --- v2.4.2/linux/include/asm-ppc/irq.h Sat Feb 3 19:51:31 2001 +++ linux/include/asm-ppc/irq.h Sat Mar 3 10:52:14 2001 @@ -88,23 +88,31 @@ #define SIU_IRQ7 (14) #define SIU_LEVEL7 (15) +/* Now include the board configuration specific associations. +*/ +#include + /* The internal interrupts we can configure as we see fit. * My personal preference is CPM at level 2, which puts it above the * MBX PCI/ISA/IDE interrupts. */ +#ifndef PIT_INTERRUPT #define PIT_INTERRUPT SIU_LEVEL0 +#endif +#ifndef CPM_INTERRUPT #define CPM_INTERRUPT SIU_LEVEL2 +#endif +#ifndef PCMCIA_INTERRUPT #define PCMCIA_INTERRUPT SIU_LEVEL6 +#endif +#ifndef DEC_INTERRUPT #define DEC_INTERRUPT SIU_LEVEL7 +#endif /* Some internal interrupt registers use an 8-bit mask for the interrupt * level instead of a number. */ #define mk_int_int_mask(IL) (1 << (7 - (IL/2))) - -/* Now include the board configuration specific associations. -*/ -#include /* always the same on 8xx -- Cort */ static __inline__ int irq_cannonicalize(int irq) diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/ivms8.h linux/include/asm-ppc/ivms8.h --- v2.4.2/linux/include/asm-ppc/ivms8.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ppc/ivms8.h Sat Mar 3 10:52:14 2001 @@ -0,0 +1,92 @@ +/* + * A collection of structures, addresses, and values associated with + * Speech Design Integrated Voicemail Systems (IVMS8) boards. + * + * Copyright (c) 2000 Wolfgang Denk (wd@denx.de) + */ +#ifndef __MACH_IVMS8_DEFS +#define __MACH_IVMS8_DEFS + +#ifndef __ASSEMBLY__ + +typedef void (interrupt_handler_t)(void *); + +typedef struct serial_io { + int (*getc)(void); + int (*tstc)(void); + void (*putc)(const char c); + void (*printf)(const char *fmt, ...); +} serial_io_t; + +typedef struct intr_util { + void (*install_hdlr)(int, interrupt_handler_t *, void *); + void (*free_hdlr)(int); +} intr_util_t; + + +/* A Board Information structure that is given to a program when + * ppcboot starts it up. + */ +typedef struct bd_info { + unsigned long bi_memstart; /* start of DRAM memory */ + unsigned long bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ + unsigned long bi_sramstart; /* start of SRAM memory */ + unsigned long bi_sramsize; /* size of SRAM memory */ + unsigned long bi_immr_base; /* base of IMMR register */ + unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned char bi_enetaddr[6]; /* Ethernet adress */ + unsigned char bi_reserved[2]; /* -- just for alignment -- */ + unsigned long bi_intfreq; /* Internal Freq, in MHz */ + unsigned long bi_busfreq; /* Bus Freq, in MHz */ + unsigned long bi_baudrate; /* Console Baudrate */ + serial_io_t bi_serial_io; /* Addr of monitor fnc for Console I/O */ + intr_util_t bi_interrupt; /* Addr of monitor fnc for Interrupts */ +} bd_t; + +#endif /* __ASSEMBLY__ */ + +#define IVMS_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */ +#define IVMS_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR IVMS_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE IVMS_IMAP_SIZE /* mapped size of IMMR area */ + +#define PCMCIA_MEM_ADDR ((uint)0xFE100000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) + +#define FEC_INTERRUPT 9 /* = SIU_LEVEL4 */ +#define IDE0_INTERRUPT 10 /* = IRQ5 */ +#define CPM_INTERRUPT 11 /* = SIU_LEVEL5 (was: SIU_LEVEL2) */ +#define PHY_INTERRUPT 12 /* = IRQ6 */ + +#define MAX_HWIFS 1 /* overwrite default in include/asm-ppc/ide.h */ + +/* + * Definitions for IDE0 Interface + */ +#define IDE0_BASE_OFFSET 0x0000 /* Offset in PCMCIA memory */ +#define IDE0_DATA_REG_OFFSET 0x0000 +#define IDE0_ERROR_REG_OFFSET 0x0081 +#define IDE0_NSECTOR_REG_OFFSET 0x0082 +#define IDE0_SECTOR_REG_OFFSET 0x0083 +#define IDE0_LCYL_REG_OFFSET 0x0084 +#define IDE0_HCYL_REG_OFFSET 0x0085 +#define IDE0_SELECT_REG_OFFSET 0x0086 +#define IDE0_STATUS_REG_OFFSET 0x0087 +#define IDE0_CONTROL_REG_OFFSET 0x0106 +#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +/* Generic 8xx type +*/ +#define _MACH_8xx (_MACH_ivms8) + +#endif /* __MACH_IVMS8_DEFS */ + diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/mpc8xx.h linux/include/asm-ppc/mpc8xx.h --- v2.4.2/linux/include/asm-ppc/mpc8xx.h Sat Nov 11 18:23:11 2000 +++ linux/include/asm-ppc/mpc8xx.h Sat Mar 3 10:52:14 2001 @@ -33,12 +33,16 @@ #include #endif -#if (defined(CONFIG_TQM860) || defined(CONFIG_TQM860L)) -#include +#if (defined(CONFIG_TQM860) || defined(CONFIG_TQM8xxL)) +#include #endif -#ifdef CONFIG_TQM8xxL -#include +#if defined(CONFIG_SPD823TS) +#include +#endif + +#if defined(CONFIG_IVMS8) +#include #endif /* I need this to get pt_regs....... diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h --- v2.4.2/linux/include/asm-ppc/pci.h Sat Feb 3 19:51:31 2001 +++ linux/include/asm-ppc/pci.h Sat Mar 3 10:52:14 2001 @@ -34,6 +34,7 @@ * * Obsolete ! Drivers should now use pci_resource_to_bus */ +extern unsigned long phys_to_bus(unsigned long pa); extern unsigned long pci_phys_to_bus(unsigned long pa, int busnr); extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr); diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h --- v2.4.2/linux/include/asm-ppc/processor.h Sat Feb 3 19:51:31 2001 +++ linux/include/asm-ppc/processor.h Sat Mar 3 10:52:14 2001 @@ -516,6 +516,8 @@ #define _MACH_8260 0x00002000 /* Generic 8260 */ #define _MACH_tqm860 0x00004000 /* TQM860/L */ #define _MACH_tqm8xxL 0x00008000 /* TQM8xxL */ +#define _MACH_spd8xxL 0x00010000 /* SPD8xx */ +#define _MACH_ibms8 0x00020000 /* IVMS8 */ /* see residual.h for these */ #define _PREP_Motorola 0x01 /* motorola prep */ diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h --- v2.4.2/linux/include/asm-ppc/semaphore.h Tue May 2 13:05:40 2000 +++ linux/include/asm-ppc/semaphore.h Sat Mar 3 10:52:14 2001 @@ -132,7 +132,7 @@ #define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, 0, 0) #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 1, 0) -#define DECLAER_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0, 1) +#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0, 1) extern inline void init_rwsem(struct rw_semaphore *sem) { diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/spd8xx.h linux/include/asm-ppc/spd8xx.h --- v2.4.2/linux/include/asm-ppc/spd8xx.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ppc/spd8xx.h Sat Mar 3 10:52:14 2001 @@ -0,0 +1,105 @@ +/* + * A collection of structures, addresses, and values associated with + * Speech Design SPD8xxTS boards. + * + * Copyright (c) 2000 Wolfgang Denk (wd@denx.de) + */ +#ifndef __MACH_SPD8xx_DEFS +#define __MACH_SPD8xx_DEFS + +#ifndef __ASSEMBLY__ + +typedef void (interrupt_handler_t)(void *); + +typedef struct serial_io { + int (*getc)(void); + int (*tstc)(void); + void (*putc)(const char c); + void (*printf)(const char *fmt, ...); +} serial_io_t; + +typedef struct intr_util { + void (*install_hdlr)(int, interrupt_handler_t *, void *); + void (*free_hdlr)(int); +} intr_util_t; + + +/* A Board Information structure that is given to a program when + * ppcboot starts it up. + */ +typedef struct bd_info { + unsigned long bi_memstart; /* start of DRAM memory */ + unsigned long bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ + unsigned long bi_sramstart; /* start of SRAM memory */ + unsigned long bi_sramsize; /* size of SRAM memory */ + unsigned long bi_immr_base; /* base of IMMR register */ + unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned char bi_enetaddr[6]; /* Ethernet adress */ + unsigned char bi_reserved[2]; /* -- just for alignment -- */ + unsigned long bi_intfreq; /* Internal Freq, in MHz */ + unsigned long bi_busfreq; /* Bus Freq, in MHz */ + unsigned long bi_baudrate; /* Console Baudrate */ + serial_io_t bi_serial_io; /* Addr of monitor fnc for Console I/O */ + intr_util_t bi_interrupt; /* Addr of monitor fnc for Interrupts */ +} bd_t; + +#endif /* __ASSEMBLY__ */ + +#define SPD_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */ +#define SPD_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR SPD_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE SPD_IMAP_SIZE /* mapped size of IMMR area */ + +#define PCMCIA_MEM_ADDR ((uint)0xFE100000) +#define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) + +#define IDE0_INTERRUPT 10 /* = IRQ5 */ +#define IDE1_INTERRUPT 12 /* = IRQ6 */ +#define CPM_INTERRUPT 13 /* = SIU_LEVEL6 (was: SIU_LEVEL2) */ + +#define MAX_HWIFS 2 /* overwrite default in include/asm-ppc/ide.h */ + +/* + * Definitions for IDE0 Interface + */ +#define IDE0_BASE_OFFSET 0x0000 /* Offset in PCMCIA memory */ +#define IDE0_DATA_REG_OFFSET 0x0000 +#define IDE0_ERROR_REG_OFFSET 0x0081 +#define IDE0_NSECTOR_REG_OFFSET 0x0082 +#define IDE0_SECTOR_REG_OFFSET 0x0083 +#define IDE0_LCYL_REG_OFFSET 0x0084 +#define IDE0_HCYL_REG_OFFSET 0x0085 +#define IDE0_SELECT_REG_OFFSET 0x0086 +#define IDE0_STATUS_REG_OFFSET 0x0087 +#define IDE0_CONTROL_REG_OFFSET 0x0106 +#define IDE0_IRQ_REG_OFFSET 0x000A /* not used */ + +/* + * Definitions for IDE1 Interface + */ +#define IDE1_BASE_OFFSET 0x0C00 /* Offset in PCMCIA memory */ +#define IDE1_DATA_REG_OFFSET 0x0000 +#define IDE1_ERROR_REG_OFFSET 0x0081 +#define IDE1_NSECTOR_REG_OFFSET 0x0082 +#define IDE1_SECTOR_REG_OFFSET 0x0083 +#define IDE1_LCYL_REG_OFFSET 0x0084 +#define IDE1_HCYL_REG_OFFSET 0x0085 +#define IDE1_SELECT_REG_OFFSET 0x0086 +#define IDE1_STATUS_REG_OFFSET 0x0087 +#define IDE1_CONTROL_REG_OFFSET 0x0106 +#define IDE1_IRQ_REG_OFFSET 0x000A /* not used */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +/* Generic 8xx type +*/ +#define _MACH_8xx (_MACH_spd8xx) + +#endif /* __MACH_SPD8xx_DEFS */ diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h --- v2.4.2/linux/include/asm-ppc/system.h Sat Nov 11 18:23:11 2000 +++ linux/include/asm-ppc/system.h Sat Mar 3 10:52:14 2001 @@ -49,15 +49,6 @@ extern void xmon_irq(int, void *, struct pt_regs *); extern void xmon(struct pt_regs *excp); - - -/* Data cache block flush - write out the cache line containing the - specified address and then invalidate it in the cache. */ -extern __inline__ void dcbf(void *line) -{ - asm("dcbf %0,%1; sync" : : "r" (line), "r" (0)); -} - extern void print_backtrace(unsigned long *); extern void show_regs(struct pt_regs * regs); extern void flush_instruction_cache(void); diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/time.h linux/include/asm-ppc/time.h --- v2.4.2/linux/include/asm-ppc/time.h Sat Nov 11 18:23:11 2000 +++ linux/include/asm-ppc/time.h Sat Mar 3 10:52:14 2001 @@ -2,7 +2,7 @@ * $Id: time.h,v 1.12 1999/08/27 04:21:23 cort Exp $ * Common time prototypes and such for all ppc machines. * - * Written by Cort Dougan (cort@cs.nmt.edu) to merge + * Written by Cort Dougan (cort@fsmlabs.com) to merge * Paul Mackerras' version and mine for PReP and Pmac. */ @@ -16,6 +16,7 @@ extern unsigned tb_ticks_per_jiffy; extern unsigned tb_to_us; extern unsigned tb_last_stamp; +extern unsigned long disarm_decr[NR_CPUS]; extern void to_tm(int tim, struct rtc_time * tm); extern time_t last_rtc_update; diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/tlb.h linux/include/asm-ppc/tlb.h --- v2.4.2/linux/include/asm-ppc/tlb.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ppc/tlb.h Sat Mar 3 10:52:14 2001 @@ -0,0 +1 @@ +#include diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/tqm860.h linux/include/asm-ppc/tqm860.h --- v2.4.2/linux/include/asm-ppc/tqm860.h Sat Nov 11 18:23:11 2000 +++ linux/include/asm-ppc/tqm860.h Wed Dec 31 16:00:00 1969 @@ -1,67 +0,0 @@ - -/* - * A collection of structures, addresses, and values associated with - * the TQ Systems TQM860 modules. This was originally created for the - * MBX860, and probably needs revisions for other boards (like the 821). - * When this file gets out of control, we can split it up into more - * meaningful pieces. - * - * Based on mbx.h, Copyright (c) 1997 Dan Malek (dmalek@jlc.net) - * - * Copyright (c) 1999 Wolfgang Denk (wd@denx.de) - */ -#ifdef __KERNEL__ -#ifndef __MACH_TQM860_DEFS -#define __MACH_TQM860_DEFS - -/* A Board Information structure that is given to a program when - * EPPC-Bug starts it up. - */ -typedef struct bd_info { - unsigned long bi_memstart; /* start of DRAM memory */ - unsigned long bi_memsize; /* size of DRAM memory in bytes */ - unsigned long bi_flashstart; /* start of FLASH memory */ - unsigned long bi_flashsize; /* size of FLASH memory */ - unsigned long bi_flashoffset; /* reserved area for startup monitor */ - unsigned long bi_sramstart; /* start of SRAM memory */ - unsigned long bi_sramsize; /* size of SRAM memory */ - unsigned long bi_immr_base; /* base of IMMR register */ - unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ - unsigned long bi_ip_addr; /* IP Address */ - unsigned char bi_enetaddr[6]; /* Ethernet adress */ - unsigned char bi_reserved[2]; /* -- just for alignment -- */ - unsigned long bi_putchar; /* Addr of monitor putchar() to Console */ - unsigned long bi_intfreq; /* Internal Freq, in MHz */ - unsigned long bi_busfreq; /* Bus Freq, in MHz */ - unsigned long bi_baudrate; /* Console Baudrate */ -} bd_t; - -/* Configuration options for TQ Systems TQM860 mini module - */ - -#define TQM_RESET_ADDR 0x40000100 /* Monitor Reset Entry */ - -#define TQM_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */ -#define TQM_IMAP_SIZE (64 * 1024) /* size of mapped area */ - -#define TQM_CLOCKRATE 50 /* 50 MHz Clock */ -#define TQM_BAUDRATE 115200 /* Console baud rate */ -#define TQM_IP_ADDR 0x0A000063 /* IP addr: 10.0.0.99 */ - -#define TQM_SERVER_IP "10.0.0.3" /* NFS server IP addr */ -#define TQM_SERVER_DIR "/LinuxPPC" /* NFS exported root */ - -#define IMAP_ADDR TQM_IMMR_BASE /* physical base address of IMMR area */ -#define IMAP_SIZE TQM_IMAP_SIZE /* mapped size of IMMR area */ - -/* We don't use the 8259. -*/ -#define NR_8259_INTS 0 - -/* Generic 8xx type -*/ -#define _MACH_8xx (_MACH_tqm860) - -#endif /* __MACH_TQM860_DEFS */ - -#endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/tqm8xx.h linux/include/asm-ppc/tqm8xx.h --- v2.4.2/linux/include/asm-ppc/tqm8xx.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ppc/tqm8xx.h Sat Mar 3 10:52:14 2001 @@ -0,0 +1,76 @@ +/* + * A collection of structures, addresses, and values associated with + * the TQ Systems TQM8xx(L) modules. This was originally created for the + * MBX860, and probably needs revisions for other boards (like the 821). + * When this file gets out of control, we can split it up into more + * meaningful pieces. + * + * Based on mbx.h, Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * Copyright (c) 1999,2000 Wolfgang Denk (wd@denx.de) + */ +#ifndef __MACH_TQM8xx_DEFS +#define __MACH_TQM8xx_DEFS + +#ifndef __ASSEMBLY__ + +typedef void (interrupt_handler_t)(void *); + +typedef struct serial_io { + int (*getc)(void); + int (*tstc)(void); + void (*putc)(const char c); + void (*printf)(const char *fmt, ...); +} serial_io_t; + +typedef struct intr_util { + void (*install_hdlr)(int, interrupt_handler_t *, void *); + void (*free_hdlr)(int); +} intr_util_t; + + +/* A Board Information structure that is given to a program when + * ppcboot starts it up. + */ +typedef struct bd_info { + unsigned long bi_memstart; /* start of DRAM memory */ + unsigned long bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ + unsigned long bi_sramstart; /* start of SRAM memory */ + unsigned long bi_sramsize; /* size of SRAM memory */ + unsigned long bi_immr_base; /* base of IMMR register */ + unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned char bi_enetaddr[6]; /* Ethernet adress */ + unsigned char bi_reserved[2]; /* -- just for alignment -- */ + unsigned long bi_intfreq; /* Internal Freq, in MHz */ + unsigned long bi_busfreq; /* Bus Freq, in MHz */ + unsigned long bi_baudrate; /* Console Baudrate */ + serial_io_t bi_serial_io; /* Addr of monitor fnc for Console I/O */ + intr_util_t bi_interrupt; /* Addr of monitor fnc for Interrupts */ +} bd_t; + +#endif /* __ASSEMBLY__ */ + +#define TQM_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */ +#define TQM_IMAP_SIZE (64 * 1024) /* size of mapped area */ + +#define IMAP_ADDR TQM_IMMR_BASE /* physical base address of IMMR area */ +#define IMAP_SIZE TQM_IMAP_SIZE /* mapped size of IMMR area */ + +/* We don't use the 8259. +*/ +#define NR_8259_INTS 0 + +/* Generic 8xx type +*/ +#if defined(CONFIG_TQM8xxL) +#define _MACH_8xx (_MACH_tqm8xxL) +#endif +#if defined(CONFIG_TQM860) +#define _MACH_8xx (_MACH_tqm860) +#endif + +#endif /* __MACH_TQM8xx_DEFS */ diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/tqm8xxL.h linux/include/asm-ppc/tqm8xxL.h --- v2.4.2/linux/include/asm-ppc/tqm8xxL.h Sat Nov 11 18:23:11 2000 +++ linux/include/asm-ppc/tqm8xxL.h Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ - -/* - * A collection of structures, addresses, and values associated with - * the TQ Systems TQM850L modules. This was originally created for the - * MBX860, and probably needs revisions for other boards (like the 821). - * When this file gets out of control, we can split it up into more - * meaningful pieces. - * - * Based on mbx.h, Copyright (c) 1997 Dan Malek (dmalek@jlc.net) - * - * Copyright (c) 1999 Wolfgang Denk (wd@denx.de) - */ -#ifdef __KERNEL__ -#ifndef __MACH_TQM8xxL_DEFS -#define __MACH_TQM8xxL_DEFS - -/* A Board Information structure that is given to a program when - * EPPC-Bug starts it up. - */ -typedef struct bd_info { - unsigned long bi_memstart; /* start of DRAM memory */ - unsigned long bi_memsize; /* size of DRAM memory in bytes */ - unsigned long bi_flashstart; /* start of FLASH memory */ - unsigned long bi_flashsize; /* size of FLASH memory */ - unsigned long bi_flashoffset; /* reserved area for startup monitor */ - unsigned long bi_sramstart; /* start of SRAM memory */ - unsigned long bi_sramsize; /* size of SRAM memory */ - unsigned long bi_immr_base; /* base of IMMR register */ - unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ - unsigned long bi_ip_addr; /* IP Address */ - unsigned char bi_enetaddr[6]; /* Ethernet adress */ - unsigned char bi_reserved[2]; /* -- just for alignment -- */ - unsigned long bi_putchar; /* Addr of monitor putchar() to Console */ - unsigned long bi_intfreq; /* Internal Freq, in MHz */ - unsigned long bi_busfreq; /* Bus Freq, in MHz */ - unsigned long bi_baudrate; /* Console Baudrate */ -} bd_t; - -/* Configuration options for TQ Systems TQM850L mini module - */ - -#define TQM_RESET_ADDR 0x40000100 /* Monitor Reset Entry */ - -#define TQM_IMMR_BASE 0xFFF00000 /* phys. addr of IMMR */ -#define TQM_IMAP_SIZE (64 * 1024) /* size of mapped area */ - -#define TQM_CLOCKRATE 50 /* 50 MHz Clock */ -/*#define TQM_BAUDRATE 115200 */ /* Console baud rate */ -#define TQM_BAUDRATE 38400 /* Console baud rate */ -#define TQM_IP_ADDR 0x0A000063 /* IP addr: 10.0.0.99 */ - -#define TQM_SERVER_IP "10.0.0.2" /* NFS server IP addr */ -#define TQM_SERVER_DIR "/LinuxPPC" /* NFS exported root */ - -#define IMAP_ADDR TQM_IMMR_BASE /* physical base address of IMMR area */ -#define IMAP_SIZE TQM_IMAP_SIZE /* mapped size of IMMR area */ - -/* We don't use the 8259. -*/ -#define NR_8259_INTS 0 - -/* Generic 8xx type -*/ -#define _MACH_8xx (_MACH_tqm8xxL) - -#endif /* __MACH_TQM8xxL_DEFS */ - -#endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.2/linux/include/asm-s390/ccwcache.h linux/include/asm-s390/ccwcache.h --- v2.4.2/linux/include/asm-s390/ccwcache.h Wed Feb 21 18:20:42 2001 +++ linux/include/asm-s390/ccwcache.h Fri Mar 2 11:12:06 2001 @@ -59,7 +59,7 @@ #define CQR_STATUS_FILLED 0x01 /* request is ready to be preocessed */ #define CQR_STATUS_QUEUED 0x02 /* request is queued to be processed */ #define CQR_STATUS_IN_IO 0x03 /* request is currently in IO */ -#define CQR_STATUS_DONE 0x04 /* request is completed sucessfully */ +#define CQR_STATUS_DONE 0x04 /* request is completed successfully */ #define CQR_STATUS_ERROR 0x05 /* request is completed with error */ #define CQR_STATUS_FAILED 0x06 /* request is finally failed */ diff -u --recursive --new-file v2.4.2/linux/include/asm-s390/lowcore.h linux/include/asm-s390/lowcore.h --- v2.4.2/linux/include/asm-s390/lowcore.h Wed Feb 21 18:20:42 2001 +++ linux/include/asm-s390/lowcore.h Fri Mar 2 11:12:06 2001 @@ -124,7 +124,7 @@ __u8 pad3[0xD8-0xC4]; /* 0x0c4 */ __u32 cpu_timer_save_area[2]; /* 0x0d8 */ __u32 clock_comp_save_area[2]; /* 0x0e0 */ - __u32 mcck_interuption_code[2]; /* 0x0e8 */ + __u32 mcck_interruption_code[2]; /* 0x0e8 */ __u8 pad4[0xf4-0xf0]; /* 0x0f0 */ __u32 external_damage_code; /* 0x0f4 */ __u32 failing_storage_address; /* 0x0f8 */ diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/ccwcache.h linux/include/asm-s390x/ccwcache.h --- v2.4.2/linux/include/asm-s390x/ccwcache.h Wed Feb 21 18:20:42 2001 +++ linux/include/asm-s390x/ccwcache.h Fri Mar 2 11:12:06 2001 @@ -59,7 +59,7 @@ #define CQR_STATUS_FILLED 0x01 /* request is ready to be preocessed */ #define CQR_STATUS_QUEUED 0x02 /* request is queued to be processed */ #define CQR_STATUS_IN_IO 0x03 /* request is currently in IO */ -#define CQR_STATUS_DONE 0x04 /* request is completed sucessfully */ +#define CQR_STATUS_DONE 0x04 /* request is completed successfully */ #define CQR_STATUS_ERROR 0x05 /* request is completed with error */ #define CQR_STATUS_FAILED 0x06 /* request is finally failed */ diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/dasd.h linux/include/asm-s390x/dasd.h --- v2.4.2/linux/include/asm-s390x/dasd.h Wed Feb 21 18:20:42 2001 +++ linux/include/asm-s390x/dasd.h Fri Mar 2 11:12:06 2001 @@ -203,7 +203,7 @@ typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr); typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr); -typedef int (*dasd_ck_id_fn_t) (dev_info_t *); +typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *); typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *); typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *); typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *); @@ -269,7 +269,7 @@ } dasd_profile_info_t; typedef struct dasd_device_t { - dev_info_t devinfo; + s390_dev_info_t devinfo; dasd_discipline_t *discipline; int level; int open_count; diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/lowcore.h linux/include/asm-s390x/lowcore.h --- v2.4.2/linux/include/asm-s390x/lowcore.h Wed Feb 21 18:20:42 2001 +++ linux/include/asm-s390x/lowcore.h Fri Mar 2 11:12:06 2001 @@ -116,7 +116,7 @@ __u8 pad3[0xc8-0xc4]; /* 0x0c4 */ __u32 stfl_fac_list; /* 0x0c8 */ __u8 pad4[0xe8-0xcc]; /* 0x0cc */ - __u32 mcck_interuption_code[2]; /* 0x0e8 */ + __u32 mcck_interruption_code[2]; /* 0x0e8 */ __u8 pad5[0xf4-0xf0]; /* 0x0f0 */ __u32 external_damage_code; /* 0x0f4 */ addr_t failing_storage_address; /* 0x0f8 */ diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/socket.h linux/include/asm-s390x/socket.h --- v2.4.2/linux/include/asm-s390x/socket.h Wed Feb 21 18:20:42 2001 +++ linux/include/asm-s390x/socket.h Fri Mar 2 11:12:06 2001 @@ -50,6 +50,7 @@ #define SO_PEERNAME 28 #define SO_TIMESTAMP 29 #define SCM_TIMESTAMP SO_TIMESTAMP +#define SO_ACCEPTCONN 30 /* Nast libc5 fixup - bletch */ #if defined(__KERNEL__) diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/unistd.h linux/include/asm-s390x/unistd.h --- v2.4.2/linux/include/asm-s390x/unistd.h Wed Feb 21 18:20:42 2001 +++ linux/include/asm-s390x/unistd.h Fri Mar 2 11:12:06 2001 @@ -330,7 +330,6 @@ static inline _syscall1(int,delete_module,const char *,name) static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf) -extern int sys_wait4(int, int *, int, struct rusage *); static inline pid_t waitpid(int pid, int * wait_stat, int flags) { return sys_wait4(pid, wait_stat, flags, NULL); diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h --- v2.4.2/linux/include/asm-sparc/smp.h Tue Oct 10 10:33:52 2000 +++ linux/include/asm-sparc/smp.h Fri Mar 2 11:30:15 2001 @@ -51,6 +51,7 @@ extern int smp_found_cpus; extern unsigned char boot_cpu_id; extern unsigned long cpu_present_map; +#define cpu_online_map cpu_present_map typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/asi.h linux/include/asm-sparc64/asi.h --- v2.4.2/linux/include/asm-sparc64/asi.h Fri Dec 13 01:37:41 1996 +++ linux/include/asm-sparc64/asi.h Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: asi.h,v 1.1 1996/11/20 12:59:45 davem Exp $ */ +/* $Id: asi.h,v 1.2 2001/03/01 21:28:37 davem Exp $ */ #ifndef _SPARC64_ASI_H #define _SPARC64_ASI_H @@ -23,19 +23,35 @@ #define ASI_PNFL 0x8a /* Primary, no fault, little endian */ #define ASI_SNFL 0x8b /* Secondary, no fault, little endian */ -/* SpitFire extended ASIs. */ +/* SpitFire and later extended ASIs. The "(III)" marker designates + * UltraSparc-III specific ASIs. + */ #define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ #define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-cachable, E-bit */ #define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian */ #define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-cachable, E-bit, little endian */ #define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ #define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, little endian */ +#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data status RAM diag */ +#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ +#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ +#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ +#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ +#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ +#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ +#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ +#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ +#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ +#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ #define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ +#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control Register */ #define ASI_DCACHE_DATA 0x46 /* Data cache data-ram diag access */ #define ASI_DCACHE_TAG 0x47 /* Data cache tag/valid ram diag access */ #define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ #define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ #define ASI_UPA_CONFIG 0x4a /* UPA config space */ +#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ +#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ #define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ #define ASI_AFSR 0x4c /* Async fault status register */ #define ASI_AFAR 0x4d /* Async fault address register */ @@ -55,16 +71,23 @@ #define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access register */ #define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read register */ #define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ +#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint register */ #define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag access */ #define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag access */ +#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram diag */ #define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag access */ #define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag access */ +#define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag */ #define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ #define ASI_BLK_AIUS 0x71 /* Secondary, user, block load/store */ +#define ASI_EC_DATA 0x74 /* (III) E-cache data staging register */ +#define ASI_EC_CTRL 0x75 /* (III) E-cache control register */ #define ASI_EC_W 0x76 /* E-cache diag write access */ #define ASI_UDB_ERROR_W 0x77 /* External UDB error registers write */ #define ASI_UDB_CONTROL_W 0x77 /* External UDB control registers write */ #define ASI_UDB_INTR_W 0x77 /* External UDB IRQ vector dispatch write */ +#define ASI_INTR_DATAN_W 0x77 /* (III) Outgoing irq vector data reg N */ +#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ #define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st */ #define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st */ #define ASI_EC_R 0x7e /* E-cache diag read access */ @@ -73,6 +96,7 @@ #define ASI_UDBH_CONTROL_R 0x7f /* External UDB control registers read hi */ #define ASI_UDBL_CONTROL_R 0x7f /* External UDB control registers read low */ #define ASI_UDB_INTR_R 0x7f /* External UDB IRQ vector dispatch read */ +#define ASI_INTR_DATAN_R 0x7f /* (III) Incoming irq vector data reg N */ #define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ #define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ #define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/dcr.h linux/include/asm-sparc64/dcr.h --- v2.4.2/linux/include/asm-sparc64/dcr.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/dcr.h Tue Mar 6 22:44:16 2001 @@ -0,0 +1,11 @@ +/* $Id: dcr.h,v 1.3 2001/03/01 23:23:33 davem Exp $ */ +#ifndef _SPARC64_DCR_H +#define _SPARC64_DCR_H + +/* UltraSparc-III Dispatch Control Register, ASR 0x12 */ +#define DCR_BPE 0x0000000000000020 /* Branch Predict Enable */ +#define DCR_RPE 0x0000000000000010 /* Return Address Prediction Enable*/ +#define DCR_SI 0x0000000000000008 /* Single Instruction Disable */ +#define DCR_MS 0x0000000000000001 /* Multi-Scalar dispatch */ + +#endif /* _SPARC64_DCR_H */ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/dcu.h linux/include/asm-sparc64/dcu.h --- v2.4.2/linux/include/asm-sparc64/dcu.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/dcu.h Tue Mar 6 22:44:16 2001 @@ -0,0 +1,26 @@ +/* $Id: dcu.h,v 1.2 2001/03/01 23:23:33 davem Exp $ */ +#ifndef _SPARC64_DCU_H +#define _SPARC64_DCU_H + +/* UltraSparc-III Data Cache Unit Control Register */ +#define DCU_CP 0x0002000000000000 /* Physical Cache Enable w/o mmu*/ +#define DCU_CV 0x0001000000000000 /* Virtual Cache Enable w/o mmu */ +#define DCU_ME 0x0000800000000000 /* NC-store Merging Enable */ +#define DCU_RE 0x0000400000000000 /* RAW bypass Enable */ +#define DCU_PE 0x0000200000000000 /* PCache Enable */ +#define DCU_HPE 0x0000100000000000 /* HW prefetch Enable */ +#define DCU_SPE 0x0000080000000000 /* SW prefetch Enable */ +#define DCU_SL 0x0000040000000000 /* Secondary load steering Enab */ +#define DCU_WE 0x0000020000000000 /* WCache enable */ +#define DCU_PM 0x000001fe00000000 /* PA Watchpoint Byte Mask */ +#define DCU_VM 0x00000001fe000000 /* VA Watchpoint Byte Mask */ +#define DCU_PR 0x0000000001000000 /* PA Watchpoint Read Enable */ +#define DCU_PW 0x0000000000800000 /* PA Watchpoint Write Enable */ +#define DCU_VR 0x0000000000400000 /* VA Watchpoint Read Enable */ +#define DCU_VW 0x0000000000200000 /* VA Watchpoint Write Enable */ +#define DCU_DM 0x0000000000000008 /* DMMU Enable */ +#define DCU_IM 0x0000000000000004 /* IMMU Enable */ +#define DCU_DC 0x0000000000000002 /* Data Cache Enable */ +#define DCU_IC 0x0000000000000001 /* Instruction Cache Enable */ + +#endif /* _SPARC64_DCU_H */ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/pbm.h linux/include/asm-sparc64/pbm.h --- v2.4.2/linux/include/asm-sparc64/pbm.h Sat Feb 3 19:51:32 2001 +++ linux/include/asm-sparc64/pbm.h Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pbm.h,v 1.23 2001/01/11 16:26:45 davem Exp $ +/* $Id: pbm.h,v 1.25 2001/02/28 03:28:55 davem Exp $ * pbm.h: UltraSparc PCI controller software state. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -144,6 +144,9 @@ struct resource io_space; struct resource mem_space; + /* Base of PCI Config space, can be per-PBM or shared. */ + unsigned long config_space; + /* State of 66MHz capabilities on this PBM. */ int is_66mhz_capable; int all_devs_66mhz; @@ -164,11 +167,8 @@ /* List of all PCI controllers. */ struct pci_controller_info *next; - /* Physical address base of controller registers - * and PCI config space. - */ + /* Physical address base of controller registers. */ unsigned long controller_regs; - unsigned long config_space; /* Opaque 32-bit system bus Port ID. */ u32 portid; @@ -184,7 +184,7 @@ /* Operations which are controller specific. */ void (*scan_bus)(struct pci_controller_info *); - unsigned int (*irq_build)(struct pci_controller_info *, struct pci_dev *, unsigned int); + unsigned int (*irq_build)(struct pci_pbm_info *, struct pci_dev *, unsigned int); void (*base_address_update)(struct pci_dev *, int); void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *); diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h --- v2.4.2/linux/include/asm-sparc64/pgalloc.h Mon Dec 11 12:37:03 2000 +++ linux/include/asm-sparc64/pgalloc.h Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pgalloc.h,v 1.14 2000/12/09 04:15:24 anton Exp $ */ +/* $Id: pgalloc.h,v 1.15 2001/03/04 18:31:00 davem Exp $ */ #ifndef _SPARC64_PGALLOC_H #define _SPARC64_PGALLOC_H @@ -93,14 +93,14 @@ #endif /* ! CONFIG_SMP */ -/* This will change for Cheetah and later chips. */ -#define VPTE_BASE 0xfffffffe00000000 +#define VPTE_BASE_SPITFIRE 0xfffffffe00000000 +#define VPTE_BASE_CHEETAH 0xffe0000000000000 extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) { /* Note the signed type. */ - long s = start, e = end; + long s = start, e = end, vpte_base; if (s > e) /* Nobody should call us with start below VM hole and end above. See if it is really true. */ @@ -110,9 +110,12 @@ s &= PMD_MASK; e = (e + PMD_SIZE - 1) & PMD_MASK; #endif + vpte_base = (tlb_type == spitfire ? + VPTE_BASE_SPITFIRE : + VPTE_BASE_CHEETAH); flush_tlb_range(mm, - VPTE_BASE + (s >> (PAGE_SHIFT - 3)), - VPTE_BASE + (e >> (PAGE_SHIFT - 3))); + vpte_base + (s >> (PAGE_SHIFT - 3)), + vpte_base + (e >> (PAGE_SHIFT - 3))); } /* Page table allocation/freeing. */ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.4.2/linux/include/asm-sparc64/pgtable.h Thu Nov 9 15:57:41 2000 +++ linux/include/asm-sparc64/pgtable.h Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.135 2000/11/08 04:49:24 davem Exp $ +/* $Id: pgtable.h,v 1.137 2001/03/02 03:12:01 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -70,7 +70,7 @@ #endif /* !(__ASSEMBLY__) */ -/* SpitFire TTE bits. */ +/* Spitfire/Cheetah TTE bits. */ #define _PAGE_VALID 0x8000000000000000 /* Valid TTE */ #define _PAGE_R 0x8000000000000000 /* Used to keep ref bit up to date */ #define _PAGE_SZ4MB 0x6000000000000000 /* 4MB Page */ @@ -79,10 +79,10 @@ #define _PAGE_SZ8K 0x0000000000000000 /* 8K Page */ #define _PAGE_NFO 0x1000000000000000 /* No Fault Only */ #define _PAGE_IE 0x0800000000000000 /* Invert Endianness */ -#define _PAGE_SOFT2 0x07FC000000000000 /* Second set of software bits */ -#define _PAGE_DIAG 0x0003FE0000000000 /* Diagnostic TTE bits */ -#define _PAGE_PADDR 0x000001FFFFFFE000 /* Physical Address bits [40:13] */ -#define _PAGE_SOFT 0x0000000000001F80 /* First set of software bits */ +#define _PAGE_SN 0x0000800000000000 /* Snoop */ +#define _PAGE_PADDR_SF 0x000001FFFFFFE000 /* (Spitfire) Phys Address [40:13] */ +#define _PAGE_PADDR 0x000007FFFFFFE000 /* (Cheetah) Phys Address [42:13] */ +#define _PAGE_SOFT 0x0000000000001F80 /* Software bits */ #define _PAGE_L 0x0000000000000040 /* Locked TTE */ #define _PAGE_CP 0x0000000000000020 /* Cacheable in Physical Cache */ #define _PAGE_CV 0x0000000000000010 /* Cacheable in Virtual Cache */ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h --- v2.4.2/linux/include/asm-sparc64/smp.h Tue Oct 3 09:24:41 2000 +++ linux/include/asm-sparc64/smp.h Fri Mar 2 11:30:15 2001 @@ -60,6 +60,7 @@ extern unsigned char boot_cpu_id; extern unsigned long cpu_present_map; +#define cpu_online_map cpu_present_map /* * General functions that each host system must provide. diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h --- v2.4.2/linux/include/asm-sparc64/spitfire.h Tue Oct 10 10:33:52 2000 +++ linux/include/asm-sparc64/spitfire.h Tue Mar 6 22:44:16 2001 @@ -1,4 +1,4 @@ -/* $Id: spitfire.h,v 1.10 2000/10/06 13:10:29 anton Exp $ +/* $Id: spitfire.h,v 1.11 2001/03/03 10:34:45 davem Exp $ * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -29,6 +29,21 @@ #ifndef __ASSEMBLY__ +enum ultra_tlb_layout { + spitfire = 0, + cheetah = 1 +}; + +extern enum ultra_tlb_layout tlb_type; + +#define SPITFIRE_HIGHEST_LOCKED_TLBENT (64 - 1) +#define CHEETAH_HIGHEST_LOCKED_TLBENT (16 - 1) + +#define sparc64_highest_locked_tlbent() \ + (tlb_type == spitfire ? \ + SPITFIRE_HIGHEST_LOCKED_TLBENT : \ + CHEETAH_HIGHEST_LOCKED_TLBENT) + extern __inline__ unsigned long spitfire_get_isfsr(void) { unsigned long ret; @@ -140,6 +155,10 @@ __asm__ __volatile__("ldxa [%1] %2, %0" : "=r" (data) : "r" (entry << 3), "i" (ASI_DTLB_DATA_ACCESS)); + + /* Clear TTE diag bits. */ + data &= ~0x0003fe0000000000UL; + return data; } @@ -168,6 +187,10 @@ __asm__ __volatile__("ldxa [%1] %2, %0" : "=r" (data) : "r" (entry << 3), "i" (ASI_ITLB_DATA_ACCESS)); + + /* Clear TTE diag bits. */ + data &= ~0x0003fe0000000000UL; + return data; } @@ -275,6 +298,157 @@ __asm__ __volatile__("stxa %%g0, [%0] %1" : /* No outputs */ : "r" (page | 0x20), "i" (ASI_IMMU_DEMAP)); +} + +/* Cheetah has "all non-locked" tlb flushes. */ +extern __inline__ void cheetah_flush_dtlb_all(void) +{ + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* No outputs */ + : "r" (0x80), "i" (ASI_DMMU_DEMAP)); +} + +extern __inline__ void cheetah_flush_itlb_all(void) +{ + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* No outputs */ + : "r" (0x80), "i" (ASI_IMMU_DEMAP)); +} + +/* Cheetah has a 4-tlb layout so direct access is a bit different. + * The first two TLBs are fully assosciative, hold 16 entries, and are + * used only for locked and >8K sized translations. One exists for + * data accesses and one for instruction accesses. + * + * The third TLB is for data accesses to 8K non-locked translations, is + * 2 way assosciative, and holds 512 entries. The fourth TLB is for + * instruction accesses to 8K non-locked translations, is 2 way + * assosciative, and holds 128 entries. + */ +extern __inline__ unsigned long cheetah_get_ldtlb_data(int entry) +{ + unsigned long data; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (data) + : "r" ((0 << 16) | (entry << 3)), + "i" (ASI_DTLB_DATA_ACCESS)); + + return data; +} + +extern __inline__ unsigned long cheetah_get_litlb_data(int entry) +{ + unsigned long data; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (data) + : "r" ((0 << 16) | (entry << 3)), + "i" (ASI_ITLB_DATA_ACCESS)); + + return data; +} + +extern __inline__ unsigned long cheetah_get_ldtlb_tag(int entry) +{ + unsigned long tag; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (tag) + : "r" ((0 << 16) | (entry << 3)), + "i" (ASI_DTLB_TAG_READ)); + + return tag; +} + +extern __inline__ unsigned long cheetah_get_litlb_tag(int entry) +{ + unsigned long tag; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (tag) + : "r" ((0 << 16) | (entry << 3)), + "i" (ASI_ITLB_TAG_READ)); + + return tag; +} + +extern __inline__ void cheetah_put_ldtlb_data(int entry, unsigned long data) +{ + __asm__ __volatile__("stxa %0, [%1] %2" + : /* No outputs */ + : "r" (data), + "r" ((0 << 16) | (entry << 3)), + "i" (ASI_DTLB_DATA_ACCESS)); +} + +extern __inline__ void cheetah_put_litlb_data(int entry, unsigned long data) +{ + __asm__ __volatile__("stxa %0, [%1] %2" + : /* No outputs */ + : "r" (data), + "r" ((0 << 16) | (entry << 3)), + "i" (ASI_ITLB_DATA_ACCESS)); +} + +extern __inline__ unsigned long cheetah_get_dtlb_data(int entry) +{ + unsigned long data; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (data) + : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS)); + + return data; +} + +extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry) +{ + unsigned long tag; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (tag) + : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ)); + return tag; +} + +extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data) +{ + __asm__ __volatile__("stxa %0, [%1] %2" + : /* No outputs */ + : "r" (data), + "r" ((2 << 16) | (entry << 3)), + "i" (ASI_DTLB_DATA_ACCESS)); +} + +extern __inline__ unsigned long cheetah_get_itlb_data(int entry) +{ + unsigned long data; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (data) + : "r" ((2 << 16) | (entry << 3)), + "i" (ASI_ITLB_DATA_ACCESS)); + + return data; +} + +extern __inline__ unsigned long cheetah_get_itlb_tag(int entry) +{ + unsigned long tag; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (tag) + : "r" ((2 << 16) | (entry << 3)), "i" (ASI_ITLB_TAG_READ)); + return tag; +} + +extern __inline__ void cheetah_put_itlb_data(int entry, unsigned long data) +{ + __asm__ __volatile__("stxa %0, [%1] %2" + : /* No outputs */ + : "r" (data), "r" ((2 << 16) | (entry << 3)), + "i" (ASI_ITLB_DATA_ACCESS)); } #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.4.2/linux/include/linux/802_11.h linux/include/linux/802_11.h --- v2.4.2/linux/include/linux/802_11.h Mon Dec 11 13:00:51 2000 +++ linux/include/linux/802_11.h Tue Mar 6 19:28:33 2001 @@ -188,4 +188,4 @@ } -#endif \ No newline at end of file +#endif diff -u --recursive --new-file v2.4.2/linux/include/linux/blkdev.h linux/include/linux/blkdev.h --- v2.4.2/linux/include/linux/blkdev.h Sat Feb 3 19:51:32 2001 +++ linux/include/linux/blkdev.h Sun Mar 11 13:49:37 2001 @@ -180,7 +180,7 @@ extern atomic_t queued_sectors; #define MAX_SEGMENTS 128 -#define MAX_SECTORS (MAX_SEGMENTS*8) +#define MAX_SECTORS 255 #define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK) diff -u --recursive --new-file v2.4.2/linux/include/linux/dcache.h linux/include/linux/dcache.h --- v2.4.2/linux/include/linux/dcache.h Wed Feb 21 18:20:45 2001 +++ linux/include/linux/dcache.h Wed Mar 7 16:56:35 2001 @@ -217,7 +217,7 @@ extern struct dentry * d_lookup(struct dentry *, struct qstr *); /* validate "insecure" dentry pointer */ -extern int d_validate(struct dentry *, struct dentry *, unsigned int, unsigned int); +extern int d_validate(struct dentry *, struct dentry *); extern char * __d_path(struct dentry *, struct vfsmount *, struct dentry *, struct vfsmount *, char *, int); diff -u --recursive --new-file v2.4.2/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.4.2/linux/include/linux/fs.h Wed Feb 21 18:20:45 2001 +++ linux/include/linux/fs.h Wed Mar 7 16:56:35 2001 @@ -244,7 +244,7 @@ struct buffer_head *b_reqnext; /* request queue */ struct buffer_head **b_pprev; /* doubly linked list of hash-queue */ - char * b_data; /* pointer to data block (512 byte) */ + char * b_data; /* pointer to data block */ struct page *b_page; /* the page this bh is mapped to */ void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */ void *b_private; /* reserved for b_end_io */ @@ -381,6 +381,7 @@ struct vm_area_struct *i_mmap; /* list of private mappings */ struct vm_area_struct *i_mmap_shared; /* list of shared mappings */ spinlock_t i_shared_lock; /* and spinlock protecting it */ + int gfp_mask; /* how to allocate the pages */ }; struct block_device { @@ -504,6 +505,8 @@ extern int init_private_file(struct file *, struct dentry *, int); +#define MAX_NON_LFS ((1UL<<31) - 1) + #define FL_POSIX 1 #define FL_FLOCK 2 #define FL_BROKEN 4 /* broken flock() emulation */ @@ -651,6 +654,7 @@ unsigned char s_blocksize_bits; unsigned char s_lock; unsigned char s_dirt; + unsigned long long s_maxbytes; /* Max file size */ struct file_system_type *s_type; struct super_operations *s_op; struct dquot_operations *dq_op; diff -u --recursive --new-file v2.4.2/linux/include/linux/genhd.h linux/include/linux/genhd.h --- v2.4.2/linux/include/linux/genhd.h Thu Jan 4 14:50:47 2001 +++ linux/include/linux/genhd.h Wed Mar 7 16:56:35 2001 @@ -223,6 +223,11 @@ #endif /* CONFIG_UNIXWARE_DISKLABEL */ +#ifdef CONFIG_MINIX_SUBPARTITION +# define MINIX_PARTITION 0x81 /* Minix Partition ID */ +# define MINIX_NR_SUBPARTITIONS 4 +#endif /* CONFIG_MINIX_SUBPARTITION */ + #ifdef __KERNEL__ extern struct gendisk *gendisk_head; /* linked list of disks */ diff -u --recursive --new-file v2.4.2/linux/include/linux/hdlc.h linux/include/linux/hdlc.h --- v2.4.2/linux/include/linux/hdlc.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/hdlc.h Tue Mar 6 19:44:37 2001 @@ -0,0 +1,336 @@ +/* + * Generic HDLC support routines for Linux + * + * Copyright (C) 1999, 2000 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __HDLC_H +#define __HDLC_H + +/* Ioctls - to be changed */ +#define HDLCGSLOTMAP (0x89F4) /* E1/T1 slot bitmap */ +#define HDLCGCLOCK (0x89F5) /* clock sources */ +#define HDLCGCLOCKRATE (0x89F6) /* clock rate */ +#define HDLCGMODE (0x89F7) /* internal to hdlc.c - protocol used */ +#define HDLCGLINE (0x89F8) /* physical interface */ +#define HDLCSSLOTMAP (0x89F9) +#define HDLCSCLOCK (0x89FA) +#define HDLCSCLOCKRATE (0x89FB) +#define HDLCSMODE (0x89FC) /* internal to hdlc.c - select protocol */ +#define HDLCPVC (0x89FD) /* internal to hdlc.c - create/delete PVC */ +#define HDLCSLINE (0x89FE) +#define HDLCRUN (0x89FF) /* Download firmware and run board */ + +/* Modes */ +#define MODE_NONE 0x00000000 /* Not initialized */ +#define MODE_DCE 0x00000080 /* DCE */ +#define MODE_HDLC 0x00000100 /* Raw HDLC frames */ +#define MODE_CISCO 0x00000200 +#define MODE_PPP 0x00000400 +#define MODE_FR 0x00000800 /* Any LMI */ +#define MODE_FR_ANSI 0x00000801 +#define MODE_FR_CCITT 0x00000802 +#define MODE_X25 0x00001000 +#define MODE_MASK 0x0000FF00 +#define MODE_SOFT 0x80000000 /* Driver modes, using hardware HDLC */ + +/* Lines */ +#define LINE_DEFAULT 0x00000000 +#define LINE_V35 0x00000001 +#define LINE_RS232 0x00000002 +#define LINE_X21 0x00000003 +#define LINE_T1 0x00000004 +#define LINE_E1 0x00000005 +#define LINE_MASK 0x000000FF +#define LINE_LOOPBACK 0x80000000 /* On-card loopback */ + +#define CLOCK_EXT 0 /* External TX and RX clock - DTE */ +#define CLOCK_INT 1 /* Internal TX and RX clock - DCE */ +#define CLOCK_TXINT 2 /* Internal TX and external RX clock */ +#define CLOCK_TXFROMRX 3 /* TX clock derived from external RX clock */ + + +#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ +#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */ + +#ifdef __KERNEL__ + +#include +#include +#include + +#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */ + +#define LINK_STATE_RELIABLE 0x01 +#define LINK_STATE_REQUEST 0x02 /* full stat sent (DCE) / req pending (DTE) */ +#define LINK_STATE_CHANGED 0x04 /* change in PVCs state, send full report */ +#define LINK_STATE_FULLREP_SENT 0x08 /* full report sent */ + +#define PVC_STATE_NEW 0x01 +#define PVC_STATE_ACTIVE 0x02 +#define PVC_STATE_FECN 0x08 /* FECN condition */ +#define PVC_STATE_BECN 0x10 /* BECN condition */ + + +#define FR_UI 0x03 +#define FR_PAD 0x00 + +#define NLPID_IP 0xCC +#define NLPID_IPV6 0x8E +#define NLPID_SNAP 0x80 +#define NLPID_PAD 0x00 +#define NLPID_Q933 0x08 + + +#define LMI_DLCI 0 /* LMI DLCI */ +#define LMI_PROTO 0x08 +#define LMI_CALLREF 0x00 /* Call Reference */ +#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */ +#define LMI_REPTYPE 1 /* report type */ +#define LMI_CCITT_REPTYPE 0x51 +#define LMI_ALIVE 3 /* keep alive */ +#define LMI_CCITT_ALIVE 0x53 +#define LMI_PVCSTAT 7 /* pvc status */ +#define LMI_CCITT_PVCSTAT 0x57 +#define LMI_FULLREP 0 /* full report */ +#define LMI_INTEGRITY 1 /* link integrity report */ +#define LMI_SINGLE 2 /* single pvc report */ +#define LMI_STATUS_ENQUIRY 0x75 +#define LMI_STATUS 0x7D /* reply */ + +#define LMI_REPT_LEN 1 /* report type element length */ +#define LMI_INTEG_LEN 2 /* link integrity element length */ + +#define LMI_LENGTH 13 /* standard LMI frame length */ +#define LMI_ANSI_LENGTH 14 + + + +typedef struct { + unsigned ea1 : 1; + unsigned cr : 1; + unsigned dlcih: 6; + + unsigned ea2 : 1; + unsigned de : 1; + unsigned becn : 1; + unsigned fecn : 1; + unsigned dlcil: 4; +}__attribute__ ((packed)) fr_hdr; + + + +typedef struct { /* Used in Cisco and PPP mode */ + u8 address; + u8 control; + u16 protocol; +}__attribute__ ((packed)) hdlc_header; + + + +typedef struct { + u32 type; /* code */ + u32 par1; + u32 par2; + u16 rel; /* reliability */ + u32 time; +}__attribute__ ((packed)) cisco_packet; +#define CISCO_PACKET_LEN 18 +#define CISCO_BIG_PACKET_LEN 20 + + + +typedef struct pvc_device_struct { + struct net_device netdev; /* PVC net device - must be first */ + struct net_device_stats stats; + struct hdlc_device_struct *master; + struct pvc_device_struct *next; + + u8 state; + u8 newstate; +}pvc_device; + + + +typedef struct { + u32 last_errors; /* last errors bit list */ + int last_poll; /* ! */ + u8 T391; /* ! link integrity verification polling timer */ + u8 T392; /* ! polling verification timer */ + u8 N391; /* full status polling counter */ + u8 N392; /* error threshold */ + u8 N393; /* monitored events count */ + u8 N391cnt; + + u8 state; /* ! */ + u32 txseq; /* ! TX sequence number - Cisco uses 4 bytes */ + u32 rxseq; /* ! RX sequence number */ +}fr_lmi; /* ! means used in Cisco HDLC as well */ + + +typedef struct hdlc_device_struct { + /* to be initialized by hardware driver: */ + struct net_device netdev; /* master net device - must be first */ + struct net_device_stats stats; + + struct ppp_device pppdev; + struct ppp_device *syncppp_ptr; + + /* set_mode may be NULL if HDLC-only board */ + int (*set_mode)(struct hdlc_device_struct *hdlc, int mode); + int (*open)(struct hdlc_device_struct *hdlc); + void (*close)(struct hdlc_device_struct *hdlc); + int (*xmit)(struct hdlc_device_struct *hdlc, struct sk_buff *skb); + int (*ioctl)(struct hdlc_device_struct *hdlc, struct ifreq *ifr, + int cmd); + + /* Only in "hardware" FR modes etc. - may be NULL */ + int (*create_pvc)(pvc_device *pvc); + void (*destroy_pvc)(pvc_device *pvc); + int (*open_pvc)(pvc_device *pvc); + void (*close_pvc)(pvc_device *pvc); + + /* for hdlc.c internal use only */ + pvc_device *first_pvc; + u16 pvc_count; + int mode; + + struct timer_list timer; + fr_lmi lmi; +}hdlc_device; + + +int register_hdlc_device(hdlc_device *hdlc); +void unregister_hdlc_device(hdlc_device *hdlc); +void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb); + + +extern __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc) +{ + return &hdlc->netdev; +} + + +extern __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev) +{ + return (hdlc_device*)dev; +} + + +extern __inline__ struct net_device* pvc_to_dev(pvc_device *pvc) +{ + return &pvc->netdev; +} + + +extern __inline__ pvc_device* dev_to_pvc(struct net_device *dev) +{ + return (pvc_device*)dev; +} + + +extern __inline__ const char *hdlc_to_name(hdlc_device *hdlc) +{ + return hdlc_to_dev(hdlc)->name; +} + + +extern __inline__ const char *pvc_to_name(pvc_device *pvc) +{ + return pvc_to_dev(pvc)->name; +} + + +extern __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state) +{ + *state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW); + if (status[2] & 0x08) + *state |= PVC_STATE_NEW; + else if (status[2] & 0x02) + *state |= PVC_STATE_ACTIVE; + + return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3); +} + + +extern __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status, + u8 state) +{ + status[0] = (dlci>>4) & 0x3F; + status[1] = ((dlci<<3) & 0x78) | 0x80; + status[2] = 0x80; + + if (state & PVC_STATE_NEW) + status[2] |= 0x08; + else if (state & PVC_STATE_ACTIVE) + status[2] |= 0x02; +} + + + +extern __inline__ u16 netdev_dlci(struct net_device *dev) +{ + return ntohs(*(u16*)dev->dev_addr); +} + + + +extern __inline__ u16 q922_to_dlci(u8 *hdr) +{ + return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4); +} + + + +extern __inline__ void dlci_to_q922(u8 *hdr, u16 dlci) +{ + hdr[0] = (dlci>>2) & 0xFC; + hdr[1] = ((dlci<<4) & 0xF0) | 0x01; +} + + + +extern __inline__ int mode_is(hdlc_device *hdlc, int mask) +{ + return (hdlc->mode & mask) == mask; +} + + + +extern __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) +{ + pvc_device *pvc=hdlc->first_pvc; + + while (pvc) { + if (netdev_dlci(&pvc->netdev) == dlci) + return pvc; + pvc=pvc->next; + } + + return NULL; +} + + + +extern __inline__ void debug_frame(const struct sk_buff *skb) +{ + int i; + + for (i=0; ilen; i++) { + if (i == 100) { + printk("...\n"); + return; + } + printk(" %02X", skb->data[i]); + } + printk("\n"); +} + + +#endif /* __KERNEL */ +#endif /* __HDLC_H */ diff -u --recursive --new-file v2.4.2/linux/include/linux/hysdn_if.h linux/include/linux/hysdn_if.h --- v2.4.2/linux/include/linux/hysdn_if.h Tue Feb 15 11:40:43 2000 +++ linux/include/linux/hysdn_if.h Tue Mar 6 19:44:37 2001 @@ -30,7 +30,7 @@ /****************/ /* error values */ /****************/ -#define ERR_NONE 0 /* no error occured */ +#define ERR_NONE 0 /* no error occurred */ #define ERR_ALREADY_BOOT 1000 /* we are already booting */ #define EPOF_BAD_MAGIC 1001 /* bad magic in POF header */ #define ERR_BOARD_DPRAM 1002 /* board DPRAM failed */ diff -u --recursive --new-file v2.4.2/linux/include/linux/i2c.h linux/include/linux/i2c.h --- v2.4.2/linux/include/linux/i2c.h Fri Dec 29 14:35:47 2000 +++ linux/include/linux/i2c.h Tue Mar 6 19:44:37 2001 @@ -454,7 +454,7 @@ * corresponding header files. */ /* -> bit-adapter specific ioctls */ -#define I2C_RETRIES 0x0701 /* number times a device adress should */ +#define I2C_RETRIES 0x0701 /* number times a device address should */ /* be polled when not acknowledging */ #define I2C_TIMEOUT 0x0702 /* set timeout - call with int */ @@ -471,7 +471,7 @@ #define I2C_FUNCS 0x0705 /* Get the adapter functionality */ #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ #if 0 -#define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific adress */ +#define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific address */ #endif #define I2C_SMBUS 0x0720 /* SMBus-level access */ diff -u --recursive --new-file v2.4.2/linux/include/linux/if_bonding.h linux/include/linux/if_bonding.h --- v2.4.2/linux/include/linux/if_bonding.h Sun Feb 27 18:45:10 2000 +++ linux/include/linux/if_bonding.h Tue Mar 6 19:44:37 2001 @@ -9,7 +9,7 @@ * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov * * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. + * of the GNU General Public License, incorporated herein by reference. * */ diff -u --recursive --new-file v2.4.2/linux/include/linux/if_eql.h linux/include/linux/if_eql.h --- v2.4.2/linux/include/linux/if_eql.h Mon Dec 11 13:02:12 2000 +++ linux/include/linux/if_eql.h Tue Mar 6 19:44:37 2001 @@ -6,7 +6,7 @@ * * * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. + * of the GNU General Public License, incorporated herein by reference. * * The author may be reached as simon@ncm.com, or C/O * NCM diff -u --recursive --new-file v2.4.2/linux/include/linux/if_frad.h linux/include/linux/if_frad.h --- v2.4.2/linux/include/linux/if_frad.h Mon Dec 11 13:00:06 2000 +++ linux/include/linux/if_frad.h Tue Mar 6 19:28:33 2001 @@ -192,9 +192,9 @@ int register_frad(const char *name); int unregister_frad(const char *name); -int (*dlci_ioctl_hook)(unsigned int, void *); +extern int (*dlci_ioctl_hook)(unsigned int, void *); -#endif __KERNEL__ +#endif /* __KERNEL__ */ #endif /* CONFIG_DLCI || CONFIG_DLCI_MODULE */ diff -u --recursive --new-file v2.4.2/linux/include/linux/init.h linux/include/linux/init.h --- v2.4.2/linux/include/linux/init.h Thu Jan 4 14:50:46 2001 +++ linux/include/linux/init.h Wed Mar 7 16:56:35 2001 @@ -86,7 +86,27 @@ #define __FINIT .previous #define __INITDATA .section ".data.init","aw" +/** + * module_init() - driver initialization entry point + * @x: function to be run at kernel boot time or module insertion + * + * module_init() will add the driver initialization routine in + * the "__initcall.int" code segment if the driver is checked as + * "y" or static, or else it will wrap the driver initialization + * routine with init_module() which is used by insmod and + * modprobe when the driver is used as a module. + */ #define module_init(x) __initcall(x); + +/** + * module_exit() - driver exit entry point + * @x: function to be run when driver is removed + * + * module_exit() will wrap the driver clean-up code + * with cleanup_module() when used with rmmod when + * the driver is a module. If the driver is statically + * compiled into the kernel, module_exit() has no effect. + */ #define module_exit(x) __exitcall(x); #else diff -u --recursive --new-file v2.4.2/linux/include/linux/loop.h linux/include/linux/loop.h --- v2.4.2/linux/include/linux/loop.h Mon Dec 11 12:50:30 2000 +++ linux/include/linux/loop.h Tue Mar 6 19:35:36 2001 @@ -9,17 +9,23 @@ * Written by Theodore Ts'o, 3/29/93. * * Copyright 1993 by Theodore Ts'o. Redistribution of this file is - * permitted under the GNU Public License. + * permitted under the GNU General Public License. */ #define LO_NAME_SIZE 64 #define LO_KEY_SIZE 32 #ifdef __KERNEL__ - + +/* Possible states of device */ +enum { + Lo_unbound, + Lo_bound, + Lo_rundown, +}; + struct loop_device { int lo_number; - struct dentry *lo_dentry; int lo_refcnt; kdev_t lo_device; int lo_offset; @@ -39,19 +45,38 @@ struct file * lo_backing_file; void *key_data; char key_reserved[48]; /* for use by the filter modules */ + + int old_gfp_mask; + + spinlock_t lo_lock; + struct buffer_head *lo_bh; + struct buffer_head *lo_bhtail; + int lo_state; + struct semaphore lo_sem; + struct semaphore lo_ctl_mutex; + struct semaphore lo_bh_mutex; + atomic_t lo_pending; }; typedef int (* transfer_proc_t)(struct loop_device *, int cmd, char *raw_buf, char *loop_buf, int size, int real_block); +extern inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf, + char *lbuf, int size, int rblock) +{ + if (!lo->transfer) + return 0; + + return lo->transfer(lo, cmd, rbuf, lbuf, size, rblock); +} #endif /* __KERNEL__ */ /* * Loop flags */ -#define LO_FLAGS_DO_BMAP 0x00000001 -#define LO_FLAGS_READ_ONLY 0x00000002 +#define LO_FLAGS_DO_BMAP 1 +#define LO_FLAGS_READ_ONLY 2 /* * Note that this structure gets the wrong offsets when directly used @@ -102,9 +127,8 @@ /* Support for loadable transfer modules */ struct loop_func_table { int number; /* filter type */ - int (*transfer)(struct loop_device *lo, int cmd, - char *raw_buf, char *loop_buf, int size, - int real_block); + int (*transfer)(struct loop_device *lo, int cmd, char *raw_buf, + char *loop_buf, int size, int real_block); int (*init)(struct loop_device *, struct loop_info *); /* release is called from loop_unregister_transfer or clr_fd */ int (*release)(struct loop_device *); diff -u --recursive --new-file v2.4.2/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.4.2/linux/include/linux/mm.h Wed Feb 21 18:20:45 2001 +++ linux/include/linux/mm.h Wed Mar 7 16:56:35 2001 @@ -481,11 +481,6 @@ #define GFP_DMA __GFP_DMA -/* Flag - indicates that the buffer can be taken from high memory which is not - permanently mapped by the kernel */ - -#define GFP_HIGHMEM __GFP_HIGHMEM - /* vma is the first one with address < vma->vm_end, * and even address < vma->vm_start. Have to extend vma. */ static inline int expand_stack(struct vm_area_struct * vma, unsigned long address) diff -u --recursive --new-file v2.4.2/linux/include/linux/mmzone.h linux/include/linux/mmzone.h --- v2.4.2/linux/include/linux/mmzone.h Thu Jan 4 14:50:46 2001 +++ linux/include/linux/mmzone.h Mon Mar 12 15:21:07 2001 @@ -21,6 +21,14 @@ struct pglist_data; +/* + * On machines where it is needed (eg PCs) we divide physical memory + * into multiple physical zones. On a PC we have 3 zones: + * + * ZONE_DMA < 16 MB ISA DMA capable memory + * ZONE_NORMAL 16-896 MB direct mapped by the kernel + * ZONE_HIGHMEM > 896 MB only page cache and user processes + */ typedef struct zone_struct { /* * Commonly accessed fields: @@ -75,6 +83,17 @@ #define NR_GFPINDEX 0x100 +/* + * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM + * (mostly NUMA machines?) to denote a higher-level memory zone than the + * zone_struct denotes. + * + * On NUMA machines, each NUMA node would have a pg_data_t to describe + * it's memory layout. + * + * XXX: we need to move the global memory statistics (active_list, ...) + * into the pg_data_t to properly support NUMA. + */ struct bootmem_data; typedef struct pglist_data { zone_t node_zones[MAX_NR_ZONES]; diff -u --recursive --new-file v2.4.2/linux/include/linux/n_r3964.h linux/include/linux/n_r3964.h --- v2.4.2/linux/include/linux/n_r3964.h Mon Dec 11 12:52:22 2000 +++ linux/include/linux/n_r3964.h Tue Mar 6 19:44:37 2001 @@ -7,7 +7,7 @@ * http://www.pap-philips.de * ----------------------------------------------------------- * This software may be used and distributed according to the terms of - * the GNU Public License, incorporated herein by reference. + * the GNU General Public License, incorporated herein by reference. * * Author: * L. Haag diff -u --recursive --new-file v2.4.2/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.4.2/linux/include/linux/netdevice.h Thu Jan 4 14:51:20 2001 +++ linux/include/linux/netdevice.h Wed Mar 7 16:56:48 2001 @@ -630,7 +630,6 @@ extern void tr_setup(struct net_device *dev); extern void fc_setup(struct net_device *dev); extern void fc_freedev(struct net_device *dev); -extern int ether_config(struct net_device *dev, struct ifmap *map); /* Support for loadable net-drivers */ extern int register_netdev(struct net_device *dev); extern void unregister_netdev(struct net_device *dev); diff -u --recursive --new-file v2.4.2/linux/include/linux/netfilter_ipv4/ipt_TCPMSS.h linux/include/linux/netfilter_ipv4/ipt_TCPMSS.h --- v2.4.2/linux/include/linux/netfilter_ipv4/ipt_TCPMSS.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ipt_TCPMSS.h Tue Mar 6 22:44:16 2001 @@ -0,0 +1,10 @@ +#ifndef _IPT_TCPMSS_H +#define _IPT_TCPMSS_H + +struct ipt_tcpmss_info { + u_int16_t mss; +}; + +#define IPT_TCPMSS_CLAMP_PMTU 0xffff + +#endif /*_IPT_TCPMSS_H*/ diff -u --recursive --new-file v2.4.2/linux/include/linux/netfilter_ipv4/ipt_tcpmss.h linux/include/linux/netfilter_ipv4/ipt_tcpmss.h --- v2.4.2/linux/include/linux/netfilter_ipv4/ipt_tcpmss.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/netfilter_ipv4/ipt_tcpmss.h Tue Mar 6 22:44:16 2001 @@ -0,0 +1,9 @@ +#ifndef _IPT_TCPMSS_MATCH_H +#define _IPT_TCPMSS_MATCH_H + +struct ipt_tcpmss_match_info { + u_int16_t mss_min, mss_max; + u_int8_t invert; +}; + +#endif /*_IPT_TCPMSS_MATCH_H*/ diff -u --recursive --new-file v2.4.2/linux/include/linux/openpic.h linux/include/linux/openpic.h --- v2.4.2/linux/include/linux/openpic.h Wed Feb 9 19:43:47 2000 +++ linux/include/linux/openpic.h Wed Dec 31 16:00:00 1969 @@ -1,367 +0,0 @@ -/* - * linux/openpic.h -- OpenPIC definitions - * - * Copyright (C) 1997 Geert Uytterhoeven - * - * This file is based on the following documentation: - * - * The Open Programmable Interrupt Controller (PIC) - * Register Interface Specification Revision 1.2 - * - * Issue Date: October 1995 - * - * Issued jointly by Advanced Micro Devices and Cyrix Corporation - * - * AMD is a registered trademark of Advanced Micro Devices, Inc. - * Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc. - * All Rights Reserved. - * - * To receive a copy of this documentation, send an email to openpic@amd.com. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#ifndef _LINUX_OPENPIC_H -#define _LINUX_OPENPIC_H - -#if !defined(__powerpc__) && !defined(__i386__) -#error Unsupported OpenPIC platform -#endif - - -#ifdef __KERNEL__ - - /* - * OpenPIC supports up to 2048 interrupt sources and up to 32 processors - */ - -#define OPENPIC_MAX_SOURCES 2048 -#define OPENPIC_MAX_PROCESSORS 32 - -#define OPENPIC_NUM_TIMERS 4 -#define OPENPIC_NUM_IPI 4 -#define OPENPIC_NUM_PRI 16 -#define OPENPIC_NUM_VECTORS 256 - - - /* - * Vector numbers - */ - -#define OPENPIC_VEC_SOURCE 16 /* and up */ -#define OPENPIC_VEC_TIMER 64 /* and up */ -#define OPENPIC_VEC_IPI 72 /* and up */ -#define OPENPIC_VEC_SPURIOUS 127 - - - /* - * OpenPIC Registers are 32 bits and aligned on 128 bit boundaries - */ - -typedef struct _OpenPIC_Reg { - u_int Reg; /* Little endian! */ - char Pad[0xc]; -} OpenPIC_Reg; - - - /* - * Per Processor Registers - */ - -typedef struct _OpenPIC_Processor { - /* - * Private Shadow Registers (for SLiC backwards compatibility) - */ - u_int IPI0_Dispatch_Shadow; /* Write Only */ - char Pad1[0x4]; - u_int IPI0_Vector_Priority_Shadow; /* Read/Write */ - char Pad2[0x34]; - /* - * Interprocessor Interrupt Command Ports - */ - OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI]; /* Write Only */ - /* - * Current Task Priority Register - */ - OpenPIC_Reg _Current_Task_Priority; /* Read/Write */ -#ifndef __powerpc__ - /* - * Who Am I Register - */ - OpenPIC_Reg _Who_Am_I; /* Read Only */ -#else - char Pad3[0x10]; -#endif -#ifndef __i386__ - /* - * Interrupt Acknowledge Register - */ - OpenPIC_Reg _Interrupt_Acknowledge; /* Read Only */ -#else - char Pad4[0x10]; -#endif - /* - * End of Interrupt (EOI) Register - */ - OpenPIC_Reg _EOI; /* Read/Write */ - char Pad5[0xf40]; -} OpenPIC_Processor; - - - /* - * Timer Registers - */ - -typedef struct _OpenPIC_Timer { - OpenPIC_Reg _Current_Count; /* Read Only */ - OpenPIC_Reg _Base_Count; /* Read/Write */ - OpenPIC_Reg _Vector_Priority; /* Read/Write */ - OpenPIC_Reg _Destination; /* Read/Write */ -} OpenPIC_Timer; - - - /* - * Global Registers - */ - -typedef struct _OpenPIC_Global { - /* - * Feature Reporting Registers - */ - OpenPIC_Reg _Feature_Reporting0; /* Read Only */ - OpenPIC_Reg _Feature_Reporting1; /* Future Expansion */ - /* - * Global Configuration Registers - */ - OpenPIC_Reg _Global_Configuration0; /* Read/Write */ - OpenPIC_Reg _Global_Configuration1; /* Future Expansion */ - /* - * Vendor Specific Registers - */ - OpenPIC_Reg _Vendor_Specific[4]; - /* - * Vendor Identification Register - */ - OpenPIC_Reg _Vendor_Identification; /* Read Only */ - /* - * Processor Initialization Register - */ - OpenPIC_Reg _Processor_Initialization; /* Read/Write */ - /* - * IPI Vector/Priority Registers - */ - OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI]; /* Read/Write */ - /* - * Spurious Vector Register - */ - OpenPIC_Reg _Spurious_Vector; /* Read/Write */ - /* - * Global Timer Registers - */ - OpenPIC_Reg _Timer_Frequency; /* Read/Write */ - OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS]; - char Pad1[0xee00]; -} OpenPIC_Global; - - - /* - * Interrupt Source Registers - */ - -typedef struct _OpenPIC_Source { - OpenPIC_Reg _Vector_Priority; /* Read/Write */ - OpenPIC_Reg _Destination; /* Read/Write */ -} OpenPIC_Source; - - - /* - * OpenPIC Register Map - */ - -struct OpenPIC { -#ifndef __powerpc__ - /* - * Per Processor Registers --- Private Access - */ - OpenPIC_Processor Private; -#else - char Pad1[0x1000]; -#endif - /* - * Global Registers - */ - OpenPIC_Global Global; - /* - * Interrupt Source Configuration Registers - */ - OpenPIC_Source Source[OPENPIC_MAX_SOURCES]; - /* - * Per Processor Registers - */ - OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS]; -}; - -extern volatile struct OpenPIC *OpenPIC; -extern u_int OpenPIC_NumInitSenses; -extern u_char *OpenPIC_InitSenses; - - - /* - * Current Task Priority Register - */ - -#define OPENPIC_CURRENT_TASK_PRIORITY_MASK 0x0000000f - - /* - * Who Am I Register - */ - -#define OPENPIC_WHO_AM_I_ID_MASK 0x0000001f - - /* - * Feature Reporting Register 0 - */ - -#define OPENPIC_FEATURE_LAST_SOURCE_MASK 0x07ff0000 -#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT 16 -#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK 0x00001f00 -#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT 8 -#define OPENPIC_FEATURE_VERSION_MASK 0x000000ff - - /* - * Global Configuration Register 0 - */ - -#define OPENPIC_CONFIG_RESET 0x80000000 -#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE 0x20000000 -#define OPENPIC_CONFIG_BASE_MASK 0x000fffff - - /* - * Vendor Identification Register - */ - -#define OPENPIC_VENDOR_ID_STEPPING_MASK 0x00ff0000 -#define OPENPIC_VENDOR_ID_STEPPING_SHIFT 16 -#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00 -#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT 8 -#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK 0x000000ff - - /* - * Vector/Priority Registers - */ - -#define OPENPIC_MASK 0x80000000 -#define OPENPIC_ACTIVITY 0x40000000 /* Read Only */ -#define OPENPIC_PRIORITY_MASK 0x000f0000 -#define OPENPIC_PRIORITY_SHIFT 16 -#define OPENPIC_VECTOR_MASK 0x000000ff - - - /* - * Interrupt Source Registers - */ - -#define OPENPIC_POLARITY_POSITIVE 0x00800000 -#define OPENPIC_POLARITY_NEGATIVE 0x00000000 -#define OPENPIC_POLARITY_MASK 0x00800000 -#define OPENPIC_SENSE_LEVEL 0x00400000 -#define OPENPIC_SENSE_EDGE 0x00000000 -#define OPENPIC_SENSE_MASK 0x00400000 - - - /* - * Timer Registers - */ - -#define OPENPIC_COUNT_MASK 0x7fffffff -#define OPENPIC_TIMER_TOGGLE 0x80000000 -#define OPENPIC_TIMER_COUNT_INHIBIT 0x80000000 - - - /* - * Aliases to make life simpler - */ - -/* Per Processor Registers */ -#define IPI_Dispatch(i) _IPI_Dispatch[i].Reg -#define Current_Task_Priority _Current_Task_Priority.Reg -#ifndef __powerpc__ -#define Who_Am_I _Who_Am_I.Reg -#endif -#ifndef __i386__ -#define Interrupt_Acknowledge _Interrupt_Acknowledge.Reg -#endif -#define EOI _EOI.Reg - -/* Global Registers */ -#define Feature_Reporting0 _Feature_Reporting0.Reg -#define Feature_Reporting1 _Feature_Reporting1.Reg -#define Global_Configuration0 _Global_Configuration0.Reg -#define Global_Configuration1 _Global_Configuration1.Reg -#define Vendor_Specific(i) _Vendor_Specific[i].Reg -#define Vendor_Identification _Vendor_Identification.Reg -#define Processor_Initialization _Processor_Initialization.Reg -#define IPI_Vector_Priority(i) _IPI_Vector_Priority[i].Reg -#define Spurious_Vector _Spurious_Vector.Reg -#define Timer_Frequency _Timer_Frequency.Reg - -/* Timer Registers */ -#define Current_Count _Current_Count.Reg -#define Base_Count _Base_Count.Reg -#define Vector_Priority _Vector_Priority.Reg -#define Destination _Destination.Reg - -/* Interrupt Source Registers */ -#define Vector_Priority _Vector_Priority.Reg -#define Destination _Destination.Reg - - /* - * OpenPIC Operations - */ - -/* Global Operations */ -extern void openpic_init(int); -extern void openpic_reset(void); -extern void openpic_enable_8259_pass_through(void); -extern void openpic_disable_8259_pass_through(void); -#ifndef __i386__ -extern u_int openpic_irq(u_int cpu); -#endif -#ifndef __powerpc__ -extern void openpic_eoi(void); -extern u_int openpic_get_priority(void); -extern void openpic_set_priority(u_int pri); -#else -extern void openpic_eoi(u_int cpu); -extern u_int openpic_get_priority(u_int cpu); -extern void openpic_set_priority(u_int cpu, u_int pri); -#endif -extern u_int openpic_get_spurious(void); -extern void openpic_set_spurious(u_int vector); -extern void openpic_init_processor(u_int cpumask); - -/* Interprocessor Interrupts */ -extern void openpic_initipi(u_int ipi, u_int pri, u_int vector); -#ifndef __powerpc__ -extern void openpic_cause_IPI(u_int ipi, u_int cpumask); -#else -extern void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask); -#endif - -/* Timer Interrupts */ -extern void openpic_inittimer(u_int timer, u_int pri, u_int vector); -extern void openpic_maptimer(u_int timer, u_int cpumask); - -/* Interrupt Sources */ -extern void openpic_enable_irq(u_int irq); -extern void openpic_disable_irq(u_int irq); -extern void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity, - int is_level); -extern void openpic_mapirq(u_int irq, u_int cpumask); -extern void openpic_set_sense(u_int irq, int sense); - -#endif /* __KERNEL__ */ - -#endif /* _LINUX_OPENPIC_H */ diff -u --recursive --new-file v2.4.2/linux/include/linux/pagemap.h linux/include/linux/pagemap.h --- v2.4.2/linux/include/linux/pagemap.h Thu Jan 4 14:50:47 2001 +++ linux/include/linux/pagemap.h Wed Mar 7 16:56:37 2001 @@ -29,9 +29,13 @@ #define PAGE_CACHE_ALIGN(addr) (((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK) #define page_cache_get(x) get_page(x) -#define page_cache_alloc() alloc_pages(GFP_HIGHUSER, 0) #define page_cache_free(x) __free_page(x) #define page_cache_release(x) __free_page(x) + +static inline struct page *page_cache_alloc(struct address_space *x) +{ + return alloc_pages(x->gfp_mask, 0); +} /* * From a kernel address, get the "struct page *" diff -u --recursive --new-file v2.4.2/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.4.2/linux/include/linux/pci.h Wed Feb 21 18:20:45 2001 +++ linux/include/linux/pci.h Wed Mar 7 16:57:12 2001 @@ -527,6 +527,7 @@ int pci_enable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); +int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask); int pci_set_power_state(struct pci_dev *dev, int state); int pci_assign_resource(struct pci_dev *dev, int i); @@ -539,6 +540,9 @@ unsigned long pci_bridge_check_io(struct pci_dev *); void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), int (*)(struct pci_dev *, u8, u8)); +#define HAVE_PCI_REQ_REGIONS 1 +int pci_request_regions(struct pci_dev *, char *); +void pci_release_regions(struct pci_dev *); /* New-style probing supporting hot-pluggable devices */ int pci_register_driver(struct pci_driver *); diff -u --recursive --new-file v2.4.2/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h --- v2.4.2/linux/include/linux/pci_ids.h Wed Feb 21 18:20:46 2001 +++ linux/include/linux/pci_ids.h Sat Mar 3 10:52:14 2001 @@ -505,7 +505,10 @@ #define PCI_DEVICE_ID_APPLE_BANDIT 0x0001 #define PCI_DEVICE_ID_APPLE_GC 0x0002 #define PCI_DEVICE_ID_APPLE_HYDRA 0x000e -#define PCI_DEVICE_ID_APPLE_UNINORTH 0x0020 +#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018 +#define PCI_DEVICE_ID_APPLE_KL_USB 0x0019 +#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 +#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021 #define PCI_VENDOR_ID_YAMAHA 0x1073 #define PCI_DEVICE_ID_YAMAHA_724 0x0004 diff -u --recursive --new-file v2.4.2/linux/include/linux/pg.h linux/include/linux/pg.h --- v2.4.2/linux/include/linux/pg.h Sat Jun 13 12:08:20 1998 +++ linux/include/linux/pg.h Tue Mar 6 19:44:37 2001 @@ -1,5 +1,5 @@ /* pg.h (c) 1998 Grant R. Guenther - Under the terms of the GNU public license + Under the terms of the GNU General Public License pg.h defines the user interface to the generic ATAPI packet diff -u --recursive --new-file v2.4.2/linux/include/linux/serial.h linux/include/linux/serial.h --- v2.4.2/linux/include/linux/serial.h Wed Feb 21 18:20:46 2001 +++ linux/include/linux/serial.h Wed Mar 7 16:56:35 2001 @@ -139,7 +139,7 @@ #define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */ #define ASYNC_SHARE_IRQ 0x01000000 /* for multifunction cards --- no longer used */ -#define ASYNC_NO_FLOW 0x00800000 /* No flow control serial console */ +#define ASYNC_CONS_FLOW 0x00800000 /* flow control for console */ #define ASYNC_INTERNAL_FLAGS 0xFF800000 /* Internal flags */ @@ -180,5 +180,6 @@ /* Allow complicated architectures to specify rs_table[] at run time */ extern int early_serial_setup(struct serial_struct *req); + #endif /* __KERNEL__ */ #endif /* _LINUX_SERIAL_H */ diff -u --recursive --new-file v2.4.2/linux/include/linux/serialP.h linux/include/linux/serialP.h --- v2.4.2/linux/include/linux/serialP.h Thu Jan 4 14:51:38 2001 +++ linux/include/linux/serialP.h Wed Mar 7 16:58:46 2001 @@ -52,6 +52,7 @@ struct termios callout_termios; int io_type; struct async_struct *info; + struct pci_dev *dev; }; struct async_struct { diff -u --recursive --new-file v2.4.2/linux/include/linux/serial_reg.h linux/include/linux/serial_reg.h --- v2.4.2/linux/include/linux/serial_reg.h Wed Jun 21 12:43:38 2000 +++ linux/include/linux/serial_reg.h Tue Mar 6 19:28:35 2001 @@ -156,8 +156,8 @@ * These register definitions are for the 16C950 */ #define UART_ASR 0x01 /* Additional Status Register */ -#define UART_RFL 0x03 /* Transmitter FIFO level */ -#define UART_TFL 0x04 /* Receiver FIFO level */ +#define UART_RFL 0x03 /* Receiver FIFO level */ +#define UART_TFL 0x04 /* Transmitter FIFO level */ #define UART_ICR 0x05 /* Index Control Register */ /* The 16950 ICR registers */ diff -u --recursive --new-file v2.4.2/linux/include/linux/synclink.h linux/include/linux/synclink.h --- v2.4.2/linux/include/linux/synclink.h Tue Nov 7 10:36:45 2000 +++ linux/include/linux/synclink.h Tue Mar 6 19:44:37 2001 @@ -6,7 +6,7 @@ * Copyright (C) 1998-2000 by Microgate Corporation * * Redistribution of this file is permitted under - * the terms of the GNU Public License (GPL) + * the terms of the GNU General Public License (GPL) */ #ifndef _SYNCLINK_H_ diff -u --recursive --new-file v2.4.2/linux/include/linux/videodev.h linux/include/linux/videodev.h --- v2.4.2/linux/include/linux/videodev.h Mon Dec 11 13:15:36 2000 +++ linux/include/linux/videodev.h Fri Mar 2 11:12:10 2001 @@ -6,13 +6,12 @@ #ifdef __KERNEL__ -#if LINUX_VERSION_CODE >= 0x020100 #include -#endif #include struct video_device { + struct module *owner; char name[32]; int type; int hardware; diff -u --recursive --new-file v2.4.2/linux/include/net/syncppp.h linux/include/net/syncppp.h --- v2.4.2/linux/include/net/syncppp.h Wed Dec 31 16:00:00 1969 +++ linux/include/net/syncppp.h Tue Mar 6 19:44:37 2001 @@ -0,0 +1,98 @@ +/* + * Defines for synchronous PPP/Cisco link level subroutines. + * + * Copyright (C) 1994 Cronyx Ltd. + * Author: Serge Vakulenko, + * + * This software is distributed with NO WARRANTIES, not even the implied + * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Authors grant any other persons or organizations permission to use + * or modify this software as long as this message is kept with the software, + * all derivative works or modified versions. + * + * Version 1.7, Wed Jun 7 22:12:02 MSD 1995 + * + * + * + */ + +#ifndef _SYNCPPP_H_ +#define _SYNCPPP_H_ 1 + +#ifdef __KERNEL__ +struct slcp { + u16 state; /* state machine */ + u32 magic; /* local magic number */ + u_char echoid; /* id of last keepalive echo request */ + u_char confid; /* id of last configuration request */ +}; + +struct sipcp { + u16 state; /* state machine */ + u_char confid; /* id of last configuration request */ +}; + +struct sppp +{ + struct sppp * pp_next; /* next interface in keepalive list */ + u32 pp_flags; /* use Cisco protocol instead of PPP */ + u16 pp_alivecnt; /* keepalive packets counter */ + u16 pp_loopcnt; /* loopback detection counter */ + u32 pp_seq; /* local sequence number */ + u32 pp_rseq; /* remote sequence number */ + struct slcp lcp; /* LCP params */ + struct sipcp ipcp; /* IPCP params */ + u32 ibytes,obytes; /* Bytes in/out */ + u32 ipkts,opkts; /* Packets in/out */ + struct timer_list pp_timer; + struct net_device *pp_if; + char pp_link_state; /* Link status */ +}; + +struct ppp_device +{ + struct net_device *dev; /* Network device pointer */ + struct sppp sppp; /* Synchronous PPP */ +}; + +#define sppp_of(dev) \ + (&((struct ppp_device *)(*(unsigned long *)((dev)->priv)))->sppp) + +#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ +#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ +#define PP_TIMO 0x04 /* cp_timeout routine active */ +#define PP_DEBUG 0x08 + +#define PPP_MTU 1500 /* max. transmit unit */ + +#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */ +#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */ +#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */ +#define LCP_STATE_OPENED 3 /* LCP state: opened */ + +#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */ +#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */ +#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */ +#define IPCP_STATE_OPENED 3 /* IPCP state: opened */ + +#define SPPP_LINK_DOWN 0 /* link down - no keepalive */ +#define SPPP_LINK_UP 1 /* link is up - keepalive ok */ + +void sppp_attach (struct ppp_device *pd); +void sppp_detach (struct net_device *dev); +void sppp_input (struct net_device *dev, struct sk_buff *m); +int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); +struct sk_buff *sppp_dequeue (struct net_device *dev); +int sppp_isempty (struct net_device *dev); +void sppp_flush (struct net_device *dev); +int sppp_open (struct net_device *dev); +int sppp_reopen (struct net_device *dev); +int sppp_close (struct net_device *dev); +#endif + +#define SPPPIOCCISCO (SIOCDEVPRIVATE) +#define SPPPIOCPPP (SIOCDEVPRIVATE+1) +#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2) + +#endif /* _SYNCPPP_H_ */ diff -u --recursive --new-file v2.4.2/linux/include/pcmcia/ciscode.h linux/include/pcmcia/ciscode.h --- v2.4.2/linux/include/pcmcia/ciscode.h Wed Feb 21 18:20:46 2001 +++ linux/include/pcmcia/ciscode.h Fri Mar 2 11:02:15 2001 @@ -112,10 +112,12 @@ #define PRODID_SOCKET_DUAL_RS232 0x0006 #define PRODID_SOCKET_EIO 0x000a #define PRODID_SOCKET_LPE 0x000d +#define PRODID_SOCKET_LPE_CF 0x0075 #define MANFID_SUNDISK 0x0045 #define MANFID_TDK 0x0105 +#define PRODID_TDK_CF010 0x0900 #define MANFID_TOSHIBA 0x0098 diff -u --recursive --new-file v2.4.2/linux/init/main.c linux/init/main.c --- v2.4.2/linux/init/main.c Wed Jan 3 20:45:26 2001 +++ linux/init/main.c Fri Mar 2 15:16:59 2001 @@ -151,6 +151,7 @@ { "nfs", 0x00ff }, { "hda", 0x0300 }, { "hdb", 0x0340 }, + { "loop", 0x0700 }, { "hdc", 0x1600 }, { "hdd", 0x1640 }, { "hde", 0x2100 }, diff -u --recursive --new-file v2.4.2/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.4.2/linux/kernel/ksyms.c Wed Feb 21 18:20:46 2001 +++ linux/kernel/ksyms.c Fri Mar 2 15:16:59 2001 @@ -121,6 +121,7 @@ EXPORT_SYMBOL(kmap_high); EXPORT_SYMBOL(kunmap_high); EXPORT_SYMBOL(highmem_start_page); +EXPORT_SYMBOL(create_bounce); #endif /* filesystem internal functions */ diff -u --recursive --new-file v2.4.2/linux/kernel/pm.c linux/kernel/pm.c --- v2.4.2/linux/kernel/pm.c Fri May 12 11:21:20 2000 +++ linux/kernel/pm.c Tue Mar 6 19:44:37 2001 @@ -25,7 +25,19 @@ int pm_active; -static spinlock_t pm_devs_lock = SPIN_LOCK_UNLOCKED; +/* + * Locking notes: + * pm_devs_lock can be a semaphore providing pm ops are not called + * from an interrupt handler (already a bad idea so no change here). Each + * change must be protected so that an unlink of an entry doesnt clash + * with a pm send - which is permitted to sleep in the current architecture + * + * Module unloads clashing with pm events now work out safely, the module + * unload path will block until the event has been sent. It may well block + * until a resume but that will be fine. + */ + +static DECLARE_MUTEX(pm_devs_lock); static LIST_HEAD(pm_devs); /** @@ -45,16 +57,14 @@ { struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); if (dev) { - unsigned long flags; - memset(dev, 0, sizeof(*dev)); dev->type = type; dev->id = id; dev->callback = callback; - spin_lock_irqsave(&pm_devs_lock, flags); + down(&pm_devs_lock); list_add(&dev->entry, &pm_devs); - spin_unlock_irqrestore(&pm_devs_lock, flags); + up(&pm_devs_lock); } return dev; } @@ -70,16 +80,22 @@ void pm_unregister(struct pm_dev *dev) { if (dev) { - unsigned long flags; - - spin_lock_irqsave(&pm_devs_lock, flags); + down(&pm_devs_lock); list_del(&dev->entry); - spin_unlock_irqrestore(&pm_devs_lock, flags); + up(&pm_devs_lock); kfree(dev); } } +static void __pm_unregister(struct pm_dev *dev) +{ + if (dev) { + list_del(&dev->entry); + kfree(dev); + } +} + /** * pm_unregister_all - unregister all devices with matching callback * @callback: callback function pointer @@ -97,13 +113,15 @@ if (!callback) return; + down(&pm_devs_lock); entry = pm_devs.next; while (entry != &pm_devs) { struct pm_dev *dev = list_entry(entry, struct pm_dev, entry); entry = entry->next; if (dev->callback == callback) - pm_unregister(dev); + __pm_unregister(dev); } + up(&pm_devs_lock); } /** @@ -119,6 +137,13 @@ * * BUGS: what stops two power management requests occuring in parallel * and conflicting. + * + * WARNING: Calling pm_send directly is not generally recommended, in + * paticular there is no locking against the pm_dev going away. The + * caller must maintain all needed locking or have 'inside knowledge' + * on the safety. Also remember that this function is not locked against + * pm_unregister. This means that you must handle SMP races on callback + * execution and unload yourself. */ int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data) @@ -183,6 +208,12 @@ * during the processing of this request are restored to their * previous state. * + * WARNING: This function takes the pm_devs_lock. The lock is not dropped until + * the callbacks have completed. This prevents races against pm locking + * functions, races against module unload pm_unregister code. It does + * mean however that you must not issue pm_ functions within the callback + * or you will deadlock and users will hate you. + * * Zero is returned on success. If a suspend fails then the status * from the device that vetoes the suspend is returned. * @@ -192,7 +223,10 @@ int pm_send_all(pm_request_t rqst, void *data) { - struct list_head *entry = pm_devs.next; + struct list_head *entry; + + down(&pm_devs_lock); + entry = pm_devs.next; while (entry != &pm_devs) { struct pm_dev *dev = list_entry(entry, struct pm_dev, entry); if (dev->callback) { @@ -203,11 +237,13 @@ */ if (rqst == PM_SUSPEND) pm_undo_all(dev); + up(&pm_devs_lock); return status; } } entry = entry->next; } + up(&pm_devs_lock); return 0; } @@ -222,6 +258,10 @@ * of the list. * * To search from the beginning pass %NULL as the @from value. + * + * The caller MUST hold the pm_devs_lock lock when calling this + * function. The instant that the lock is dropped all pointers returned + * may become invalid. */ struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from) diff -u --recursive --new-file v2.4.2/linux/kernel/ptrace.c linux/kernel/ptrace.c --- v2.4.2/linux/kernel/ptrace.c Wed Nov 8 19:01:34 2000 +++ linux/kernel/ptrace.c Mon Mar 12 10:50:15 2001 @@ -28,6 +28,7 @@ struct page *page; repeat: + spin_lock(&mm->page_table_lock); pgdir = pgd_offset(vma->vm_mm, addr); if (pgd_none(*pgdir)) goto fault_in_page; @@ -47,9 +48,13 @@ /* ZERO_PAGE is special: reads from it are ok even though it's marked reserved */ if (page != ZERO_PAGE(addr) || write) { - if ((!VALID_PAGE(page)) || PageReserved(page)) + if ((!VALID_PAGE(page)) || PageReserved(page)) { + spin_unlock(&mm->page_table_lock); return 0; + } } + get_page(page); + spin_unlock(&mm->page_table_lock); flush_cache_page(vma, addr); if (write) { @@ -64,19 +69,23 @@ flush_page_to_ram(page); kunmap(page); } + put_page(page); return len; fault_in_page: + spin_unlock(&mm->page_table_lock); /* -1: out of memory. 0 - unmapped page */ if (handle_mm_fault(mm, vma, addr, write) > 0) goto repeat; return 0; bad_pgd: + spin_unlock(&mm->page_table_lock); pgd_ERROR(*pgdir); return 0; bad_pmd: + spin_unlock(&mm->page_table_lock); pmd_ERROR(*pgmiddle); return 0; } diff -u --recursive --new-file v2.4.2/linux/kernel/sched.c linux/kernel/sched.c --- v2.4.2/linux/kernel/sched.c Wed Feb 21 18:20:46 2001 +++ linux/kernel/sched.c Tue Mar 6 19:44:37 2001 @@ -339,7 +339,7 @@ if (task_on_runqueue(p)) goto out; add_to_runqueue(p); - if (!synchronous) + if (!synchronous || !(p->cpus_allowed & (1 << smp_processor_id()))) reschedule_idle(p); success = 1; out: @@ -359,6 +359,32 @@ wake_up_process(p); } +/** + * schedule_timeout - sleep until timeout + * @timeout: timeout value in jiffies + * + * Make the current task sleep until @timeout jiffies have + * elapsed. The routine will return immediately unless + * the current task state has been set (see set_current_state()). + * + * You can set the task state as follows - + * + * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to + * pass before the routine returns. The routine will return 0 + * + * %TASK_INTERRUPTIBLE - the routine may return early if a signal is + * delivered to the current task. In this case the remaining time + * in jiffies will be returned, or 0 if the timer expired in time + * + * The current task state is guaranteed to be TASK_RUNNING when this + * routine returns. + * + * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule + * the CPU away without a bound on the timeout. In this case the return + * value will be %MAX_SCHEDULE_TIMEOUT. + * + * In all cases the return value is guaranteed to be non-negative. + */ signed long schedule_timeout(signed long timeout) { struct timer_list timer; @@ -473,7 +499,7 @@ goto out_unlock; spin_lock_irqsave(&runqueue_lock, flags); - if (prev->state == TASK_RUNNING) + if ((prev->state == TASK_RUNNING) && !prev->has_cpu) reschedule_idle(prev); spin_unlock_irqrestore(&runqueue_lock, flags); goto out_unlock; @@ -541,7 +567,7 @@ } default: del_from_runqueue(prev); - case TASK_RUNNING: + case TASK_RUNNING:; } prev->need_resched = 0; diff -u --recursive --new-file v2.4.2/linux/kernel/sys.c linux/kernel/sys.c --- v2.4.2/linux/kernel/sys.c Mon Oct 16 12:58:51 2000 +++ linux/kernel/sys.c Tue Mar 6 19:44:37 2001 @@ -330,6 +330,12 @@ return 0; } +static void deferred_cad(void *dummy) +{ + notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); + machine_restart(NULL); +} + /* * This function gets called by ctrl-alt-del - ie the keyboard interrupt. * As it's called within an interrupt, it may NOT sync: the only choice @@ -337,10 +343,13 @@ */ void ctrl_alt_del(void) { - if (C_A_D) { - notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); - machine_restart(NULL); - } else + static struct tq_struct cad_tq = { + routine: deferred_cad, + }; + + if (C_A_D) + schedule_task(&cad_tq); + else kill_proc(1, SIGINT, 1); } @@ -367,12 +376,14 @@ { int old_rgid = current->gid; int old_egid = current->egid; + int new_rgid = old_rgid; + int new_egid = old_egid; if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || (current->egid==rgid) || capable(CAP_SETGID)) - current->gid = rgid; + new_rgid = rgid; else return -EPERM; } @@ -381,18 +392,22 @@ (current->egid == egid) || (current->sgid == egid) || capable(CAP_SETGID)) - current->fsgid = current->egid = egid; + new_egid = egid; else { - current->gid = old_rgid; return -EPERM; } } + if (new_egid != old_egid) + { + current->dumpable = 0; + wmb(); + } if (rgid != (gid_t) -1 || (egid != (gid_t) -1 && egid != old_rgid)) - current->sgid = current->egid; - current->fsgid = current->egid; - if (current->egid != old_egid) - current->dumpable = 0; + current->sgid = new_egid; + current->fsgid = new_egid; + current->egid = new_egid; + current->gid = new_rgid; return 0; } @@ -406,14 +421,25 @@ int old_egid = current->egid; if (capable(CAP_SETGID)) + { + if(old_egid != gid) + { + current->dumpable=0; + wmb(); + } current->gid = current->egid = current->sgid = current->fsgid = gid; + } else if ((gid == current->gid) || (gid == current->sgid)) + { + if(old_egid != gid) + { + current->dumpable=0; + wmb(); + } current->egid = current->fsgid = gid; + } else return -EPERM; - - if (current->egid != old_egid) - current->dumpable = 0; return 0; } @@ -463,7 +489,7 @@ } } -static int set_user(uid_t new_ruid) +static int set_user(uid_t new_ruid, int dumpclear) { struct user_struct *new_user, *old_user; @@ -479,6 +505,11 @@ atomic_dec(&old_user->processes); atomic_inc(&new_user->processes); + if(dumpclear) + { + current->dumpable = 0; + wmb(); + } current->uid = new_ruid; current->user = new_user; free_uid(old_user); @@ -525,16 +556,19 @@ return -EPERM; } - if (new_ruid != old_ruid && set_user(new_ruid) < 0) + if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) return -EAGAIN; + if (new_euid != old_euid) + { + current->dumpable=0; + wmb(); + } current->fsuid = current->euid = new_euid; if (ruid != (uid_t) -1 || (euid != (uid_t) -1 && euid != old_ruid)) current->suid = current->euid; current->fsuid = current->euid; - if (current->euid != old_euid) - current->dumpable = 0; if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); @@ -559,21 +593,26 @@ asmlinkage long sys_setuid(uid_t uid) { int old_euid = current->euid; - int old_ruid, old_suid, new_ruid; + int old_ruid, old_suid, new_ruid, new_suid; old_ruid = new_ruid = current->uid; old_suid = current->suid; + new_suid = old_suid; + if (capable(CAP_SETUID)) { - if (uid != old_ruid && set_user(uid) < 0) + if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) return -EAGAIN; - current->suid = uid; - } else if ((uid != current->uid) && (uid != current->suid)) + new_suid = uid; + } else if ((uid != current->uid) && (uid != new_suid)) return -EPERM; - current->fsuid = current->euid = uid; - if (old_euid != uid) + { current->dumpable = 0; + wmb(); + } + current->fsuid = current->euid = uid; + current->suid = new_suid; if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); @@ -605,12 +644,15 @@ return -EPERM; } if (ruid != (uid_t) -1) { - if (ruid != current->uid && set_user(ruid) < 0) + if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) return -EAGAIN; } if (euid != (uid_t) -1) { if (euid != current->euid) + { current->dumpable = 0; + wmb(); + } current->euid = euid; current->fsuid = euid; } @@ -640,7 +682,7 @@ */ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { - if (!capable(CAP_SETGID)) { + if (!capable(CAP_SETGID)) { if ((rgid != (gid_t) -1) && (rgid != current->gid) && (rgid != current->egid) && (rgid != current->sgid)) return -EPERM; @@ -651,14 +693,17 @@ (sgid != current->egid) && (sgid != current->sgid)) return -EPERM; } - if (rgid != (gid_t) -1) - current->gid = rgid; if (egid != (gid_t) -1) { if (egid != current->egid) + { current->dumpable = 0; + wmb(); + } current->egid = egid; current->fsgid = egid; } + if (rgid != (gid_t) -1) + current->gid = rgid; if (sgid != (gid_t) -1) current->sgid = sgid; return 0; @@ -690,9 +735,14 @@ if (uid == current->uid || uid == current->euid || uid == current->suid || uid == current->fsuid || capable(CAP_SETUID)) + { + if (uid != old_fsuid) + { + current->dumpable = 0; + wmb(); + } current->fsuid = uid; - if (current->fsuid != old_fsuid) - current->dumpable = 0; + } /* We emulate fsuid by essentially doing a scaled-down version * of what we did in setresuid and friends. However, we only @@ -727,10 +777,14 @@ if (gid == current->gid || gid == current->egid || gid == current->sgid || gid == current->fsgid || capable(CAP_SETGID)) + { + if (gid != old_fsgid) + { + current->dumpable = 0; + wmb(); + } current->fsgid = gid; - if (current->fsgid != old_fsgid) - current->dumpable = 0; - + } return old_fsgid; } diff -u --recursive --new-file v2.4.2/linux/lib/inflate.c linux/lib/inflate.c --- v2.4.2/linux/lib/inflate.c Fri Jan 14 17:56:38 2000 +++ linux/lib/inflate.c Tue Mar 6 19:44:37 2001 @@ -11,7 +11,7 @@ * Little mods for all variable to reside either into rodata or bss segments * by marking constant variables with 'const' and initializing all the others * at run-time only. This allows for the kernel uncompressor to run - * directly from Flash or ROM memory on embeded systems. + * directly from Flash or ROM memory on embedded systems. */ /* diff -u --recursive --new-file v2.4.2/linux/lib/string.c linux/lib/string.c --- v2.4.2/linux/lib/string.c Thu Aug 10 13:10:14 2000 +++ linux/lib/string.c Tue Mar 6 19:44:37 2001 @@ -20,6 +20,12 @@ #include #ifndef __HAVE_ARCH_STRNICMP +/** + * strnicmp - Case insensitive, length-limited string comparison + * @s1: One string + * @s2: The other string + * @len: the maximum number of characters to compare + */ int strnicmp(const char *s1, const char *s2, size_t len) { /* Yes, Virginia, it had better be unsigned */ @@ -49,6 +55,11 @@ char * ___strtok; #ifndef __HAVE_ARCH_STRCPY +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + */ char * strcpy(char * dest,const char *src) { char *tmp = dest; @@ -60,6 +71,16 @@ #endif #ifndef __HAVE_ARCH_STRNCPY +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @count: The maximum number of bytes to copy + * + * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. + * However, the result is not %NUL-terminated if the source exceeds + * @count bytes. + */ char * strncpy(char * dest,const char *src,size_t count) { char *tmp = dest; @@ -72,6 +93,11 @@ #endif #ifndef __HAVE_ARCH_STRCAT +/** + * strcat - Append one %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + */ char * strcat(char * dest, const char * src) { char *tmp = dest; @@ -86,6 +112,15 @@ #endif #ifndef __HAVE_ARCH_STRNCAT +/** + * strncat - Append a length-limited, %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * @count: The maximum numbers of bytes to copy + * + * Note that in contrast to strncpy, strncat ensures the result is + * terminated. + */ char * strncat(char *dest, const char *src, size_t count) { char *tmp = dest; @@ -106,6 +141,11 @@ #endif #ifndef __HAVE_ARCH_STRCMP +/** + * strcmp - Compare two strings + * @cs: One string + * @ct: Another string + */ int strcmp(const char * cs,const char * ct) { register signed char __res; @@ -120,6 +160,12 @@ #endif #ifndef __HAVE_ARCH_STRNCMP +/** + * strncmp - Compare two length-limited strings + * @cs: One string + * @ct: Another string + * @count: The maximum number of bytes to compare + */ int strncmp(const char * cs,const char * ct,size_t count) { register signed char __res = 0; @@ -135,6 +181,11 @@ #endif #ifndef __HAVE_ARCH_STRCHR +/** + * strchr - Find the first occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ char * strchr(const char * s, int c) { for(; *s != (char) c; ++s) @@ -145,6 +196,11 @@ #endif #ifndef __HAVE_ARCH_STRRCHR +/** + * strrchr - Find the last occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ char * strrchr(const char * s, int c) { const char *p = s + strlen(s); @@ -157,6 +213,10 @@ #endif #ifndef __HAVE_ARCH_STRLEN +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ size_t strlen(const char * s) { const char *sc; @@ -168,6 +228,11 @@ #endif #ifndef __HAVE_ARCH_STRNLEN +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ size_t strnlen(const char * s, size_t count) { const char *sc; @@ -179,6 +244,12 @@ #endif #ifndef __HAVE_ARCH_STRSPN +/** + * strspn - Calculate the length of the initial substring of @s which only + * contain letters in @accept + * @s: The string to be searched + * @accept: The string to search for + */ size_t strspn(const char *s, const char *accept) { const char *p; @@ -200,6 +271,11 @@ #endif #ifndef __HAVE_ARCH_STRPBRK +/** + * strpbrk - Find the first occurrence of a set of characters + * @cs: The string to be searched + * @ct: The characters to search for + */ char * strpbrk(const char * cs,const char * ct) { const char *sc1,*sc2; @@ -215,6 +291,13 @@ #endif #ifndef __HAVE_ARCH_STRTOK +/** + * strtok - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * WARNING: strtok is deprecated, use strsep instead. + */ char * strtok(char * s,const char * ct) { char *sbegin, *send; @@ -237,7 +320,13 @@ #endif #ifndef __HAVE_ARCH_STRSEP - +/** + * strsep - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * strsep() updates @s to point after the token, ready for the next call. + */ char * strsep(char **s, const char * ct) { char *sbegin=*s; @@ -256,6 +345,12 @@ #endif #ifndef __HAVE_ARCH_MEMSET +/** + * memset - Fill a region of memory with the given value + * @s: Pointer to the start of the area. + * @c: The byte to fill the area with + * @count: The size of the area. + */ void * memset(void * s,int c,size_t count) { char *xs = (char *) s; @@ -268,6 +363,18 @@ #endif #ifndef __HAVE_ARCH_BCOPY +/** + * bcopy - Copy one area of memory to another + * @src: Where to copy from + * @dest: Where to copy to + * @count: The size of the area. + * + * When using copies for I/O remember that bcopy and memcpy are entitled + * to do out of order writes and may well exactly that. + * + * Note that this is the same as memcpy, with the arguments reversed. memcpy + * is the standard, bcopy is a legacy BSD function. + */ char * bcopy(const char * src, char * dest, int count) { char *tmp = dest; @@ -280,6 +387,15 @@ #endif #ifndef __HAVE_ARCH_MEMCPY +/** + * memcpy - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * When using copies for I/O remember that bcopy and memcpy are entitled + * to do out of order writes and may well exactly that. + */ void * memcpy(void * dest,const void *src,size_t count) { char *tmp = (char *) dest, *s = (char *) src; @@ -292,6 +408,14 @@ #endif #ifndef __HAVE_ARCH_MEMMOVE +/** + * memmove - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * memmove copes with overlapping areas. + */ void * memmove(void * dest,const void *src,size_t count) { char *tmp, *s; @@ -314,6 +438,12 @@ #endif #ifndef __HAVE_ARCH_MEMCMP +/** + * memmove - Compare two areas of memory + * @cs: One area of memory + * @ct: Another area of memory + * @count: The size of the area. + */ int memcmp(const void * cs,const void * ct,size_t count) { const unsigned char *su1, *su2; @@ -326,10 +456,16 @@ } #endif -/* - * find the first occurrence of byte 'c', or 1 past the area if none - */ #ifndef __HAVE_ARCH_MEMSCAN +/** + * memscan - Find a character in an area of memory. + * @addr: The memory area + * @c: The byte to search for + * @size: The size of the area. + * + * returns the address of the first occurrence of @c, or 1 byte past + * the area if @c is not found + */ void * memscan(void * addr, int c, size_t size) { unsigned char * p = (unsigned char *) addr; @@ -345,6 +481,11 @@ #endif #ifndef __HAVE_ARCH_STRSTR +/** + * strstr - Find the first substring in a %NUL terminated string + * @s1: The string to be searched + * @s2: The string to search for + */ char * strstr(const char * s1,const char * s2) { int l1, l2; @@ -364,6 +505,15 @@ #endif #ifndef __HAVE_ARCH_MEMCHR +/** + * memchr - Find a character in an area of memory. + * @s: The memory area + * @c: The byte to search for + * @n: The size of the area. + * + * returns the address of the first occurrence of @c, or %NULL + * if @c is not found + */ void *memchr(const void *s, int c, size_t n) { const unsigned char *p = s; diff -u --recursive --new-file v2.4.2/linux/lib/vsprintf.c linux/lib/vsprintf.c --- v2.4.2/linux/lib/vsprintf.c Mon Nov 27 17:44:26 2000 +++ linux/lib/vsprintf.c Tue Mar 6 19:44:37 2001 @@ -16,6 +16,12 @@ #include +/** + * simple_strtoul - convert a string to an unsigned long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) { unsigned long result = 0,value; @@ -41,6 +47,12 @@ return result; } +/** + * simple_strtol - convert a string to a signed long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ long simple_strtol(const char *cp,char **endp,unsigned int base) { if(*cp=='-') @@ -48,6 +60,12 @@ return simple_strtoul(cp,endp,base); } +/** + * simple_strtoull - convert a string to an unsigned long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) { unsigned long long result = 0,value; @@ -73,6 +91,12 @@ return result; } +/** + * simple_strtoll - convert a string to a signed long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ long long simple_strtoll(const char *cp,char **endp,unsigned int base) { if(*cp=='-') @@ -163,9 +187,15 @@ return str; } -/* Forward decl. needed for IP address printing stuff... */ -int sprintf(char * buf, const char *fmt, ...); - +/** + * vsprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + * + * Call this function if you are already dealing with a va_list. + * You probably want sprintf instead. + */ int vsprintf(char *buf, const char *fmt, va_list args) { int len; @@ -343,6 +373,12 @@ return str-buf; } +/** + * sprintf - Format a string and place it in a buffer + * @buf: The buffer to place the result into + * @fmt: The format string to use + * @args: Arguments for the format string + */ int sprintf(char * buf, const char *fmt, ...) { va_list args; diff -u --recursive --new-file v2.4.2/linux/mm/filemap.c linux/mm/filemap.c --- v2.4.2/linux/mm/filemap.c Wed Feb 21 18:20:46 2001 +++ linux/mm/filemap.c Fri Mar 2 15:20:32 2001 @@ -559,7 +559,7 @@ if (page) return 0; - page = page_cache_alloc(); + page = page_cache_alloc(mapping); if (!page) return -ENOMEM; @@ -1174,7 +1174,7 @@ */ if (!cached_page) { spin_unlock(&pagecache_lock); - cached_page = page_cache_alloc(); + cached_page = page_cache_alloc(mapping); if (!cached_page) { desc->error = -ENOMEM; break; @@ -1474,7 +1474,7 @@ */ old_page = page; if (no_share) { - struct page *new_page = page_cache_alloc(); + struct page *new_page = alloc_page(GFP_HIGHUSER); if (new_page) { copy_user_highpage(new_page, old_page, address); @@ -2319,7 +2319,7 @@ page = __find_get_page(mapping, index, hash); if (!page) { if (!cached_page) { - cached_page = page_cache_alloc(); + cached_page = page_cache_alloc(mapping); if (!cached_page) return ERR_PTR(-ENOMEM); } @@ -2382,7 +2382,7 @@ page = __find_lock_page(mapping, index, hash); if (!page) { if (!*cached_page) { - *cached_page = page_cache_alloc(); + *cached_page = page_cache_alloc(mapping); if (!*cached_page) return NULL; } diff -u --recursive --new-file v2.4.2/linux/mm/memory.c linux/mm/memory.c --- v2.4.2/linux/mm/memory.c Wed Feb 21 18:20:46 2001 +++ linux/mm/memory.c Fri Mar 2 15:20:23 2001 @@ -870,7 +870,7 @@ * Ok, we need to copy. Oh, well.. */ spin_unlock(&mm->page_table_lock); - new_page = page_cache_alloc(); + new_page = alloc_page(GFP_HIGHUSER); if (!new_page) return -1; spin_lock(&mm->page_table_lock); diff -u --recursive --new-file v2.4.2/linux/mm/shmem.c linux/mm/shmem.c --- v2.4.2/linux/mm/shmem.c Sat Feb 3 19:51:32 2001 +++ linux/mm/shmem.c Fri Mar 2 15:16:59 2001 @@ -321,7 +321,7 @@ inode->i_sb->u.shmem_sb.free_blocks--; spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock); /* Ok, get a new page */ - page = page_cache_alloc(); + page = page_cache_alloc(mapping); if (!page) goto oom; clear_user_highpage(page, address); @@ -338,7 +338,7 @@ up(&inode->i_sem); if (no_share) { - struct page *new_page = page_cache_alloc(); + struct page *new_page = page_cache_alloc(inode->i_mapping); if (new_page) { copy_user_highpage(new_page, page, address); diff -u --recursive --new-file v2.4.2/linux/mm/slab.c linux/mm/slab.c --- v2.4.2/linux/mm/slab.c Sat Feb 3 19:51:32 2001 +++ linux/mm/slab.c Fri Mar 2 11:29:39 2001 @@ -814,28 +814,6 @@ return cachep; } -/* - * This check if the kmem_cache_t pointer is chained in the cache_cache - * list. -arca - */ -static int is_chained_kmem_cache(kmem_cache_t * cachep) -{ - struct list_head *p; - int ret = 0; - - /* Find the cache in the chain of caches. */ - down(&cache_chain_sem); - list_for_each(p, &cache_chain) { - if (p == &cachep->next) { - ret = 1; - break; - } - } - up(&cache_chain_sem); - - return ret; -} - #ifdef CONFIG_SMP /* * Waits for all CPUs to execute func(). @@ -938,7 +916,7 @@ */ int kmem_cache_shrink(kmem_cache_t *cachep) { - if (!cachep || in_interrupt() || !is_chained_kmem_cache(cachep)) + if (!cachep || in_interrupt()) BUG(); return __kmem_cache_shrink(cachep); diff -u --recursive --new-file v2.4.2/linux/net/Config.in linux/net/Config.in --- v2.4.2/linux/net/Config.in Wed Feb 21 18:20:47 2001 +++ linux/net/Config.in Tue Mar 6 22:44:15 2001 @@ -81,7 +81,7 @@ mainmenu_option next_comment comment 'QoS and/or fair queueing' -bool 'QoS and/or fair queueing (EXPERIMENTAL)' CONFIG_NET_SCHED +bool 'QoS and/or fair queueing' CONFIG_NET_SCHED if [ "$CONFIG_NET_SCHED" = "y" ]; then source net/sched/Config.in fi diff -u --recursive --new-file v2.4.2/linux/net/atm/lec.c linux/net/atm/lec.c --- v2.4.2/linux/net/atm/lec.c Sat Feb 3 19:51:33 2001 +++ linux/net/atm/lec.c Tue Mar 6 19:28:33 2001 @@ -51,9 +51,9 @@ #define DPRINTK(format,args...) #endif -struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, +extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, unsigned char *addr); -void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); +extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); #define DUMP_PACKETS 0 /* 0 = None, diff -u --recursive --new-file v2.4.2/linux/net/core/dev.c linux/net/core/dev.c --- v2.4.2/linux/net/core/dev.c Mon Dec 11 13:29:35 2000 +++ linux/net/core/dev.c Fri Mar 2 11:02:15 2001 @@ -349,7 +349,7 @@ /* * Saves at boot time configured settings for any netdevice. */ -static int __init netdev_boot_setup(char *str) +int __init netdev_boot_setup(char *str) { int ints[5]; struct ifmap map; @@ -359,7 +359,7 @@ return 0; /* Save settings */ - memset(&map, -1, sizeof(map)); + memset(&map, 0, sizeof(map)); if (ints[0] > 0) map.irq = ints[1]; if (ints[0] > 1) diff -u --recursive --new-file v2.4.2/linux/net/ethernet/eth.c linux/net/ethernet/eth.c --- v2.4.2/linux/net/ethernet/eth.c Tue Aug 22 08:59:00 2000 +++ linux/net/ethernet/eth.c Fri Mar 2 11:02:15 2001 @@ -30,6 +30,7 @@ * Alan Cox : Protect against forwarding explosions with * older network drivers and IFF_ALLMULTI. * Christer Weinigel : Better rebuild header message. + * Andrew Morton : 26Feb01: kill ether_setup() - use netdev_boot_setup(). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -60,31 +61,9 @@ #include #include -static int __init eth_setup(char *str) -{ - int ints[5]; - struct ifmap map; +extern int __init netdev_boot_setup(char *str); - str = get_options(str, ARRAY_SIZE(ints), ints); - if (!str || !*str) - return 0; - - /* Save settings */ - memset(&map, -1, sizeof(map)); - if (ints[0] > 0) - map.irq = ints[1]; - if (ints[0] > 1) - map.base_addr = ints[2]; - if (ints[0] > 2) - map.mem_start = ints[3]; - if (ints[0] > 3) - map.mem_end = ints[4]; - - /* Add new entry to the list */ - return netdev_boot_setup_add(str, &map); -} - -__setup("ether=", eth_setup); +__setup("ether=", netdev_boot_setup); /* * Create the Ethernet MAC header for an arbitrary protocol layer diff -u --recursive --new-file v2.4.2/linux/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in --- v2.4.2/linux/net/ipv4/netfilter/Config.in Sat Feb 3 19:51:33 2001 +++ linux/net/ipv4/netfilter/Config.in Tue Mar 6 22:44:16 2001 @@ -20,6 +20,7 @@ dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES + dep_tristate ' tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then dep_tristate ' Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES fi @@ -45,7 +46,7 @@ # If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), # or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh. if [ "$CONFIG_IP_NF_FTP" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_FTP m + define_tristate CONFIG_IP_NF_NAT_FTP m else if [ "$CONFIG_IP_NF_FTP" = "y" ]; then define_tristate CONFIG_IP_NF_NAT_FTP $CONFIG_IP_NF_NAT @@ -60,6 +61,7 @@ dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE fi dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES + dep_tristate ' TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES fi # Backwards compatibility modules: only if you don't build in the others. diff -u --recursive --new-file v2.4.2/linux/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile --- v2.4.2/linux/net/ipv4/netfilter/Makefile Sat Feb 3 19:51:33 2001 +++ linux/net/ipv4/netfilter/Makefile Tue Mar 6 22:44:16 2001 @@ -54,6 +54,7 @@ obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o +obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o # targets obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o @@ -63,6 +64,7 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o +obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o # backwards compatibility obj-$(CONFIG_IP_NF_COMPAT_IPCHAINS) += ipchains.o diff -u --recursive --new-file v2.4.2/linux/net/ipv4/netfilter/ipt_TCPMSS.c linux/net/ipv4/netfilter/ipt_TCPMSS.c --- v2.4.2/linux/net/ipv4/netfilter/ipt_TCPMSS.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ipt_TCPMSS.c Tue Mar 6 22:44:16 2001 @@ -0,0 +1,245 @@ +/* + * This is a module which is used for setting the MSS option in TCP packets. + * + * Copyright (c) 2000 Marc Boucher + */ +#include +#include + +#include +#include + +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static u_int16_t +cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) +{ + u_int32_t diffs[] = { oldvalinv, newval }; + return csum_fold(csum_partial((char *)diffs, sizeof(diffs), + oldcheck^0xFFFF)); +} + +static inline unsigned int +optlen(const u_int8_t *opt, unsigned int offset) +{ + /* Beware zero-length options: make finite progress */ + if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) return 1; + else return opt[offset+1]; +} + +static unsigned int +ipt_tcpmss_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_tcpmss_info *tcpmssinfo = targinfo; + struct tcphdr *tcph; + struct iphdr *iph = (*pskb)->nh.iph; + u_int16_t tcplen, newtotlen, oldval, newmss; + unsigned int i; + u_int8_t *opt; + + tcplen = (*pskb)->len - iph->ihl*4; + + tcph = (void *)iph + iph->ihl*4; + + /* Since it passed flags test in tcp match, we know it is is + not a fragment, and has data >= tcp header length. SYN + packets should not contain data: if they did, then we risk + running over MTU, sending Frag Needed and breaking things + badly. --RR */ + if (tcplen != tcph->doff*4) { + if (net_ratelimit()) + printk(KERN_ERR + "ipt_tcpmss_target: bad length (%d bytes)\n", + (*pskb)->len); + return NF_DROP; + } + + if(tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) { + if(!(*pskb)->dst) { + if (net_ratelimit()) + printk(KERN_ERR + "ipt_tcpmss_target: no dst?! can't determine path-MTU\n"); + return NF_DROP; /* or IPT_CONTINUE ?? */ + } + + if((*pskb)->dst->pmtu <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) { + if (net_ratelimit()) + printk(KERN_ERR + "ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", (*pskb)->dst->pmtu); + return NF_DROP; /* or IPT_CONTINUE ?? */ + } + + newmss = (*pskb)->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr); + } else + newmss = tcpmssinfo->mss; + + opt = (u_int8_t *)tcph; + for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)){ + if ((opt[i] == TCPOPT_MSS) && + ((tcph->doff*4 - i) >= TCPOLEN_MSS) && + (opt[i+1] == TCPOLEN_MSS)) { + u_int16_t oldmss; + + oldmss = (opt[i+2] << 8) | opt[i+3]; + + if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && + (oldmss <= newmss)) + return IPT_CONTINUE; + + opt[i+2] = (newmss & 0xff00) >> 8; + opt[i+3] = (newmss & 0x00ff); + + tcph->check = cheat_check(htons(oldmss)^0xFFFF, + htons(newmss), + tcph->check); + + DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu" + "->%u.%u.%u.%u:%hu changed TCP MSS option" + " (from %u to %u)\n", + NIPQUAD((*pskb)->nh.iph->saddr), + ntohs(tcph->source), + NIPQUAD((*pskb)->nh.iph->daddr), + ntohs(tcph->dest), + oldmss, newmss); + goto retmodified; + } + } + + /* + * MSS Option not found ?! add it.. + */ + if (skb_tailroom((*pskb)) < TCPOLEN_MSS) { + struct sk_buff *newskb; + + newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), + TCPOLEN_MSS, GFP_ATOMIC); + if (!newskb) { + if (net_ratelimit()) + printk(KERN_ERR "ipt_tcpmss_target:" + " unable to allocate larger skb\n"); + return NF_DROP; + } + + kfree_skb(*pskb); + *pskb = newskb; + iph = (*pskb)->nh.iph; + tcph = (void *)iph + iph->ihl*4; + } + + skb_put((*pskb), TCPOLEN_MSS); + + opt = (u_int8_t *)tcph + sizeof(struct tcphdr); + memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); + + tcph->check = cheat_check(htons(tcplen) ^ 0xFFFF, + htons(tcplen + TCPOLEN_MSS), tcph->check); + tcplen += TCPOLEN_MSS; + + opt[0] = TCPOPT_MSS; + opt[1] = TCPOLEN_MSS; + opt[2] = (newmss & 0xff00) >> 8; + opt[3] = (newmss & 0x00ff); + + tcph->check = cheat_check(~0, *((u_int32_t *)opt), tcph->check); + + oldval = ((u_int16_t *)tcph)[6]; + tcph->doff += TCPOLEN_MSS/4; + tcph->check = cheat_check(oldval ^ 0xFFFF, + ((u_int16_t *)tcph)[6], tcph->check); + + newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); + iph->check = cheat_check(iph->tot_len ^ 0xFFFF, + newtotlen, iph->check); + iph->tot_len = newtotlen; + + DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu" + "->%u.%u.%u.%u:%hu added TCP MSS option (%u)\n", + NIPQUAD((*pskb)->nh.iph->saddr), + ntohs(tcph->source), + NIPQUAD((*pskb)->nh.iph->daddr), + ntohs(tcph->dest), + newmss); + + retmodified: + /* If we had a hardware checksum before, it's now invalid */ + (*pskb)->ip_summed = CHECKSUM_NONE; + (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; + return IPT_CONTINUE; +} + +#define TH_SYN 0x02 + +static inline int find_syn_match(const struct ipt_entry_match *m) +{ + const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data; + + if (strcmp(m->u.kernel.match->name, "tcp") == 0 + && (tcpinfo->flg_cmp & TH_SYN) + && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS)) + return 1; + + return 0; +} + +/* Must specify -p tcp --syn/--tcp-flags SYN */ +static int +ipt_tcpmss_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + const struct ipt_tcpmss_info *tcpmssinfo = targinfo; + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) { + DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n", + targinfosize, IPT_ALIGN(sizeof(struct ipt_tcpmss_info))); + return 0; + } + + + if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && + ((hook_mask & ~((1 << NF_IP_FORWARD) + | (1 << NF_IP_LOCAL_OUT) + | (1 << NF_IP_POST_ROUTING))) != 0)) { + printk("TCPMSS: path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n"); + return 0; + } + + if (e->ip.proto == IPPROTO_TCP + && !(e->ip.invflags & IPT_INV_PROTO) + && IPT_MATCH_ITERATE(e, find_syn_match)) + return 1; + + printk("TCPMSS: Only works on TCP SYN packets\n"); + return 0; +} + +static struct ipt_target ipt_tcpmss_reg += { { NULL, NULL }, "TCPMSS", + ipt_tcpmss_target, ipt_tcpmss_checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_target(&ipt_tcpmss_reg); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_tcpmss_reg); +} + +module_init(init); +module_exit(fini); diff -u --recursive --new-file v2.4.2/linux/net/ipv4/netfilter/ipt_tcpmss.c linux/net/ipv4/netfilter/ipt_tcpmss.c --- v2.4.2/linux/net/ipv4/netfilter/ipt_tcpmss.c Wed Dec 31 16:00:00 1969 +++ linux/net/ipv4/netfilter/ipt_tcpmss.c Tue Mar 6 22:44:16 2001 @@ -0,0 +1,108 @@ +/* Kernel module to match TCP MSS values. */ +#include +#include +#include + +#include +#include + +#define TH_SYN 0x02 + +/* Returns 1 if the mss option is set and matched by the range, 0 otherwise */ +static inline int +mssoption_match(u_int16_t min, u_int16_t max, + const struct tcphdr *tcp, + u_int16_t datalen, + int invert, + int *hotdrop) +{ + unsigned int i; + const u_int8_t *opt = (u_int8_t *)tcp; + + /* If we don't have the whole header, drop packet. */ + if (tcp->doff * 4 > datalen) { + *hotdrop = 1; + return 0; + } + + for (i = sizeof(struct tcphdr); i < tcp->doff * 4; ) { + if ((opt[i] == TCPOPT_MSS) + && ((tcp->doff * 4 - i) >= TCPOLEN_MSS) + && (opt[i+1] == TCPOLEN_MSS)) { + u_int16_t mssval; + + mssval = (opt[i+2] << 8) | opt[i+3]; + + return (mssval >= min && mssval <= max) ^ invert; + } + if (opt[i] < 2) i++; + else i += opt[i+1]?:1; + } + + return invert; +} + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_tcpmss_match_info *info = matchinfo; + const struct tcphdr *tcph = (void *)skb->nh.iph + skb->nh.iph->ihl*4; + + return mssoption_match(info->mss_min, info->mss_max, tcph, + skb->len - skb->nh.iph->ihl*4, + info->invert, hotdrop); +} + +static inline int find_syn_match(const struct ipt_entry_match *m) +{ + const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data; + + if (strcmp(m->u.kernel.match->name, "tcp") == 0 + && (tcpinfo->flg_cmp & TH_SYN) + && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS)) + return 1; + + return 0; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_tcpmss_match_info))) + return 0; + + /* Must specify -p tcp */ + if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) { + printk("tcpmss: Only works on TCP packets\n"); + return 0; + } + + return 1; +} + +static struct ipt_match tcpmss_match += { { NULL, NULL }, "tcpmss", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&tcpmss_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&tcpmss_match); +} + +module_init(init); +module_exit(fini); diff -u --recursive --new-file v2.4.2/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v2.4.2/linux/net/ipx/af_ipx.c Wed Feb 21 18:20:47 2001 +++ linux/net/ipx/af_ipx.c Tue Mar 6 19:28:33 2001 @@ -450,11 +450,12 @@ spin_lock_bh(&ipx_interfaces_lock); for (i = ipx_interfaces; i;) { tmp = i->if_next; - if (i->if_dev == dev) + if (i->if_dev == dev) { if (event == NETDEV_UP) ipxitf_hold(i); else __ipxitf_put(i); + } i = tmp; } spin_unlock_bh(&ipx_interfaces_lock); diff -u --recursive --new-file v2.4.2/linux/net/irda/af_irda.c linux/net/irda/af_irda.c --- v2.4.2/linux/net/irda/af_irda.c Sat Feb 3 19:51:33 2001 +++ linux/net/irda/af_irda.c Fri Mar 2 11:12:12 2001 @@ -146,7 +146,7 @@ /* Close our TSAP. * If we leave it open, IrLMP put it back into the list of - * unconnected LSAPs. The problem is that any incomming request + * unconnected LSAPs. The problem is that any incoming request * can then be matched to this socket (and it will be, because * it is at the head of the list). This would prevent any * listening socket waiting on the same TSAP to get those requests. @@ -229,7 +229,7 @@ /* * Function irda_connect_indication(instance, sap, qos, max_sdu_size, userdata) * - * Incomming connection + * Incoming connection * */ static void irda_connect_indication(void *instance, void *sap, @@ -285,7 +285,7 @@ /* * Function irda_connect_response (handle) * - * Accept incomming connection + * Accept incoming connection * */ void irda_connect_response(struct irda_sock *self) @@ -836,7 +836,7 @@ /* * Function irda_accept (sock, newsock, flags) * - * Wait for incomming connection + * Wait for incoming connection * */ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) @@ -1995,6 +1995,9 @@ if (get_user(len, optlen)) return -EFAULT; + if(optlen < 0) + return -EINVAL; + switch (optname) { case IRLMP_ENUMDEVICES: /* Ask lmp for the current discovery log */ diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_core.c linux/net/irda/ircomm/ircomm_core.c --- v2.4.2/linux/net/irda/ircomm/ircomm_core.c Mon Nov 27 18:07:31 2000 +++ linux/net/irda/ircomm/ircomm_core.c Fri Mar 2 11:12:12 2001 @@ -220,7 +220,7 @@ /* * Function ircomm_connect_indication (self, qos, skb) * - * Notify user layer about the incomming connection + * Notify user layer about the incoming connection * */ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_event.c linux/net/irda/ircomm/ircomm_event.c --- v2.4.2/linux/net/irda/ircomm/ircomm_event.c Tue Dec 21 10:17:58 1999 +++ linux/net/irda/ircomm/ircomm_event.c Fri Mar 2 11:12:12 2001 @@ -151,7 +151,7 @@ /* * Function ircomm_state_waitr (self, event, skb) * - * IrCOMM has received an incomming connection request and is awaiting + * IrCOMM has received an incoming connection request and is awaiting * response from the user */ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_lmp.c linux/net/irda/ircomm/ircomm_lmp.c --- v2.4.2/linux/net/irda/ircomm/ircomm_lmp.c Tue Dec 21 10:17:58 1999 +++ linux/net/irda/ircomm/ircomm_lmp.c Fri Mar 2 11:12:12 2001 @@ -219,7 +219,7 @@ /* * Function ircomm_lmp_data_indication (instance, sap, skb) * - * Incomming data which we must deliver to the state machine, to check + * Incoming data which we must deliver to the state machine, to check * we are still connected. */ int ircomm_lmp_data_indication(void *instance, void *sap, diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_ttp.c linux/net/irda/ircomm/ircomm_ttp.c --- v2.4.2/linux/net/irda/ircomm/ircomm_ttp.c Tue Dec 21 10:17:58 1999 +++ linux/net/irda/ircomm/ircomm_ttp.c Fri Mar 2 11:12:12 2001 @@ -156,7 +156,7 @@ /* * Function ircomm_ttp_data_indication (instance, sap, skb) * - * Incomming data + * Incoming data * */ int ircomm_ttp_data_indication(void *instance, void *sap, diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c --- v2.4.2/linux/net/irda/ircomm/ircomm_tty.c Mon Nov 27 18:07:31 2000 +++ linux/net/irda/ircomm/ircomm_tty.c Fri Mar 2 11:12:12 2001 @@ -1106,7 +1106,7 @@ /* * Function ircomm_tty_data_indication (instance, sap, skb) * - * Handle incomming data, and deliver it to the line discipline + * Handle incoming data, and deliver it to the line discipline * */ static int ircomm_tty_data_indication(void *instance, void *sap, @@ -1155,7 +1155,7 @@ /* * Function ircomm_tty_control_indication (instance, sap, skb) * - * Parse all incomming parameters (easy!) + * Parse all incoming parameters (easy!) * */ static int ircomm_tty_control_indication(void *instance, void *sap, diff -u --recursive --new-file v2.4.2/linux/net/irda/irias_object.c linux/net/irda/irias_object.c --- v2.4.2/linux/net/irda/irias_object.c Mon Jan 1 09:54:07 2001 +++ linux/net/irda/irias_object.c Fri Mar 2 11:12:12 2001 @@ -162,7 +162,7 @@ ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); ASSERT(attrib != NULL, return -1;); - /* Remove atribute from object */ + /* Remove attribute from object */ node = hashbin_remove(obj->attribs, 0, attrib->name); if (!node) return 0; /* Already removed or non-existent */ diff -u --recursive --new-file v2.4.2/linux/net/irda/irlan/irlan_provider.c linux/net/irda/irlan/irlan_provider.c --- v2.4.2/linux/net/irda/irlan/irlan_provider.c Sat Nov 11 18:11:23 2000 +++ linux/net/irda/irlan/irlan_provider.c Fri Mar 2 11:12:12 2001 @@ -162,7 +162,7 @@ /* * Function irlan_provider_connect_response (handle) * - * Accept incomming connection + * Accept incoming connection * */ void irlan_provider_connect_response(struct irlan_cb *self, @@ -371,7 +371,7 @@ /* * Function irlan_provider_register(void) * - * Register provider support so we can accept incomming connections. + * Register provider support so we can accept incoming connections. * */ int irlan_provider_open_ctrl_tsap(struct irlan_cb *self) diff -u --recursive --new-file v2.4.2/linux/net/irda/irlap.c linux/net/irda/irlap.c --- v2.4.2/linux/net/irda/irlap.c Wed Feb 21 18:20:47 2001 +++ linux/net/irda/irlap.c Fri Mar 2 11:12:12 2001 @@ -51,6 +51,7 @@ hashbin_t *irlap = NULL; int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ; +extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb); static void __irlap_close(struct irlap_cb *self); static char *lap_reasons[] = { @@ -241,7 +242,7 @@ /* * Function irlap_connect_response (self, skb) * - * Service user has accepted incomming connection + * Service user has accepted incoming connection * */ void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) diff -u --recursive --new-file v2.4.2/linux/net/irda/irlap_comp.c linux/net/irda/irlap_comp.c --- v2.4.2/linux/net/irda/irlap_comp.c Sat Nov 11 18:11:22 2000 +++ linux/net/irda/irlap_comp.c Fri Mar 2 11:12:12 2001 @@ -92,7 +92,7 @@ /* * Function irda_set_compression (self, proto) * - * The the compression protocol to be used by this session + * The compression protocol to be used by this session * */ int irda_set_compression( struct irlap_cb *self, int proto) diff -u --recursive --new-file v2.4.2/linux/net/irda/irlap_event.c linux/net/irda/irlap_event.c --- v2.4.2/linux/net/irda/irlap_event.c Wed Feb 21 18:20:47 2001 +++ linux/net/irda/irlap_event.c Fri Mar 2 11:12:12 2001 @@ -546,7 +546,7 @@ break; case SLOT_TIMER_EXPIRED: /* - * Wait a little longer if we detect an incomming frame. This + * Wait a little longer if we detect an incoming frame. This * is not mentioned in the spec, but is a good thing to do, * since we want to work even with devices that violate the * timing requirements. diff -u --recursive --new-file v2.4.2/linux/net/irda/irlmp.c linux/net/irda/irlmp.c --- v2.4.2/linux/net/irda/irlmp.c Wed Feb 21 18:20:47 2001 +++ linux/net/irda/irlmp.c Fri Mar 2 11:12:12 2001 @@ -450,7 +450,7 @@ /* * Function irlmp_connect_indication (self) * - * Incomming connection + * Incoming connection * */ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) diff -u --recursive --new-file v2.4.2/linux/net/irda/irlmp_frame.c linux/net/irda/irlmp_frame.c --- v2.4.2/linux/net/irda/irlmp_frame.c Sat Nov 11 18:11:23 2000 +++ linux/net/irda/irlmp_frame.c Fri Mar 2 11:12:12 2001 @@ -470,7 +470,7 @@ lsap = (struct lsap_cb *) hashbin_get_first(queue); while (lsap != NULL) { /* - * If this is an incomming connection, then the destination + * If this is an incoming connection, then the destination * LSAP selector may have been specified as LM_ANY so that * any client can connect. In that case we only need to check * if the source LSAP (in our view!) match! diff -u --recursive --new-file v2.4.2/linux/net/irda/irnet/Config.in linux/net/irda/irnet/Config.in --- v2.4.2/linux/net/irda/irnet/Config.in Sat Nov 11 18:11:23 2000 +++ linux/net/irda/irnet/Config.in Fri Mar 2 11:12:12 2001 @@ -1 +1,4 @@ -dep_tristate ' IrNET protocol' CONFIG_IRNET $CONFIG_IRDA +if [ "$CONFIG_NETDEVICES" != "n" ]; then + dep_tristate ' IrNET protocol' CONFIG_IRNET $CONFIG_IRDA $CONFIG_PPP +fi + diff -u --recursive --new-file v2.4.2/linux/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h --- v2.4.2/linux/net/irda/irnet/irnet.h Mon Dec 11 13:33:14 2000 +++ linux/net/irda/irnet/irnet.h Fri Mar 2 11:12:12 2001 @@ -9,7 +9,7 @@ * what's in there... * * Note : as most part of the Linux kernel, this module is available - * under the GNU Public License (GPL). + * under the GNU General Public License (GPL). */ #ifndef IRNET_H @@ -52,14 +52,14 @@ * o multipoint operation (limited by IrLAP specification) * o information in /proc/net/irda/irnet * o IrNET events on /dev/irnet (for user space daemon) - * o IrNET deamon (irnetd) to automatically handle incomming requests + * o IrNET deamon (irnetd) to automatically handle incoming requests * o Windows 2000 compatibility (tested, but need more work) * Currently missing : * o Lot's of testing (that's your job) * o Connection retries (may be too hard to do) * o Check pppd persist mode - * o User space deamon (to automatically handle incomming requests) - * o A registered device number (comming, waiting from an answer) + * o User space deamon (to automatically handle incoming requests) + * o A registered device number (coming, waiting from an answer) * o Final integration in Linux-IrDA (up to Dag) * * The setup is not currently the most easy, but this should get much @@ -109,16 +109,16 @@ * and allow to offer the event channel, useful for other stuff like debug. * * On the other hand, this require a loose coordination between the - * present module and irnetd. One critical area is how incomming request + * present module and irnetd. One critical area is how incoming request * are handled. - * When irnet receive an incomming request, it send an event to irnetd and - * drop the incomming IrNET socket. + * When irnet receive an incoming request, it send an event to irnetd and + * drop the incoming IrNET socket. * irnetd start a pppd instance, which create a new IrNET socket. This new * socket is then connected in the originating node to the pppd instance. * At this point, in the originating node, the first socket is closed. * * I admit, this is a bit messy and waste some ressources. The alternative - * is caching incomming socket, and that's also quite messy and waste + * is caching incoming socket, and that's also quite messy and waste * ressources. * We also make connection time slower. For example, on a 115 kb/s link it * adds 60ms to the connection time (770 ms). However, this is slower than diff -u --recursive --new-file v2.4.2/linux/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c --- v2.4.2/linux/net/irda/irnet/irnet_irda.c Sun Nov 12 20:40:42 2000 +++ linux/net/irda/irnet/irnet_irda.c Fri Mar 2 11:12:12 2001 @@ -523,7 +523,7 @@ /* * The IrNET service is composed of one server socket and a variable * number of regular IrNET sockets. The server socket is supposed to - * handle incomming connections and redirect them to one IrNET sockets. + * handle incoming connections and redirect them to one IrNET sockets. * It's a superset of the regular IrNET socket, but has a very distinct * behaviour... */ @@ -662,7 +662,7 @@ /* * Function irda_connect_socket (self) * - * Connect an incomming connection to the socket + * Connect an incoming connection to the socket * */ static inline int @@ -721,7 +721,7 @@ /* * Function irda_disconnect_server (self) * - * Cleanup the server socket when the incomming connection abort + * Cleanup the server socket when the incoming connection abort * */ static inline void @@ -1097,7 +1097,7 @@ /* * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata) * - * Incomming connection + * Incoming connection * * In theory, this function is called only on the server socket. * Some other node is attempting to connect to the IrNET service, and has diff -u --recursive --new-file v2.4.2/linux/net/sched/Makefile linux/net/sched/Makefile --- v2.4.2/linux/net/sched/Makefile Fri Dec 29 14:07:24 2000 +++ linux/net/sched/Makefile Tue Mar 6 22:44:15 2001 @@ -1,182 +1,34 @@ # # Makefile for the Linux Traffic Control Unit. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := sched.o obj-y := sch_generic.o -ifeq ($(CONFIG_NET_SCHED), y) -obj-y += sch_api.o sch_fifo.o - -ifeq ($(CONFIG_NET_ESTIMATOR), y) -obj-y += estimator.o -endif - -ifeq ($(CONFIG_NET_CLS), y) -obj-y += cls_api.o - -ifeq ($(CONFIG_NET_CLS_POLICE), y) -obj-y += police.o -endif - -endif - -ifeq ($(CONFIG_NET_SCH_INGRESS), y) -obj-y += sch_ingress.o -else - ifeq ($(CONFIG_NET_SCH_INGRESS), m) - obj-m += sch_ingress.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_CBQ), y) -obj-y += sch_cbq.o -else - ifeq ($(CONFIG_NET_SCH_CBQ), m) - obj-m += sch_cbq.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_CSZ), y) -obj-y += sch_csz.o -else - ifeq ($(CONFIG_NET_SCH_CSZ), m) - obj-m += sch_csz.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_HPFQ), y) -obj-y += sch_hpfq.o -else - ifeq ($(CONFIG_NET_SCH_HPFQ), m) - obj-m += sch_hpfq.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_HFSC), y) -obj-y += sch_hfsc.o -else - ifeq ($(CONFIG_NET_SCH_HFSC), m) - obj-m += sch_hfsc.o - endif -endif - - -ifeq ($(CONFIG_NET_SCH_SFQ), y) -obj-y += sch_sfq.o -else - ifeq ($(CONFIG_NET_SCH_SFQ), m) - obj-m += sch_sfq.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_RED), y) -obj-y += sch_red.o -else - ifeq ($(CONFIG_NET_SCH_RED), m) - obj-m += sch_red.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_TBF), y) -obj-y += sch_tbf.o -else - ifeq ($(CONFIG_NET_SCH_TBF), m) - obj-m += sch_tbf.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_PRIO), y) -obj-y += sch_prio.o -else - ifeq ($(CONFIG_NET_SCH_PRIO), m) - obj-m += sch_prio.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_TEQL), y) -obj-y += sch_teql.o -else - ifeq ($(CONFIG_NET_SCH_TEQL), m) - obj-m += sch_teql.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_GRED), y) -obj-y += sch_gred.o -else - ifeq ($(CONFIG_NET_SCH_GRED), m) - obj-m += sch_gred.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_DSMARK), y) -obj-y += sch_dsmark.o -else - ifeq ($(CONFIG_NET_SCH_DSMARK), m) - obj-m += sch_dsmark.o - endif -endif - -ifeq ($(CONFIG_NET_CLS_TCINDEX), y) -obj-y += cls_tcindex.o -else - ifeq ($(CONFIG_NET_CLS_TCINDEX), m) - obj-m += cls_tcindex.o - endif -endif - -ifeq ($(CONFIG_NET_SCH_ATM), y) -obj-y += sch_atm.o -endif - -ifeq ($(CONFIG_NET_CLS_U32), y) -obj-y += cls_u32.o -else - ifeq ($(CONFIG_NET_CLS_U32), m) - obj-m += cls_u32.o - endif -endif - -ifeq ($(CONFIG_NET_CLS_RSVP), y) -obj-y += cls_rsvp.o -else - ifeq ($(CONFIG_NET_CLS_RSVP), m) - obj-m += cls_rsvp.o - endif -endif - -ifeq ($(CONFIG_NET_CLS_RSVP6), y) -obj-y += cls_rsvp6.o -else - ifeq ($(CONFIG_NET_CLS_RSVP6), m) - obj-m += cls_rsvp6.o - endif -endif - -ifeq ($(CONFIG_NET_CLS_ROUTE4), y) -obj-y += cls_route.o -else - ifeq ($(CONFIG_NET_CLS_ROUTE4), m) - obj-m += cls_route.o - endif -endif - -ifeq ($(CONFIG_NET_CLS_FW), y) -obj-y += cls_fw.o -else - ifeq ($(CONFIG_NET_CLS_FW), m) - obj-m += cls_fw.o - endif -endif - -endif +obj-$(CONFIG_NET_SCHED) += sch_api.o sch_fifo.o +obj-$(CONFIG_NET_ESTIMATOR) += estimator.o +obj-$(CONFIG_NET_CLS) += cls_api.o +obj-$(CONFIG_NET_CLS_POLICE) += police.o +obj-$(CONFIG_NET_SCH_INGRESS) += sch_ingress.o +obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o +obj-$(CONFIG_NET_SCH_CSZ) += sch_csz.o +obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o +obj-$(CONFIG_NET_SCH_HFSC) += sch_hfsc.o +obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o +obj-$(CONFIG_NET_SCH_RED) += sch_red.o +obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o +obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o +obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o +obj-$(CONFIG_NET_SCH_GRED) += sch_gred.o +obj-$(CONFIG_NET_SCH_DSMARK) += sch_dsmark.o +obj-$(CONFIG_NET_CLS_TCINDEX) += cls_tcindex.o +obj-$(CONFIG_NET_SCH_ATM) += sch_atm.o +obj-$(CONFIG_NET_CLS_U32) += cls_u32.o +obj-$(CONFIG_NET_CLS_RSVP) += cls_rsvp.o +obj-$(CONFIG_NET_CLS_RSVP6) += cls_rsvp6.o +obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o +obj-$(CONFIG_NET_CLS_FW) += cls_fw.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.2/linux/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c --- v2.4.2/linux/net/sched/cls_tcindex.c Fri Aug 18 10:26:25 2000 +++ linux/net/sched/cls_tcindex.c Tue Mar 6 22:44:15 2001 @@ -339,7 +339,7 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker) { struct tcindex_data *p = PRIV(tp); - struct tcindex_filter *f; + struct tcindex_filter *f,*next; int i; DPRINTK("tcindex_walk(tp %p,walker %p),p %p\n",tp,walker,p); @@ -361,7 +361,8 @@ if (!p->h) return; for (i = 0; i < p->hash; i++) { - for (f = p->h[i]; f; f = f->next) { + for (f = p->h[i]; f; f = next) { + next = f->next; if (walker->count >= walker->skip) { if (walker->fn(tp,(unsigned long) &f->result, walker) < 0) { diff -u --recursive --new-file v2.4.2/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c --- v2.4.2/linux/net/sched/sch_cbq.c Tue Jul 11 19:02:37 2000 +++ linux/net/sched/sch_cbq.c Tue Mar 6 22:44:15 2001 @@ -506,7 +506,7 @@ } } - q->wd_expires = delay; + q->wd_expires = base_delay; } } diff -u --recursive --new-file v2.4.2/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c --- v2.4.2/linux/net/sunrpc/svcsock.c Wed Feb 21 18:20:50 2001 +++ linux/net/sunrpc/svcsock.c Mon Mar 12 18:13:28 2001 @@ -212,16 +212,22 @@ svc_sock_release(struct svc_rqst *rqstp) { struct svc_sock *svsk = rqstp->rq_sock; + struct svc_serv *serv = svsk->sk_server; if (!svsk) return; svc_release_skb(rqstp); rqstp->rq_sock = NULL; + + spin_lock_bh(&serv->sv_lock); if (!--(svsk->sk_inuse) && svsk->sk_dead) { + spin_unlock_bh(&serv->sv_lock); dprintk("svc: releasing dead socket\n"); sock_release(svsk->sk_sock); kfree(svsk); } + else + spin_unlock_bh(&serv->sv_lock); } /* @@ -1034,14 +1040,15 @@ if (svsk->sk_qued) rpc_remove_list(&serv->sv_sockets, svsk); - spin_unlock_bh(&serv->sv_lock); svsk->sk_dead = 1; if (!svsk->sk_inuse) { + spin_unlock_bh(&serv->sv_lock); sock_release(svsk->sk_sock); kfree(svsk); } else { + spin_unlock_bh(&serv->sv_lock); printk(KERN_NOTICE "svc: server socket destroy delayed\n"); /* svsk->sk_server = NULL; */ } diff -u --recursive --new-file v2.4.2/linux/net/unix/af_unix.c linux/net/unix/af_unix.c --- v2.4.2/linux/net/unix/af_unix.c Wed Feb 21 18:20:50 2001 +++ linux/net/unix/af_unix.c Tue Mar 6 19:44:37 2001 @@ -1852,8 +1852,8 @@ extern void unix_sysctl_register(void); extern void unix_sysctl_unregister(void); #else -static inline unix_sysctl_register() {}; -static inline unix_sysctl_unregister() {}; +static inline void unix_sysctl_register(void) {} +static inline void unix_sysctl_unregister(void) {} #endif static const char banner[] __initdata = KERN_INFO "NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.\n"; diff -u --recursive --new-file v2.4.2/linux/scripts/mkdep.c linux/scripts/mkdep.c --- v2.4.2/linux/scripts/mkdep.c Wed Sep 27 14:09:30 2000 +++ linux/scripts/mkdep.c Fri Mar 2 11:12:12 2001 @@ -2,7 +2,7 @@ * Originally by Linus Torvalds. * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain. * - * Usage: mkdep file ... + * Usage: mkdep cflags -- file ... * * Read source files and output makefile dependency lines for them. * I make simple dependency lines for #include <*.h> and #include "*.h". @@ -22,10 +22,17 @@ * 2.3.99-pre1, Andrew Morton * - Changed so that 'filename.o' depends upon 'filename.[cS]'. This is so that * missing source files are noticed, rather than silently ignored. + * + * 2.4.2-pre3, Keith Owens + * - Accept cflags followed by '--' followed by filenames. mkdep extracts -I + * options from cflags and looks in the specified directories as well as the + * defaults. Only -I is supported, no attempt is made to handle -idirafter, + * -isystem, -I- etc. */ #include #include +#include #include #include #include @@ -44,11 +51,10 @@ struct path_struct { int len; - char buffer[256-sizeof(int)]; -} path_array[2] = { - { 0, "" }, - { 0, "" } + char *buffer; }; +struct path_struct *path_array; +int paths; /* Current input file */ @@ -181,9 +187,10 @@ /* * Handle an #include line. */ -void handle_include(int type, const char * name, int len) +void handle_include(int start, const char * name, int len) { - struct path_struct *path = path_array+type; + struct path_struct *path; + int i; if (len == 14 && !memcmp(name, "linux/config.h", len)) return; @@ -191,13 +198,58 @@ if (len >= 7 && !memcmp(name, "config/", 7)) define_config(name+7, len-7-2); - memcpy(path->buffer+path->len, name, len); - path->buffer[path->len+len] = '\0'; - if (access(path->buffer, F_OK) != 0) - return; + for (i = start, path = path_array+start; i < paths; ++i, ++path) { + memcpy(path->buffer+path->len, name, len); + path->buffer[path->len+len] = '\0'; + if (access(path->buffer, F_OK) == 0) { + do_depname(); + printf(" \\\n %s", path->buffer); + return; + } + } - do_depname(); - printf(" \\\n %s", path->buffer); +} + + + +/* + * Add a path to the list of include paths. + */ +void add_path(const char * name) +{ + struct path_struct *path; + char resolved_path[PATH_MAX+1]; + const char *name2; + + if (strcmp(name, ".")) { + name2 = realpath(name, resolved_path); + if (!name2) { + fprintf(stderr, "realpath(%s) failed, %m\n", name); + exit(1); + } + } + else { + name2 = ""; + } + + path_array = realloc(path_array, (++paths)*sizeof(*path_array)); + if (!path_array) { + fprintf(stderr, "cannot expand path_arry\n"); + exit(1); + } + + path = path_array+paths-1; + path->len = strlen(name2); + path->buffer = malloc(path->len+1+256+1); + if (!path->buffer) { + fprintf(stderr, "cannot allocate path buffer\n"); + exit(1); + } + strcpy(path->buffer, name2); + if (path->len && *(path->buffer+path->len-1) != '/') { + *(path->buffer+path->len) = '/'; + *(path->buffer+(++(path->len))) = '\0'; + } } @@ -210,7 +262,7 @@ char *pc; int i; - pc = path_array[0].buffer + path_array[0].len; + pc = path_array[paths-1].buffer + path_array[paths-1].len; memcpy(pc, "config/", 7); pc += 7; @@ -228,7 +280,7 @@ define_config(pc, len); do_depname(); - printf(" \\\n $(wildcard %s.h)", path_array[0].buffer); + printf(" \\\n $(wildcard %s.h)", path_array[paths-1].buffer); } @@ -387,7 +439,7 @@ GETNEXT CASE('\n', start); NOTCASE('"', pound_include_dquote); - handle_include(1, map_dot, next - map_dot - 1); + handle_include(0, map_dot, next - map_dot - 1); goto start; /* #\s*include\s*<(.*)> */ @@ -395,7 +447,7 @@ GETNEXT CASE('\n', start); NOTCASE('>', pound_include_langle); - handle_include(0, map_dot, next - map_dot - 1); + handle_include(1, map_dot, next - map_dot - 1); goto start; /* #\s*d */ @@ -524,7 +576,7 @@ int main(int argc, char **argv) { int len; - char *hpath; + const char *hpath; hpath = getenv("HPATH"); if (!hpath) { @@ -532,12 +584,26 @@ "Don't bypass the top level Makefile.\n", stderr); return 1; } - len = strlen(hpath); - memcpy(path_array[0].buffer, hpath, len); - if (len && hpath[len-1] != '/') - path_array[0].buffer[len++] = '/'; - path_array[0].buffer[len] = '\0'; - path_array[0].len = len; + + add_path("."); /* for #include "..." */ + + while (++argv, --argc > 0) { + if (strncmp(*argv, "-I", 2) == 0) { + if (*((*argv)+2)) { + add_path((*argv)+2); + } + else { + ++argv; + --argc; + add_path(*argv); + } + } + else if (strcmp(*argv, "--") == 0) { + break; + } + } + + add_path(hpath); /* must be last entry, for config files */ while (--argc > 0) { const char * filename = *++argv; diff -u --recursive --new-file v2.4.2/linux/scripts/ver_linux linux/scripts/ver_linux --- v2.4.2/linux/scripts/ver_linux Sun Sep 17 09:45:06 2000 +++ linux/scripts/ver_linux Fri Mar 2 11:12:12 2001 @@ -5,30 +5,64 @@ # differ on your system. # PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH -echo '-- Versions installed: (if some fields are empty or look' -echo '-- unusual then possibly you have very old versions)' +echo 'If some fields are empty or look unusual you may have an old version.' +echo 'Compare to the current minimal requirements in Documentation/Changes.' +echo ' ' + uname -a -insmod -V 2>&1 | awk 'NR==1 {print "Kernel modules ",$NF}' +echo ' ' + echo "Gnu C " `gcc --version` + make --version 2>&1 | awk -F, '{print $1}' | awk \ - '/GNU Make/{print "Gnu Make ",$NF}' + '/GNU Make/{print "Gnu make ",$NF}' + ld -v 2>&1 | awk -F\) '{print $1}' | awk \ - '/BFD/{print "Binutils ",$NF}' -ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed -e 's/\.so$//' \ - | awk -F'[.-]' '{print "Linux C Library " $(NF-2)"."$(NF-1)"."$NF}' -echo -n "Dynamic linker " -ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1 + '/BFD/{print "binutils ",$NF}' + +mount --version | awk -F\- '{print "util-linux ", $NF}' + +insmod -V 2>&1 | awk 'NR==1 {print "modutils ",$NF}' + +tune2fs 2>&1 | grep tune2fs | sed 's/,//' | awk \ +'NR==1 {print "e2fsprogs ", $2}' + +reiserfsck 2>&1 | grep reiserfsprogs | awk \ +'NR==1{print "reiserfsprogs ", $NF}' + +cardmgr -V 2>&1| grep version | awk \ +'NR==1{print "pcmcia-cs ", $3}' + +pppd --version 2>&1| grep version | awk \ +'NR==1{print "PPP ", $3}' + +isdnctrl 2>&1 | grep version | awk \ +'NR==1{print "isdn4k-utils ", $NF}' + +ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed \ +-e 's/\.so$//' | awk -F'[.-]' '{print "Linux C Library " \ +$(NF-2)"."$(NF-1)"."$NF}' + +ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1 | awk \ +'NR==1{print "Dynamic linker (ldd) ", $NF}' + ls -l /usr/lib/lib{g,stdc}++.so 2>/dev/null | awk -F. \ '{print "Linux C++ Library " $4"."$5"."$6}' + ps --version 2>&1 | awk 'NR==1{print "Procps ", $NF}' -mount --version | awk -F\- '{print "Mount ", $NF}' -hostname -V 2>&1 | awk 'NR==1{print "Net-tools ", $NF}' + +ifconfig --version 2>&1 | grep tools | awk \ +'NR==1{print "Net-tools ", $NF}' + # Kbd needs 'loadkeys -h', loadkeys -h 2>&1 | awk \ '(NR==1 && ($3 !~ /option/)) {print "Kbd ", $3}' + # while console-tools needs 'loadkeys -V'. loadkeys -V 2>&1 | awk \ '(NR==1 && ($2 ~ /console-tools/)) {print "Console-tools ", $3}' + expr --v 2>&1 | awk 'NR==1{print "Sh-utils ", $NF}' + X=`cat /proc/modules | sed -e "s/ .*$//"` echo "Modules Loaded "$X