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 Sun Mar 25 18:14:20 2001 @@ -307,8 +307,8 @@ D: Original author of the Linux networking code N: Anton Blanchard -E: anton@linuxcare.com -W: http://linuxcare.com.au/anton/ +E: anton@samba.org +W: http://samba.org/~anton/ P: 1024/8462A731 4C 55 86 34 44 59 A7 99 2B 97 88 4A 88 9A 0D 97 D: sun4 port, Sparc hacker S: 47 Robert Street @@ -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 @@ -331,9 +331,6 @@ D: AUN network protocols D: Co-architect of the parallel port sharing system D: IPv6 netfilter -S: FutureTV Labs Ltd -S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG -S: United Kingdom N: Thomas Bogendörfer E: tsbogend@alpha.franken.de @@ -679,12 +676,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 +1019,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 +1340,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 +2182,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 Sun Mar 25 18:24:31 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. @@ -7358,6 +7474,24 @@ location). You also want to check out the PCMCIA-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . +Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards) +CONFIG_PCMCIA_HERMES + A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + It should also be usable on various Prism II based cards such as the + Linksys, D-Link and Farallon Skyline. It should also work on Symbol + cards such as the 3Com AirConnect and Ericsson WLAN. + + To use your PC-cards, you will need supporting software from David + Hinds' pcmcia-cs package (see the file Documentation/Changes for + location). You also want to check out the PCMCIA-HOWTO, available + from http://www.linuxdoc.org/docs.html#howto . + + You will also very likely also need the Wireless Tools in order to + configure your card and that /etc/pcmcia/wireless.opts works : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html + Aviator/Raytheon 2.4MHz wireless support CONFIG_PCMCIA_RAYCS Say Y here if you intend to attach an Aviator/Raytheon PCMCIA @@ -8390,22 +8524,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 @@ -8418,6 +8536,26 @@ say M here and read Documentation/modules.txt. This is recommended. The module will be called 8139too.o. +Use PIO instead of MMIO +CONFIG_8139TOO_PIO + This instructs the driver to use programmed I/O ports (PIO) instead + of PCI shared memory (MMIO). This can possibly solve some problems in + case your mainboard has memory consistency issues. If unsure, say N. + +Support for automatic channel equalization (EXPERIMENTAL) +CONFIG_8139TOO_TUNE_TWISTER + This implements a function which might come in handy in case you are + using low quality on long cabling. It tries to match the transceiver + to the cable characteristics. This is experimental since hardly + documented by the manufacturer. If unsure, say N. + +Support for older RTL-8129/8130 boards +CONFIG_8139TOO_8129 + This enables support for the older and uncommon RTL-8129 and + RTL-8130 chips, which support MII via an external transceiver, instead + of an internal one. Disabling this option will save some memory + by making the code size smaller. If unsure, say Y. + SiS 900 PCI Fast Ethernet Adapter support CONFIG_SIS900 This is a driver for the Fast Ethernet PCI network cards based on @@ -8481,7 +8619,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 +9537,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 +9577,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 +9592,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 +9602,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 +9612,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 +9628,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 @@ -10514,6 +10652,32 @@ inserted in and removed from the running kernel whenever you want). The module will be called mct_u232.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. + +USB Edgeport Serial Driver +CONFIG_USB_SERIAL_EDGEPORT + Say Y here if you want to use any of the following devices from + Inside Out Networks (Digi): + Edgeport/4 + Rapidport/4 + Edgeport/4t + Edgeport/2 + Edgeport/4i + Edgeport/2i + Edgeport/421 + Edgeport/21 + Edgeport/8 + Edgeport/8 Dual + Edgeport/2D8 + Edgeport/4D8 + Edgeport/8i + Edgeport/2 DIN + Edgeport/4 DIN + Edgeport/16 Dual + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called io_edgeport.o. If you want to compile it + as a module, say M here and read Documentation/modules.txt. USB Serial Converter verbose debug CONFIG_USB_SERIAL_DEBUG 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/SAK.txt linux/Documentation/SAK.txt --- v2.4.2/linux/Documentation/SAK.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/SAK.txt Thu Mar 22 09:20:45 2001 @@ -0,0 +1,88 @@ +Linux 2.4.2 Secure Attention Key (SAK) handling +18 March 2001, Andrew Morton + +An operating system's Secure Attention Key is a security tool which is +provided as protection against trojan password capturing programs. It +is an undefeatable way of killing all programs which could be +masquerading as login applications. Users need to be taught to enter +this key sequence before they log in to the system. + +From the PC keyboard, Linux has two similar but different ways of +providing SAK. One is the ALT-SYSRQ-K sequence. You shouldn't use +this sequence. It is only available if the kernel was compiled with +sysrq support. + +The proper way of generating a SAK is to define the key sequence using +`loadkeys'. This will work whether or not sysrq support is compiled +into the kernel. + +SAK works correctly when the keyboard is in raw mode. This means that +once defined, SAK will kill a running X server. If the system is in +run level 5, the X server will restart. This is what you want to +happen. + +What key sequence should you use? Well, CTRL-ALT-DEL is used to reboot +the machine. CTRL-ALT-BACKSPACE is magical to the X server. We'll +choose CTRL-ALT-PAUSE. + +In your rc.sysinit (or rc.local) file, add the command + + echo "control alt keycode 101 = SAK" | /bin/loadkeys + +And that's it! Only the superuser may reprogram the SAK key. + + +NOTES +===== + +1: Linux SAK is said to be not a "true SAK" as is required by + systems which implement C2 level security. This author does not + know why. + + +2: On the PC keyboard, SAK kills all applications which have + /dev/console opened. + + Unfortunately this includes a number of things which you don't + actually want killed. This is because these appliccaitons are + incorrectly holding /dev/console open. Be sure to complain to your + Linux distributor about this! + + You can identify processes which will be killed by SAK with the + command + + # ls -l /proc/[0-9]*/fd/* | grep console + l-wx------ 1 root root 64 Mar 18 00:46 /proc/579/fd/0 -> /dev/console + + Then: + + # ps aux|grep 579 + root 579 0.0 0.1 1088 436 ? S 00:43 0:00 gpm -t ps/2 + + So `gpm' will be killed by SAK. This is a bug in gpm. It should + be closing standard input. You can work around this by finding the + initscript which launches gpm and changing it thusly: + + Old: + + daemon gpm + + New: + + daemon gpm < /dev/null + + Vixie cron also seems to have this problem, and needs the same treatment. + + Also, one prominent Linux distribution has the following three + lines in its rc.sysinit and rc scripts: + + exec 3<&0 + exec 4>&1 + exec 5>&2 + + These commands cause *all* daemons which are launched by the + initscripts to have file descriptors 3, 4 and 5 attached to + /dev/console. So SAK kills them all. A workaround is to simply + delete these lines, but this may cause system management + applications to malfunction - test everything well. + 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/cachetlb.txt linux/Documentation/cachetlb.txt --- v2.4.2/linux/Documentation/cachetlb.txt Sat Feb 3 19:51:21 2001 +++ linux/Documentation/cachetlb.txt Sun Mar 25 18:14:20 2001 @@ -229,9 +229,9 @@ mapped into some user address space, there is always at least one more mapping, that of the kernel in it's linear mapping starting at PAGE_OFFSET. So immediately, once the first user maps a given -physical page into it's address space, by implication the D-cache +physical page into its address space, by implication the D-cache aliasing problem has the potential to exist since the kernel already -maps this page at it's virtual address. +maps this page at its virtual address. First, I describe the old method to deal with this problem. I am describing it for documentation purposes, but it is deprecated and the @@ -252,11 +252,11 @@ Admittedly, the author did not think very much when designing this interface. It does not give the architecture enough information about -what exactly is going on, and there is not context with which to base -any judgment about whether an alias is possible at all. The new -interfaces to deal with D-cache aliasing are meant to address this by -telling the architecture specific code exactly which is going on at -the proper points in time. +what exactly is going on, and there is no context to base a judgment +on about whether an alias is possible at all. The new interfaces to +deal with D-cache aliasing are meant to address this by telling the +architecture specific code exactly which is going on at the proper points +in time. Here is the new interface: 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/i810_rng.txt linux/Documentation/i810_rng.txt --- v2.4.2/linux/Documentation/i810_rng.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/i810_rng.txt Sun Mar 25 18:24:31 2001 @@ -0,0 +1,123 @@ + Hardware driver for Intel i810 Random Number Generator (RNG) + Copyright 2000,2001 Jeff Garzik + Copyright 2000,2001 Philipp Rumpf + +Introduction: + + The i810_rng device driver is software that makes use of a + special hardware feature on the Intel i8xx-based chipsets, + a Random Number Generator (RNG). + + In order to make effective use of this device driver, you + should download the support software as well. Download the + latest version of the "intel-rng-tools" package from the + i810_rng driver's official Web site: + + http://sourceforge.net/projects/gkernel/ + +About the Intel RNG hardware, from the firmware hub datasheet: + + The Firmware Hub integrates a Random Number Generator (RNG) + using thermal noise generated from inherently random quantum + mechanical properties of silicon. When not generating new random + bits the RNG circuitry will enter a low power state. Intel will + provide a binary software driver to give third party software + access to our RNG for use as a security feature. At this time, + the RNG is only to be used with a system in an OS-present state. + +Theory of operation: + + Character driver. Using the standard open() + and read() system calls, you can read random data from + the i810 RNG device. This data is NOT CHECKED by any + fitness tests, and could potentially be bogus (if the + hardware is faulty or has been tampered with). Data is only + output if the hardware "has-data" flag is set, but nevertheless + a security-conscious person would run fitness tests on the + data before assuming it is truly random. + + /dev/intel_rng is char device major 10, minor 183. + +Driver notes: + + * FIXME: support poll(2) + + 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. + +Driver details: + + Based on: + Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet + May 1999 Order Number: 290658-002 R + + Intel 82802 Firmware Hub: Random Number Generator + Programmer's Reference Manual + December 1999 Order Number: 298029-001 R + + Intel 82802 Firmware HUB Random Number Generator Driver + Copyright (c) 2000 Matt Sottek + + Special thanks to Matt Sottek. I did the "guts", he + did the "brains" and all the testing. + +Change history: + + Version 0.9.5: + * Rip out entropy injection via timer. It never ever worked, + and a better solution (rngd) is now available. + + Version 0.9.4: + * Fix: Remove request_mem_region + * Fix: Horrible bugs in FIPS calculation and test execution + + 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.2: + * Simplify open blocking logic + + Version 0.9.1: + * Support i815 chipsets too (Matt Sottek) + * Fix reference counting when statically compiled (prumpf) + * Rewrite rng_dev_read (prumpf) + * Make module races less likely (prumpf) + * Small miscellaneous bug fixes (prumpf) + * Use pci table for PCI id list + + Version 0.9.0: + * Don't register a pci_driver, because we are really + using PCI bridge vendor/device ids, and someone + may want to register a driver for the bridge. (bug fix) + * Don't let the usage count go negative (bug fix) + * Clean up spinlocks (bug fix) + * Enable PCI device, if necessary (bug fix) + * iounmap on module unload (bug fix) + * If RNG chrdev is already in use when open(2) is called, + sleep until it is available. + * Remove redundant globals rng_allocated, rng_use_count + * Convert numeric globals to unsigned + * Module unload cleanup + + Version 0.6.2: + * Clean up spinlocks. Since we don't have any interrupts + to worry about, but we do have a timer to worry about, + we use spin_lock_bh everywhere except the timer function + itself. + * Fix module load/unload. + * Fix timer function and h/w enable/disable logic + * New timer interval sysctl + * Clean up sysctl names 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/00-INDEX linux/Documentation/isdn/00-INDEX --- v2.4.2/linux/Documentation/isdn/00-INDEX Fri Jul 28 12:50:51 2000 +++ linux/Documentation/isdn/00-INDEX Mon Mar 26 15:38:19 2001 @@ -40,4 +40,4 @@ _ info for running X.25 over ISDN. README.hysdn - info on driver for Hypercope active HYSDN cards - \ No newline at end of file + 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 Mon Mar 26 15:38:19 2001 @@ -1,4 +1,4 @@ -$Id: INTERFACE,v 1.15 1999/08/25 20:02:13 werner Exp $ +$Id: INTERFACE,v 1.15.8.2 2001/03/13 16:17:07 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 Mon Mar 26 15:38:19 2001 @@ -1,4 +1,4 @@ -$Id: README.eicon,v 1.10 2000/08/13 12:19:15 armin Exp $ +$Id: README.eicon,v 1.10.6.1 2001/02/19 10:04:59 armin Exp $ (c) 1999,2000 Armin Schindler (mac@melware.de) (c) 1999,2000 Cytronics & Melware (info@melware.de) @@ -99,17 +99,6 @@ Just use "eiconctrl isdnlog on" and the driver will generate 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 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 Sun Mar 25 18:24:31 2001 @@ -1,8 +1,10 @@ "8139too" Fast Ethernet driver for Linux - Improved support for RTL-8139 10/100 Fast Ethernet adapters + RTL-8139, -8129, and -8130 10/100 Fast Ethernet adapters - Copyright 2000 Jeff Garzik + Copyright 2000,2001 Jeff Garzik + + http://sourceforge.net/projects/gkernel/ Architectures supported (all PCI platforms): @@ -25,7 +27,7 @@ Requirements ------------ -Kernel 2.3.41 or later. +Kernel 2.4.3 or later. A Fast Ethernet adapter containing an RTL8139-based chip. @@ -95,6 +97,8 @@ AOpen ALN-325C KTI KF-230TX KTI KF-230TX/2 +Lantech FastNet TX +SMC EZNET 10/100 (please add your adapter model to this list) @@ -138,12 +142,13 @@ Submitting Bug Reports ---------------------- Obtain and compile the modified rtl8139-diag source code from the -8139too driver Web site. This diagnostics programs, originally -from Donald Becker, has been modified to display all registers -on your RTL8139 chip, not just the first 0x80. +8139too driver Web site, http://sourceforge.net/projects/gkernel/ +This diagnostics programs, originally from Donald Becker, has been +modified to display all registers on your RTL8139 chip, not just the +first 0x80. If possible, send the output of a working and broken driver with - rtl8139-diag -mmmaaavvveefN > my-output-file.txt + rtl8139-diag -mmaaavvveefN > my-output-file.txt Send "lspci -vvv" or "cat /proc/pci" output for PCI information. @@ -179,6 +184,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 diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt --- v2.4.2/linux/Documentation/networking/cs89x0.txt Mon Sep 18 14:58:17 2000 +++ linux/Documentation/networking/cs89x0.txt Sun Mar 25 18:24:31 2001 @@ -242,13 +242,18 @@ b) The "io" parameter must be specified on the command-line. -c) In case you can not re-load the driver because Linux system - returns the "device or resource busy" message, try to re-load it by - increment the IO port address by one. The driver will write - commands to the IO base addresses to reset the data port pointer. - You can specify an I/O address with an address value one greater - than the configured address. Example, to scan for an adapter - located at IO base 0x300, specify an IO address of 0x301. +c) The driver's hardware probe routine is designed to avoid + writing to I/O space until it knows that there is a cs89x0 + card at the written addresses. This could cause problems + with device probing. To avoid this behaviour, add one + to the `io=' module parameter. This doesn't actually change + the I/O address, but it is a flag to tell the driver + topartially initialise the hardware before trying to + identify the card. This could be dangerous if you are + not sure that there is a cs89x0 card at the provided address. + + For example, to scan for an adapter located at IO base 0x300, + specify an IO address of 0x301. d) The "duplex=auto" parameter is only supported for the CS8920. diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt --- v2.4.2/linux/Documentation/networking/ip-sysctl.txt Thu Nov 9 15:57:53 2000 +++ linux/Documentation/networking/ip-sysctl.txt Sun Mar 25 18:14:21 2001 @@ -272,6 +272,12 @@ if it is <= 0. Default: 2 +tcp_rfc1337 - BOOLEAN + If set, the TCP stack behaves conforming to RFC1337. If unset, + we are not conforming to RFC, but prevent TCP TIME_WAIT + asassination. + Default: 0 + ip_local_port_range - 2 INTEGERS Defines the local port range that is used by TCP and UDP to choose the local port. The first number is the first, the @@ -285,6 +291,18 @@ (i.e. by default) range 1024-4999 is enough to issue up to 2000 connections per second to systems supporting timestamps. +ip_nonlocal_bind - BOOLEAN + If set, allows processes to bind() to non-local IP adresses, + which can be quite useful - but may break some applications. + Default: 0 + +ip_dynaddr - BOOLEAN + If set non-zero, enables support for dynamic addresses. + If set to a non-zero value larger than 1, a kernel log + message will be printed when dynamic address rewriting + occurs. + Default: 0 + icmp_echo_ignore_all - BOOLEAN icmp_echo_ignore_broadcasts - BOOLEAN If either is set to true, then the kernel will ignore either all @@ -310,6 +328,10 @@ Alpha 1/1024s. See the HZ define in /usr/include/asm/param.h for the exact value on your system. +igmp_max_memberships - INTEGER + Change the maximum number of multicast groups we can subscribe to. + Default: 20 + conf/interface/*: conf/all/* is special and changes the settings for all interfaces. Change special settings per interface. @@ -376,4 +398,4 @@ Updated by: Andi Kleen ak@muc.de -$Id: ip-sysctl.txt,v 1.17 2000/11/06 07:15:36 davem Exp $ +$Id: ip-sysctl.txt,v 1.18 2001/03/16 06:49:20 davem Exp $ 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/parport.txt linux/Documentation/parport.txt --- v2.4.2/linux/Documentation/parport.txt Fri Dec 29 14:07:19 2000 +++ linux/Documentation/parport.txt Mon Mar 26 15:41:19 2001 @@ -19,12 +19,12 @@ If you load the parport code as a module, say - # insmod parport.o + # insmod parport to load the generic parport code. You then must load the architecture-dependent code with (for example): - # insmod parport_pc.o io=0x3bc,0x378,0x278 irq=none,7,auto + # insmod parport_pc io=0x3bc,0x378,0x278 irq=none,7,auto to tell the parport code that you want three PC-style ports, one at 0x3bc with no IRQ, one at 0x378 using IRQ 7, and one at 0x278 with an @@ -192,7 +192,7 @@ override this, though, by using parameters either when you load the lp driver: - # insmod lp.o parport=0,2 + # insmod lp parport=0,2 or on the LILO command line: 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/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt --- v2.4.2/linux/Documentation/sysctl/vm.txt Mon Aug 7 23:01:34 2000 +++ linux/Documentation/sysctl/vm.txt Wed Mar 14 14:39:07 2001 @@ -32,7 +32,7 @@ This file controls the operation of the bdflush kernel daemon. The source code to this struct can be found in -linux/mm/buffer.c. It currently contains 9 integer values, +linux/fs/buffer.c. It currently contains 9 integer values, of which 6 are actually used by the kernel. From linux/fs/buffer.c: diff -u --recursive --new-file v2.4.2/linux/Documentation/sysrq.txt linux/Documentation/sysrq.txt --- v2.4.2/linux/Documentation/sysrq.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/sysrq.txt Thu Mar 22 09:20:45 2001 @@ -29,6 +29,8 @@ You send a BREAK, then within 5 seconds a command key. Sending BREAK twice is interpreted as a normal BREAK. +On Mac - Press 'Keypad+-F13-' + On other - If you know of the key combos for other architectures, please let me know so I can add them to this section. diff -u --recursive --new-file v2.4.2/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt --- v2.4.2/linux/Documentation/usb/usb-serial.txt Wed Feb 21 18:20:09 2001 +++ linux/Documentation/usb/usb-serial.txt Mon Mar 19 17:21:54 2001 @@ -223,6 +223,28 @@ this driver. Also, D-Link's DU-H3SP USB BAY also works with this driver. +Inside Out Networks Edgeport Driver + + This driver supports all devices made by Inside Out Networks, specifically + the following models: + Edgeport/4 + Rapidport/4 + Edgeport/4t + Edgeport/2 + Edgeport/4i + Edgeport/2i + Edgeport/421 + Edgeport/21 + Edgeport/8 + Edgeport/8 Dual + Edgeport/2D8 + Edgeport/4D8 + Edgeport/8i + Edgeport/2 DIN + Edgeport/4 DIN + Edgeport/16 Dual + + Generic Serial driver If your device is not one of the above listed devices, compatible with diff -u --recursive --new-file v2.4.2/linux/Documentation/vm/locking linux/Documentation/vm/locking --- v2.4.2/linux/Documentation/vm/locking Fri Oct 13 12:10:30 2000 +++ linux/Documentation/vm/locking Mon Mar 19 12:35:11 2001 @@ -4,7 +4,7 @@ from different people about how locking and synchronization is done in the Linux vm code. -page_table_lock +page_table_lock & mmap_sem -------------------------------------- Page stealers pick processes out of the process pool and scan for @@ -23,29 +23,23 @@ Any code that modifies the vmlist, or the vm_start/vm_end/ vm_flags:VM_LOCKED/vm_next of any vma *in the list* must prevent -kswapd from looking at the chain. This does not include driver mmap() -methods, for example, since the vma is still not in the list. +kswapd from looking at the chain. The rules are: -1. To modify the vmlist (add/delete or change fields in an element), -you must hold mmap_sem to guard against clones doing mmap/munmap/faults, -(ie all vm system calls and faults), and from ptrace, swapin due to -swap deletion etc. -2. To modify the vmlist (add/delete or change fields in an element), -you must also hold page_table_lock, to guard against page stealers -scanning the list. -3. To scan the vmlist (find_vma()), you must either - a. grab mmap_sem, which should be done by all cases except - page stealer. -or - b. grab page_table_lock, only done by page stealer. -4. While holding the page_table_lock, you must be able to guarantee -that no code path will lead to page stealing. A better guarantee is -to claim non sleepability, which ensures that you are not sleeping -for a lock, whose holder might in turn be doing page stealing. +1. To scan the vmlist (look but don't touch) you must hold the + mmap_sem with read bias, i.e. down_read(&mm->mmap_sem) +2. To modify the vmlist you need to hold the mmap_sem with + read&write bias, i.e. down_write(&mm->mmap_sem) *AND* + you need to take the page_table_lock. +3. The swapper takes _just_ the page_table_lock, this is done + because the mmap_sem can be an extremely long lived lock + and the swapper just cannot sleep on that. +4. The exception to this rule is expand_stack, which just + takes the read lock and the page_table_lock, this is ok + because it doesn't really modify fields anybody relies on. 5. You must be able to guarantee that while holding page_table_lock -or page_table_lock of mm A, you will not try to get either lock -for mm B. + or page_table_lock of mm A, you will not try to get either lock + for mm B. The caveats are: 1. find_vma() makes use of, and updates, the mmap_cache pointer hint. 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 Sun Mar 25 18:14:20 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 @@ -1142,7 +1142,7 @@ P: Jakub Jelinek M: jj@sunsite.ms.mff.cuni.cz P: Anton Blanchard -M: anton@linuxcare.com +M: anton@samba.org L: sparclinux@vger.kernel.org L: ultralinux@vger.kernel.org W: http://ultra.linux.cz @@ -1452,6 +1452,11 @@ P: Henner Eisen M: eis@baty.hanse.de L: linux-x25@vger.kernel.org +S: Maintained + +X86 3-LEVEL PAGING (PAE) SUPPORT +P: Ingo Molnar +M: mingo@redhat.com S: Maintained Z85230 SYNCHRONOUS DRIVER 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 Thu Mar 29 20:13:15 2001 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 2 +SUBLEVEL = 3 EXTRAVERSION = 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/README linux/README --- v2.4.2/linux/README Tue Jan 2 16:55:26 2001 +++ linux/README Sun Mar 25 18:24:31 2001 @@ -40,6 +40,12 @@ contains information about the problems, which may result by upgrading your kernel. + - The Documentation/DocBook/ subdirectory contains several guides for + kernel developers and users. These guides can be rendered in a + number of formats: PostScript (.ps), PDF, and HTML, among others. + After installation, "make psdocs", "make pdfdocs", or "make htmldocs" + will render the documentation in the requested format. + INSTALLING the kernel: - If you install the full sources, put the kernel tarball in a 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/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.4.2/linux/arch/alpha/kernel/osf_sys.c Wed Feb 21 18:20:10 2001 +++ linux/arch/alpha/kernel/osf_sys.c Mon Mar 19 12:35:09 2001 @@ -242,9 +242,9 @@ goto out; } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, off); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); out: 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 Sun Mar 25 18:24:31 2001 @@ -6,7 +6,7 @@ */ struct pci_dev; -struct pci_controler; +struct pci_controller; struct pci_iommu_arena; /* @@ -68,6 +68,7 @@ /* ??? Experimenting with no HAE for CIA. */ #define CIA_DEFAULT_MEM_BASE ((32+2)*1024*1024) +#define IRONGATE_DEFAULT_MEM_BASE ((256*8-16)*1024*1024) /* * A small note about bridges and interrupts. The DECchip 21050 (and @@ -133,7 +134,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 +144,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_nautilus.c linux/arch/alpha/kernel/sys_nautilus.c --- v2.4.2/linux/arch/alpha/kernel/sys_nautilus.c Tue Jul 11 14:26:47 2000 +++ linux/arch/alpha/kernel/sys_nautilus.c Sun Mar 25 18:24:31 2001 @@ -518,7 +518,7 @@ machine_check: nautilus_machine_check, max_dma_address: ALPHA_NAUTILUS_MAX_DMA_ADDRESS, min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, + min_mem_address: IRONGATE_DEFAULT_MEM_BASE, nr_irqs: 16, device_interrupt: isa_device_interrupt, 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/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.4.2/linux/arch/alpha/mm/fault.c Fri Dec 29 14:07:19 2000 +++ linux/arch/alpha/mm/fault.c Mon Mar 19 12:35:09 2001 @@ -113,7 +113,7 @@ goto vmalloc_fault; #endif - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; @@ -146,7 +146,7 @@ * the fault. */ fault = handle_mm_fault(mm, vma, address, cause > 0); - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); if (fault < 0) goto out_of_memory; @@ -160,7 +160,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); if (user_mode(regs)) { force_sig(SIGSEGV, current); 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/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c --- v2.4.2/linux/arch/arm/kernel/sys_arm.c Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/kernel/sys_arm.c Mon Mar 19 12:35:10 2001 @@ -65,9 +65,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); 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/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.4.2/linux/arch/arm/mm/fault-common.c Wed Feb 21 18:20:10 2001 +++ linux/arch/arm/mm/fault-common.c Mon Mar 19 12:35:10 2001 @@ -223,9 +223,9 @@ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); fault = __do_page_fault(mm, addr, mode, tsk); - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); ret: /* 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/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c --- v2.4.2/linux/arch/cris/kernel/sys_cris.c Wed Feb 21 18:20:11 2001 +++ linux/arch/cris/kernel/sys_cris.c Mon Mar 19 12:35:11 2001 @@ -62,9 +62,9 @@ } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); out: @@ -87,9 +87,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); 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 Mon Mar 19 12:35:11 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: @@ -212,7 +212,7 @@ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; @@ -270,7 +270,7 @@ goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* @@ -280,7 +280,7 @@ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); bad_area_nosemaphore: DPG(show_registers(regs)); @@ -334,14 +334,14 @@ */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if(user_mode(regs)) do_exit(SIGKILL); goto no_context; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel @@ -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 Fri Mar 23 16:05:44 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 @@ -434,6 +434,7 @@ # CONFIG_PCMCIA_XIRTULIP is not set CONFIG_NET_PCMCIA_RADIO=y CONFIG_PCMCIA_RAYCS=y +# CONFIG_PCMCIA_HERMES is not set # CONFIG_PCMCIA_NETWAVE is not set # CONFIG_PCMCIA_WAVELAN is not set # CONFIG_AIRONET4500_CS is not set @@ -529,13 +530,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/head.S linux/arch/i386/kernel/head.S --- v2.4.2/linux/arch/i386/kernel/head.S Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/kernel/head.S Sun Mar 25 17:38:31 2001 @@ -415,23 +415,6 @@ ENTRY(empty_zero_page) .org 0x5000 -ENTRY(empty_bad_page) - -.org 0x6000 -ENTRY(empty_bad_pte_table) - -#if CONFIG_X86_PAE - - .org 0x7000 - ENTRY(empty_bad_pmd_table) - - .org 0x8000 - -#else - - .org 0x7000 - -#endif /* * This starts the data section. Note that the above is all 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/ldt.c linux/arch/i386/kernel/ldt.c --- v2.4.2/linux/arch/i386/kernel/ldt.c Fri Dec 29 14:07:20 2000 +++ linux/arch/i386/kernel/ldt.c Mon Mar 19 12:35:09 2001 @@ -86,7 +86,7 @@ * the GDT index of the LDT is allocated dynamically, and is * limited by MAX_LDT_DESCRIPTORS. */ - down(&mm->mmap_sem); + down_write(&mm->mmap_sem); if (!mm->context.segments) { error = -ENOMEM; mm->context.segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); @@ -141,7 +141,7 @@ error = 0; out_unlock: - up(&mm->mmap_sem); + up_write(&mm->mmap_sem); out: return error; } 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 Thu Mar 29 11:24:17 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,106 @@ 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 & (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)) == 0) { + 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)); + } +} + +static void __init pci_fixup_via691(struct pci_dev *d) +{ + /* + * The VIA bridge corrupts with Posting enabled */ u8 tmp; + 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<<7)) { + printk("PCI: Disabled enhanced CPU to PCI posting\n"); + pci_write_config_byte(d, 0x70, tmp & ~(1<<7)); } } +static void __init pci_fixup_via691_2(struct pci_dev *d) +{ + /* + * The VIA bridge corrupts with Posting enabled + */ + u8 tmp; + + pci_read_config_byte(d, 0x40, &tmp); + if(tmp & (1<<7)) { + printk("PCI: Disabled enhanced CPU to PCI posting #2\n"); + pci_write_config_byte(d, 0x40, 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_VIA, PCI_DEVICE_ID_VIA_82C691, pci_fixup_via691 }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, pci_fixup_via691_2 }, + { 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/setup.c linux/arch/i386/kernel/setup.c --- v2.4.2/linux/arch/i386/kernel/setup.c Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/kernel/setup.c Sun Mar 25 18:24:31 2001 @@ -294,7 +294,7 @@ visws_board_rev = raw; } - printk("Silicon Graphics %s (rev %d)\n", + printk(KERN_INFO "Silicon Graphics %s (rev %d)\n", visws_board_type == VISWS_320 ? "320" : (visws_board_type == VISWS_540 ? "540" : "unknown"), @@ -401,7 +401,7 @@ int x = e820.nr_map; if (x == E820MAX) { - printk("Ooops! Too many entries in the memory map!\n"); + printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); return; } @@ -418,8 +418,9 @@ int i; for (i = 0; i < e820.nr_map; i++) { - printk(" %s: %016Lx @ %016Lx ", who, - e820.map[i].size, e820.map[i].addr); + printk(" %s: %016Lx - %016Lx ", who, + e820.map[i].addr, + e820.map[i].addr + e820.map[i].size); switch (e820.map[i].type) { case E820_RAM: printk("(usable)\n"); break; @@ -521,7 +522,7 @@ add_memory_region(0, LOWMEMSIZE(), E820_RAM); add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); } - printk("BIOS-provided physical RAM map:\n"); + printk(KERN_INFO "BIOS-provided physical RAM map:\n"); print_memory_map(who); } /* setup_memory_region */ @@ -591,7 +592,7 @@ *to = '\0'; *cmdline_p = command_line; if (usermem) { - printk("user-defined physical RAM map:\n"); + printk(KERN_INFO "user-defined physical RAM map:\n"); print_memory_map("user"); } } @@ -798,7 +799,7 @@ initrd_end = initrd_start+INITRD_SIZE; } else { - printk("initrd extends beyond end of memory " + printk(KERN_ERR "initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)\ndisabling initrd\n", INITRD_START + INITRD_SIZE, max_low_pfn << PAGE_SHIFT); @@ -902,7 +903,7 @@ if (n >= 0x80000005) { cpuid(0x80000005, &dummy, &dummy, &ecx, &edx); - printk("CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n", + printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n", edx>>24, edx&0xFF, ecx>>24, ecx&0xFF); c->x86_cache_size=(ecx>>24)+(edx>>24); } @@ -926,7 +927,7 @@ c->x86_cache_size = l2size; - printk("CPU: L2 Cache: %dK (%d bytes/line)\n", + printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n", l2size, ecx & 0xFF); } @@ -1339,7 +1340,7 @@ name="C6"; fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK; fcr_clr=DPDC; - printk("Disabling bugged TSC.\n"); + printk(KERN_NOTICE "Disabling bugged TSC.\n"); clear_bit(X86_FEATURE_TSC, &c->x86_capability); break; case 8: @@ -1376,10 +1377,10 @@ newlo=(lo|fcr_set) & (~fcr_clr); if (newlo!=lo) { - printk("Centaur FCR was 0x%X now 0x%X\n", lo, newlo ); + printk(KERN_INFO "Centaur FCR was 0x%X now 0x%X\n", lo, newlo ); wrmsr(0x107, newlo, hi ); } else { - printk("Centaur FCR is 0x%X\n",lo); + printk(KERN_INFO "Centaur FCR is 0x%X\n",lo); } /* Emulate MTRRs using Centaur's MCR. */ set_bit(X86_FEATURE_CENTAUR_MCR, &c->x86_capability); @@ -1432,7 +1433,7 @@ max = cpuid_eax(0x80860000); if ( max >= 0x80860001 ) { cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); - printk("CPU: Processor revision %u.%u.%u.%u, %u MHz\n", + printk(KERN_INFO "CPU: Processor revision %u.%u.%u.%u, %u MHz\n", (cpu_rev >> 24) & 0xff, (cpu_rev >> 16) & 0xff, (cpu_rev >> 8) & 0xff, @@ -1441,7 +1442,7 @@ } if ( max >= 0x80860002 ) { cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy); - printk("CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n", + printk(KERN_INFO "CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n", (cms_rev1 >> 24) & 0xff, (cms_rev1 >> 16) & 0xff, (cms_rev1 >> 8) & 0xff, @@ -1470,7 +1471,7 @@ (void *)&cpu_info[56], (void *)&cpu_info[60]); cpu_info[64] = '\0'; - printk("CPU: %s\n", cpu_info); + printk(KERN_INFO "CPU: %s\n", cpu_info); } /* Unhide possibly hidden capability flags */ @@ -1502,7 +1503,7 @@ c->f00f_bug = 1; if ( !f00f_workaround_enabled ) { trap_init_f00f_bug(); - printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n"); + printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); f00f_workaround_enabled = 1; } } @@ -1610,12 +1611,12 @@ } } if ( l1i || l1d ) - printk("CPU: L1 I cache: %dK, L1 D cache: %dK\n", + printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n", l1i, l1d); if ( l2 ) - printk("CPU: L2 cache: %dK\n", l2); + printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); if ( l3 ) - printk("CPU: L3 cache: %dK\n", l3); + printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); /* * This assumes the L3 cache is shared; it typically lives in @@ -1785,7 +1786,7 @@ rdmsr(0x119,lo,hi); lo |= 0x200000; wrmsr(0x119,lo,hi); - printk(KERN_INFO "CPU serial number disabled.\n"); + printk(KERN_NOTICE "CPU serial number disabled.\n"); clear_bit(X86_FEATURE_PN, &c->x86_capability); } } @@ -1976,7 +1977,7 @@ } } - printk("CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n", + printk(KERN_DEBUG "CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], @@ -2023,7 +2024,7 @@ break; } - printk("CPU: After vendor init, caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], @@ -2063,7 +2064,7 @@ /* Now the feature flags better reflect actual CPU features! */ - printk("CPU: After generic, caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: After generic, caps: %08x %08x %08x %08x\n", c->x86_capability[0], c->x86_capability[1], c->x86_capability[2], @@ -2081,7 +2082,7 @@ boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; } - printk("CPU: Common caps: %08x %08x %08x %08x\n", + printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n", boot_cpu_data.x86_capability[0], boot_cpu_data.x86_capability[1], boot_cpu_data.x86_capability[2], @@ -2249,16 +2250,16 @@ struct tss_struct * t = &init_tss[nr]; if (test_and_set_bit(nr, &cpu_initialized)) { - printk("CPU#%d already initialized!\n", nr); + printk(KERN_WARNING "CPU#%d already initialized!\n", nr); for (;;) __sti(); } - printk("Initializing CPU#%d\n", nr); + printk(KERN_INFO "Initializing CPU#%d\n", nr); if (cpu_has_vme || cpu_has_tsc || cpu_has_de) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); #ifndef CONFIG_X86_TSC if (tsc_disable && cpu_has_tsc) { - printk("Disabling TSC...\n"); + printk(KERN_NOTICE "Disabling TSC...\n"); /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); set_in_cr4(X86_CR4_TSD); diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c --- v2.4.2/linux/arch/i386/kernel/sys_i386.c Wed Jul 5 11:31:00 2000 +++ linux/arch/i386/kernel/sys_i386.c Mon Mar 19 12:35:09 2001 @@ -55,9 +55,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); 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 Mon Mar 19 18:23:40 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/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.4.2/linux/arch/i386/mm/fault.c Wed Feb 21 18:20:11 2001 +++ linux/arch/i386/mm/fault.c Mon Mar 19 12:35:09 2001 @@ -141,7 +141,7 @@ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -214,7 +214,7 @@ if (bit < 32) tsk->thread.screen_bitmap |= 1 << bit; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* @@ -222,7 +222,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ @@ -290,14 +290,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if (error_code & 4) do_exit(SIGKILL); goto no_context; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel diff -u --recursive --new-file v2.4.2/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.4.2/linux/arch/i386/mm/init.c Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/mm/init.c Mon Mar 26 11:01:56 2001 @@ -40,132 +40,23 @@ static unsigned long totalram_pages; static unsigned long totalhigh_pages; -/* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a - * do_exit(), but using this instead means there is less risk - * for a process dying in kernel mode, possibly leaving an inode - * unused etc.. - * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. - * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. - */ - -/* - * These are allocated in head.S so that we get proper page alignment. - * If you change the size of these then change head.S as well. - */ -extern char empty_bad_page[PAGE_SIZE]; -#if CONFIG_X86_PAE -extern pmd_t empty_bad_pmd_table[PTRS_PER_PMD]; -#endif -extern pte_t empty_bad_pte_table[PTRS_PER_PTE]; - -/* - * We init them before every return and make them writable-shared. - * This guarantees we get out of the kernel in some more or less sane - * way. - */ -#if CONFIG_X86_PAE -static pmd_t * get_bad_pmd_table(void) -{ - pmd_t v; - int i; - - set_pmd(&v, __pmd(_PAGE_TABLE + __pa(empty_bad_pte_table))); - - for (i = 0; i < PAGE_SIZE/sizeof(pmd_t); i++) - empty_bad_pmd_table[i] = v; - - return empty_bad_pmd_table; -} -#endif - -static pte_t * get_bad_pte_table(void) -{ - pte_t v; - int i; - - v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED)); - - for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) - empty_bad_pte_table[i] = v; - - return empty_bad_pte_table; -} - - - -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page(pte); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte))); - return pte + offset; - } - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table()))); - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - unsigned long pte; - - pte = (unsigned long) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - clear_page((void *)pte); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); - return (pte_t *)pte + offset; - } - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table()))); - return NULL; - } - free_page(pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; if(pgtable_cache_size > high) { do { - if(pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; - if(pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed++; - if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; + if (pgd_quicklist) { + free_pgd_slow(get_pgd_fast()); + freed++; + } + if (pmd_quicklist) { + pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); + freed++; + } + if (pte_quicklist) { + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; + } } while(pgtable_cache_size > low); } return freed; @@ -327,10 +218,8 @@ pgd_base = swapper_pg_dir; #if CONFIG_X86_PAE - for (i = 0; i < PTRS_PER_PGD; i++) { - pgd = pgd_base + i; - __pgd_clear(pgd); - } + for (i = 0; i < PTRS_PER_PGD; i++) + set_pgd(pgd_base + i, __pgd(1 + __pa(empty_zero_page))); #endif i = __pgd_offset(PAGE_OFFSET); pgd = pgd_base + i; diff -u --recursive --new-file v2.4.2/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c --- v2.4.2/linux/arch/i386/mm/ioremap.c Thu Oct 12 12:44:04 2000 +++ linux/arch/i386/mm/ioremap.c Tue Mar 20 08:13:33 2001 @@ -49,7 +49,7 @@ if (address >= end) BUG(); do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); @@ -62,6 +62,7 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) { + int error; pgd_t * dir; unsigned long end = address + size; @@ -70,19 +71,23 @@ flush_cache_all(); if (address >= end) BUG(); + spin_lock(&init_mm.page_table_lock); do { pmd_t *pmd; - pmd = pmd_alloc_kernel(dir, address); + pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; if (!pmd) - return -ENOMEM; + break; if (remap_area_pmd(pmd, address, end - address, phys_addr + address, flags)) - return -ENOMEM; + break; + error = 0; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); - return 0; + return error; } /* diff -u --recursive --new-file v2.4.2/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c --- v2.4.2/linux/arch/ia64/ia32/binfmt_elf32.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/ia32/binfmt_elf32.c Thu Mar 22 09:24:58 2001 @@ -204,7 +204,6 @@ for (i = 0 ; i < MAX_ARG_PAGES ; i++) { if (bprm->page[i]) { - current->mm->rss++; put_dirty_page(current,bprm->page[i],stack_base); } stack_base += PAGE_SIZE; @@ -260,11 +259,11 @@ # define IA32_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) # define IA32_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1)) - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); retval = ia32_do_mmap(filep, IA32_PAGESTART(addr), eppnt->p_filesz + IA32_PAGEOFFSET(eppnt->p_vaddr), prot, type, eppnt->p_offset - IA32_PAGEOFFSET(eppnt->p_vaddr)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); #endif return retval; } diff -u --recursive --new-file v2.4.2/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.4.2/linux/arch/ia64/ia32/sys_ia32.c Wed Feb 21 18:20:11 2001 +++ linux/arch/ia64/ia32/sys_ia32.c Mon Mar 19 12:35:10 2001 @@ -120,12 +120,12 @@ * `execve' frees all current memory we only have to do an * `munmap' if the `execve' failes. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); av = (char **) do_mmap_pgoff(0, 0UL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (IS_ERR(av)) return (long)av; @@ -247,9 +247,9 @@ back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); __copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (r < 0) return(r); if (addr == 0) @@ -293,9 +293,9 @@ poff = offset & PAGE_MASK; len += offset - poff; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (!IS_ERR((void *) error)) error += offset - poff; @@ -2573,7 +2573,7 @@ return(-EFAULT); } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); lock_kernel(); addr = do_mmap_pgoff(file, IA32_IOBASE, @@ -2581,7 +2581,7 @@ (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT); unlock_kernel(); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (addr >= 0) { __asm__ __volatile__("mov ar.k0=%0 ;;" :: "r"(addr)); diff -u --recursive --new-file v2.4.2/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c --- v2.4.2/linux/arch/ia64/kernel/sys_ia64.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/sys_ia64.c Mon Mar 19 12:35:10 2001 @@ -102,7 +102,7 @@ * check and the clearing of r8. However, we can't call sys_brk() because we need * to acquire the mmap_sem before we can do the test... */ - down(&mm->mmap_sem); + down_write(&mm->mmap_sem); if (brk < mm->end_code) goto out; @@ -142,7 +142,7 @@ mm->brk = brk; out: retval = mm->brk; - up(&mm->mmap_sem); + up_write(&mm->mmap_sem); regs->r8 = 0; /* ensure large retval isn't mistaken as error code */ return retval; } @@ -200,9 +200,9 @@ if (flags & MAP_SHARED) current->thread.flags |= IA64_THREAD_MAP_SHARED; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); current->thread.flags &= ~IA64_THREAD_MAP_SHARED; 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/mm/fault.c linux/arch/ia64/mm/fault.c --- v2.4.2/linux/arch/ia64/mm/fault.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/mm/fault.c Mon Mar 19 12:35:10 2001 @@ -60,7 +60,7 @@ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma_prev(mm, address, &prev_vma); if (!vma) @@ -112,7 +112,7 @@ default: goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; check_expansion: @@ -135,7 +135,7 @@ goto good_area; bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); if (isr & IA64_ISR_SP) { /* * This fault was due to a speculative load set the "ed" bit in the psr to @@ -185,7 +185,7 @@ return; out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); 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/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c --- v2.4.2/linux/arch/m68k/kernel/sys_m68k.c Mon Nov 27 17:11:26 2000 +++ linux/arch/m68k/kernel/sys_m68k.c Mon Mar 19 12:35:09 2001 @@ -59,9 +59,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); @@ -146,9 +146,9 @@ } a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); out: diff -u --recursive --new-file v2.4.2/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c --- v2.4.2/linux/arch/m68k/mm/fault.c Thu Jan 4 13:00:55 2001 +++ linux/arch/m68k/mm/fault.c Mon Mar 19 12:35:10 2001 @@ -101,7 +101,7 @@ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -168,7 +168,7 @@ #warning should be obsolete now... if (CPU_IS_040_OR_060) flush_tlb_page(vma, address); - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return 0; /* @@ -203,6 +203,6 @@ current->thread.faddr = address; send_sig: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return send_fault_sig(regs); } 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/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.4.2/linux/arch/mips/kernel/irixelf.c Wed Feb 21 18:20:13 2001 +++ linux/arch/mips/kernel/irixelf.c Mon Mar 19 12:35:09 2001 @@ -314,12 +314,12 @@ (unsigned long) elf_prot, (unsigned long) elf_type, (unsigned long) (eppnt->p_offset & 0xfffff000)); #endif - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(interpreter, vaddr, eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), elf_prot, elf_type, eppnt->p_offset & 0xfffff000); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if(error < 0 && error > -1024) { printk("Aieee IRIX interp mmap error=%d\n", error); @@ -498,12 +498,12 @@ prot = (epp->p_flags & PF_R) ? PROT_READ : 0; prot |= (epp->p_flags & PF_W) ? PROT_WRITE : 0; prot |= (epp->p_flags & PF_X) ? PROT_EXEC : 0; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); (void) do_mmap(fp, (epp->p_vaddr & 0xfffff000), (epp->p_filesz + (epp->p_vaddr & 0xfff)), prot, EXEC_MAP_FLAGS, (epp->p_offset & 0xfffff000)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); /* Fixup location tracking vars. */ if((epp->p_vaddr & 0xfffff000) < *estack) @@ -762,10 +762,10 @@ * Since we do not have the power to recompile these, we * emulate the SVr4 behavior. Sigh. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); (void) do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); #endif start_thread(regs, elf_entry, bprm->p); @@ -837,14 +837,14 @@ while(elf_phdata->p_type != PT_LOAD) elf_phdata++; /* Now use mmap to map the library into memory. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(file, elf_phdata->p_vaddr & 0xfffff000, elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, elf_phdata->p_offset & 0xfffff000); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); k = elf_phdata->p_vaddr + elf_phdata->p_filesz; if (k > elf_bss) elf_bss = k; @@ -916,12 +916,12 @@ prot = (hp->p_flags & PF_R) ? PROT_READ : 0; prot |= (hp->p_flags & PF_W) ? PROT_WRITE : 0; prot |= (hp->p_flags & PF_X) ? PROT_EXEC : 0; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); retval = do_mmap(filp, (hp->p_vaddr & 0xfffff000), (hp->p_filesz + (hp->p_vaddr & 0xfff)), prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), (hp->p_offset & 0xfffff000)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if(retval != (hp->p_vaddr & 0xfffff000)) { printk("irix_mapelf: do_mmap fails with %d!\n", retval); 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/kernel/syscall.c linux/arch/mips/kernel/syscall.c --- v2.4.2/linux/arch/mips/kernel/syscall.c Tue Sep 5 13:50:02 2000 +++ linux/arch/mips/kernel/syscall.c Mon Mar 19 12:35:09 2001 @@ -69,9 +69,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); diff -u --recursive --new-file v2.4.2/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.4.2/linux/arch/mips/kernel/sysirix.c Wed Feb 21 18:20:13 2001 +++ linux/arch/mips/kernel/sysirix.c Mon Mar 19 12:35:09 2001 @@ -472,7 +472,7 @@ if (retval) return retval; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); pgdp = pgd_offset(mm, addr); pmdp = pmd_offset(pgdp, addr); ptep = pte_offset(pmdp, addr); @@ -485,7 +485,7 @@ PAGE_SHIFT, pageno); } } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); break; } @@ -535,7 +535,7 @@ struct mm_struct *mm = current->mm; int ret; - down(&mm->mmap_sem); + down_write(&mm->mmap_sem); if (brk < mm->end_code) { ret = -ENOMEM; goto out; @@ -593,7 +593,7 @@ ret = 0; out: - up(&mm->mmap_sem); + up_write(&mm->mmap_sem); return ret; } @@ -1083,9 +1083,9 @@ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); @@ -1643,9 +1643,9 @@ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); diff -u --recursive --new-file v2.4.2/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c --- v2.4.2/linux/arch/mips/mm/fault.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/mm/fault.c Mon Mar 19 12:35:09 2001 @@ -60,7 +60,7 @@ printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid, address, write, regs->cp0_epc); #endif - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; @@ -103,7 +103,7 @@ goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* @@ -111,7 +111,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); if (user_mode(regs)) { tsk->thread.cp0_badvaddr = address; @@ -163,14 +163,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if (user_mode(regs)) do_exit(SIGKILL); goto no_context; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel diff -u --recursive --new-file v2.4.2/linux/arch/mips/mm/umap.c linux/arch/mips/mm/umap.c --- v2.4.2/linux/arch/mips/mm/umap.c Mon Aug 7 21:02:27 2000 +++ linux/arch/mips/mm/umap.c Mon Mar 19 12:35:09 2001 @@ -94,7 +94,7 @@ unsigned long beg = start; pgd_t *dir; - down (&task->mm->mmap_sem); + down_write (&task->mm->mmap_sem); dir = pgd_offset (task->mm, start); flush_cache_range (task->mm, beg, end); while (start < end){ @@ -103,7 +103,7 @@ dir++; } flush_tlb_range (task->mm, beg, end); - up (&task->mm->mmap_sem); + up_write (&task->mm->mmap_sem); } void *vmalloc_uncached (unsigned long size) 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/linux32.c linux/arch/mips64/kernel/linux32.c --- v2.4.2/linux/arch/mips64/kernel/linux32.c Sat Feb 3 19:51:22 2001 +++ linux/arch/mips64/kernel/linux32.c Mon Mar 19 12:35:10 2001 @@ -443,10 +443,10 @@ * `execve' frees all current memory we only have to do an * `munmap' if the `execve' failes. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); av = (char **) do_mmap_pgoff(0, 0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (IS_ERR(av)) return (long) av; 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/kernel/syscall.c linux/arch/mips64/kernel/syscall.c --- v2.4.2/linux/arch/mips64/kernel/syscall.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/syscall.c Mon Mar 19 12:35:10 2001 @@ -64,9 +64,9 @@ } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(file, addr, len, prot, flags, offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); out: 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 Mon Mar 19 12:35:10 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) @@ -95,7 +95,7 @@ printk("Cpu%d[%s:%d:%08lx:%ld:%08lx]\n", smp_processor_id(), current->comm, current->pid, address, write, regs->cp0_epc); #endif - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; @@ -138,7 +138,7 @@ goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* @@ -146,7 +146,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Quickly check for vmalloc range faults. @@ -209,14 +209,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if (user_mode(regs)) do_exit(SIGKILL); goto no_context; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel diff -u --recursive --new-file v2.4.2/linux/arch/mips64/mm/umap.c linux/arch/mips64/mm/umap.c --- v2.4.2/linux/arch/mips64/mm/umap.c Mon Aug 7 21:02:27 2000 +++ linux/arch/mips64/mm/umap.c Mon Mar 19 12:35:10 2001 @@ -89,7 +89,7 @@ unsigned long beg = start; pgd_t *dir; - down (&task->mm->mmap_sem); + down_write (&task->mm->mmap_sem); dir = pgd_offset (task->mm, start); flush_cache_range (task->mm, beg, end); while (start < end){ @@ -98,7 +98,7 @@ dir++; } flush_tlb_range (task->mm, beg, end); - up (&task->mm->mmap_sem); + up_write (&task->mm->mmap_sem); } void *vmalloc_uncached (unsigned long size) 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/parisc/kernel/sys_parisc.c linux/arch/parisc/kernel/sys_parisc.c --- v2.4.2/linux/arch/parisc/kernel/sys_parisc.c Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/kernel/sys_parisc.c Mon Mar 19 12:35:11 2001 @@ -51,7 +51,7 @@ struct file * file = NULL; int error; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { error = -EBADF; @@ -65,7 +65,7 @@ fput(file); out: unlock_kernel(); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return error; } diff -u --recursive --new-file v2.4.2/linux/arch/parisc/mm/fault.c linux/arch/parisc/mm/fault.c --- v2.4.2/linux/arch/parisc/mm/fault.c Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/mm/fault.c Mon Mar 19 12:37:16 2001 @@ -175,7 +175,7 @@ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = pa_find_vma(mm, address); if (!vma) goto bad_area; @@ -218,14 +218,14 @@ default: goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* * Something tried to access memory that isn't in our memory map.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); if (user_mode(regs)) { struct siginfo si; @@ -275,7 +275,7 @@ parisc_terminate("Bad Address (null pointer deref?)",regs,code,address); out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); 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/syscalls.c linux/arch/ppc/kernel/syscalls.c --- v2.4.2/linux/arch/ppc/kernel/syscalls.c Sun Sep 17 09:48:07 2000 +++ linux/arch/ppc/kernel/syscalls.c Mon Mar 19 12:35:09 2001 @@ -198,9 +198,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); ret = do_mmap(file, addr, len, prot, flags, offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); out: 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 Mon Mar 19 12:35:09 2001 @@ -99,7 +99,7 @@ bad_page_fault(regs, address, SIGSEGV); return; } - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; @@ -159,7 +159,7 @@ goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * keep track of tlb+htab misses that are good addrs but * just need pte's created via handle_mm_fault() @@ -169,7 +169,7 @@ return; bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); pte_errors++; /* User mode accesses cause a SIGSEGV */ @@ -190,7 +190,7 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); @@ -198,7 +198,7 @@ return; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; @@ -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 Mon Mar 26 15:29:44 2001 @@ -110,7 +110,7 @@ #endif void MMU_init(void); -static void *MMU_get_page(void); +void *early_get_page(void); unsigned long prep_find_end_of_memory(void); unsigned long pmac_find_end_of_memory(void); unsigned long apus_find_end_of_memory(void); @@ -125,7 +125,7 @@ unsigned long m8260_find_end_of_memory(void); #endif /* CONFIG_8260 */ static void mapin_ram(void); -void map_page(unsigned long va, unsigned long pa, int flags); +int map_page(unsigned long va, unsigned long pa, int flags); void set_phys_avail(unsigned long total_ram); extern void die_if_kernel(char *,struct pt_regs *,long); @@ -206,41 +206,20 @@ pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE; } -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - if (pmd_none(*pmd)) { - if (!mem_init_done) - pte = (pte_t *) MMU_get_page(); - else if ((pte = (pte_t *) __get_free_page(GFP_KERNEL))) - clear_page(pte); - if (pte) { - pmd_val(*pmd) = (unsigned long)pte; - return pte + offset; - } - pmd_val(*pmd) = (unsigned long)BAD_PAGETABLE; - return NULL; - } - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - int do_check_pgt_cache(int low, int high) { int freed = 0; - if(pgtable_cache_size > high) { + if (pgtable_cache_size > high) { do { - if(pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; - if(pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed++; - if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; - } while(pgtable_cache_size > low); + if (pgd_quicklist) { + free_pgd_slow(get_pgd_fast()); + freed++; + } + if (pte_quicklist) { + pte_free_slow(pte_alloc_one_fast(NULL, 0)); + freed++; + } + } while (pgtable_cache_size > low); } return freed; } @@ -383,6 +362,7 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags) { unsigned long p, v, i; + int err; /* * Choose an address to map it to. @@ -453,10 +433,20 @@ flags |= _PAGE_GUARDED; /* - * Is it a candidate for a BAT mapping? + * Should check if it is a candidate for a BAT mapping */ - for (i = 0; i < size; i += PAGE_SIZE) - map_page(v+i, p+i, flags); + + spin_lock(&init_mm.page_table_lock); + err = 0; + for (i = 0; i < size && err == 0; i += PAGE_SIZE) + err = map_page(v+i, p+i, flags); + spin_unlock(&init_mm.page_table_lock); + if (err) { + if (mem_init_done) + vfree((void *)v); + return NULL; + } + out: return (void *) (v + (addr & ~PAGE_MASK)); } @@ -492,7 +482,7 @@ return (pte_val(*pg) & PAGE_MASK) | (addr & ~PAGE_MASK); } -void +int map_page(unsigned long va, unsigned long pa, int flags) { pmd_t *pd; @@ -501,10 +491,13 @@ /* Use upper 10 bits of VA to index the first level map */ pd = pmd_offset(pgd_offset_k(va), va); /* Use middle 10 bits of VA to index the second-level map */ - pg = pte_alloc(pd, va); + pg = pte_alloc(&init_mm, pd, va); + if (pg == 0) + return -ENOMEM; set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags))); if (mem_init_done) flush_hash_page(0, va); + return 0; } #ifndef CONFIG_8xx @@ -830,21 +823,16 @@ } } -/* In fact this is only called until mem_init is done. */ -static void __init *MMU_get_page(void) +/* This is only called until mem_init is done. */ +void __init *early_get_page(void) { void *p; - if (mem_init_done) { - p = (void *) __get_free_page(GFP_KERNEL); - } else if (init_bootmem_done) { + if (init_bootmem_done) { p = alloc_bootmem_pages(PAGE_SIZE); } else { p = mem_pieces_find(PAGE_SIZE, PAGE_SIZE); } - if (p == 0) - panic("couldn't get a page in MMU_get_page"); - __clear_user(p, PAGE_SIZE); return p; } @@ -889,13 +877,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/kernel/sys_s390.c linux/arch/s390/kernel/sys_s390.c --- v2.4.2/linux/arch/s390/kernel/sys_s390.c Wed Feb 21 18:20:14 2001 +++ linux/arch/s390/kernel/sys_s390.c Mon Mar 19 12:35:11 2001 @@ -61,9 +61,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); diff -u --recursive --new-file v2.4.2/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c --- v2.4.2/linux/arch/s390/mm/fault.c Wed Feb 21 18:20:14 2001 +++ linux/arch/s390/mm/fault.c Mon Mar 19 12:35:11 2001 @@ -122,7 +122,7 @@ * task's user address space, so we search the VMAs */ - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -173,7 +173,7 @@ goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* @@ -181,7 +181,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* User mode accesses just cause a SIGSEGV */ if (psw_mask & PSW_PROBLEM_STATE) { @@ -240,14 +240,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if (psw_mask & PSW_PROBLEM_STATE) do_exit(SIGKILL); goto no_context; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel 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/binfmt_elf32.c linux/arch/s390x/kernel/binfmt_elf32.c --- v2.4.2/linux/arch/s390x/kernel/binfmt_elf32.c Wed Feb 21 18:20:14 2001 +++ linux/arch/s390x/kernel/binfmt_elf32.c Mon Mar 19 12:35:11 2001 @@ -193,11 +193,11 @@ if(!addr) addr = 0x40000000; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); map_addr = do_mmap(filep, ELF_PAGESTART(addr), eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return(map_addr); } 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/kernel/exec32.c linux/arch/s390x/kernel/exec32.c --- v2.4.2/linux/arch/s390x/kernel/exec32.c Wed Feb 21 18:20:14 2001 +++ linux/arch/s390x/kernel/exec32.c Thu Mar 22 09:25:21 2001 @@ -54,7 +54,7 @@ if (!mpnt) return -ENOMEM; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; @@ -73,12 +73,11 @@ struct page *page = bprm->page[i]; if (page) { bprm->page[i] = NULL; - current->mm->rss++; put_dirty_page(current,page,stack_base); } stack_base += PAGE_SIZE; } - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return 0; } diff -u --recursive --new-file v2.4.2/linux/arch/s390x/kernel/linux32.c linux/arch/s390x/kernel/linux32.c --- v2.4.2/linux/arch/s390x/kernel/linux32.c Wed Feb 21 18:20:14 2001 +++ linux/arch/s390x/kernel/linux32.c Mon Mar 19 12:35:11 2001 @@ -4184,9 +4184,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); diff -u --recursive --new-file v2.4.2/linux/arch/s390x/kernel/sys_s390.c linux/arch/s390x/kernel/sys_s390.c --- v2.4.2/linux/arch/s390x/kernel/sys_s390.c Wed Feb 21 18:20:15 2001 +++ linux/arch/s390x/kernel/sys_s390.c Mon Mar 19 12:35:11 2001 @@ -61,9 +61,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); diff -u --recursive --new-file v2.4.2/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c --- v2.4.2/linux/arch/s390x/mm/fault.c Wed Feb 21 18:20:15 2001 +++ linux/arch/s390x/mm/fault.c Mon Mar 19 12:35:11 2001 @@ -122,7 +122,7 @@ * task's user address space, so we search the VMAs */ - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) { @@ -176,7 +176,7 @@ goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* @@ -184,7 +184,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* User mode accesses just cause a SIGSEGV */ if (psw_mask & PSW_PROBLEM_STATE) { @@ -243,14 +243,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if (psw_mask & PSW_PROBLEM_STATE) do_exit(SIGKILL); goto no_context; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel 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/sh/kernel/sys_sh.c linux/arch/sh/kernel/sys_sh.c --- v2.4.2/linux/arch/sh/kernel/sys_sh.c Wed Jul 5 11:31:01 2000 +++ linux/arch/sh/kernel/sys_sh.c Mon Mar 19 12:35:10 2001 @@ -57,9 +57,9 @@ goto out; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (file) fput(file); diff -u --recursive --new-file v2.4.2/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c --- v2.4.2/linux/arch/sh/mm/fault.c Thu Jan 4 13:19:13 2001 +++ linux/arch/sh/mm/fault.c Mon Mar 19 12:35:10 2001 @@ -109,7 +109,7 @@ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -151,7 +151,7 @@ goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* @@ -159,7 +159,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); if (user_mode(regs)) { tsk->thread.address = address; @@ -208,14 +208,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if (user_mode(regs)) do_exit(SIGKILL); goto no_context; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel diff -u --recursive --new-file v2.4.2/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.4.2/linux/arch/sparc/defconfig Sat Feb 3 19:51:24 2001 +++ linux/arch/sparc/defconfig Sun Mar 25 18:14:21 2001 @@ -105,8 +105,8 @@ # # CONFIG_SPARCAUDIO is not set # CONFIG_SPARCAUDIO_AMD7930 is not set -# CONFIG_SPARCAUDIO_CS4231 is not set # CONFIG_SPARCAUDIO_DBRI is not set +# CONFIG_SPARCAUDIO_CS4231 is not set # CONFIG_SPARCAUDIO_DUMMY is not set # @@ -126,7 +126,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=y CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y @@ -266,6 +265,8 @@ # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=m CONFIG_AUTOFS4_FS=m +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set CONFIG_AFFS_FS=m diff -u --recursive --new-file v2.4.2/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c --- v2.4.2/linux/arch/sparc/kernel/ptrace.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc/kernel/ptrace.c Sun Mar 25 18:14:21 2001 @@ -305,7 +305,13 @@ goto out; } #endif - if(!(child = find_task_by_pid(pid))) { + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + + if (!child) { pt_error_return(regs, ESRCH); goto out; } @@ -319,7 +325,7 @@ * You'll never be able to kill the process. ;-) */ pt_error_return(regs, EPERM); - goto out; + goto out_tsk; } if((!child->dumpable || (current->uid != child->euid) || @@ -330,12 +336,12 @@ (!cap_issubset(child->cap_permitted, current->cap_permitted)) || (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); - goto out; + goto out_tsk; } /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) { pt_error_return(regs, EPERM); - goto out; + goto out_tsk; } child->ptrace |= PT_PTRACED; write_lock_irqsave(&tasklist_lock, flags); @@ -347,21 +353,21 @@ write_unlock_irqrestore(&tasklist_lock, flags); send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } if (!(child->ptrace & PT_PTRACED)) { pt_error_return(regs, ESRCH); - goto out; + goto out_tsk; } if(child->state != TASK_STOPPED) { if(request != PTRACE_KILL) { pt_error_return(regs, ESRCH); - goto out; + goto out_tsk; } } if(child->p_pptr != current) { pt_error_return(regs, ESRCH); - goto out; + goto out_tsk; } switch(request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -373,16 +379,16 @@ pt_os_succ_return(regs, tmp, (long *)data); else pt_error_return(regs, EIO); - goto out; + goto out_tsk; } case PTRACE_PEEKUSR: read_sunos_user(regs, addr, child, (long *) data); - goto out; + goto out_tsk; case PTRACE_POKEUSR: write_sunos_user(regs, addr, child); - goto out; + goto out_tsk; case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: { @@ -391,7 +397,7 @@ pt_succ_return(regs, 0); else pt_error_return(regs, EIO); - goto out; + goto out_tsk; } case PTRACE_GETREGS: { @@ -402,7 +408,7 @@ rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs)); if(rval) { pt_error_return(regs, -rval); - goto out; + goto out_tsk; } __put_user(cregs->psr, (&pregs->psr)); __put_user(cregs->pc, (&pregs->pc)); @@ -414,7 +420,7 @@ #ifdef DEBUG_PTRACE printk ("PC=%x nPC=%x o7=%x\n", cregs->pc, cregs->npc, cregs->u_regs [15]); #endif - goto out; + goto out_tsk; } case PTRACE_SETREGS: { @@ -429,7 +435,7 @@ i = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs)); if(i) { pt_error_return(regs, -i); - goto out; + goto out_tsk; } __get_user(psr, (&pregs->psr)); __get_user(pc, (&pregs->pc)); @@ -446,7 +452,7 @@ for(i = 1; i < 16; i++) __get_user(cregs->u_regs[i], (&pregs->u_regs[i-1])); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_GETFPREGS: { @@ -466,7 +472,7 @@ i = verify_area(VERIFY_WRITE, fps, sizeof(struct fps)); if(i) { pt_error_return(regs, -i); - goto out; + goto out_tsk; } for(i = 0; i < 32; i++) __put_user(child->thread.float_regs[i], (&fps->regs[i])); @@ -480,7 +486,7 @@ __put_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); } pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_SETFPREGS: { @@ -500,7 +506,7 @@ i = verify_area(VERIFY_READ, fps, sizeof(struct fps)); if(i) { pt_error_return(regs, -i); - goto out; + goto out_tsk; } copy_from_user(&child->thread.float_regs[0], &fps->regs[0], (32 * sizeof(unsigned long))); __get_user(child->thread.fsr, (&fps->fsr)); @@ -511,7 +517,7 @@ __get_user(child->thread.fpqueue[i].insn, (&fps->fpq[i].insn)); } pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_READTEXT: @@ -520,13 +526,13 @@ if (res == data) { pt_succ_return(regs, 0); - goto out; + goto out_tsk; } /* Partial read is an IO failure */ if (res >= 0) res = -EIO; pt_error_return(regs, -res); - goto out; + goto out_tsk; } case PTRACE_WRITETEXT: @@ -535,13 +541,13 @@ if (res == data) { pt_succ_return(regs, 0); - goto out; + goto out_tsk; } /* Partial write is an IO failure */ if (res >= 0) res = -EIO; pt_error_return(regs, -res); - goto out; + goto out_tsk; } case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ @@ -550,12 +556,12 @@ case PTRACE_CONT: { /* restart after signal. */ if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); - goto out; + goto out_tsk; } if (addr != 1) { if (addr & 3) { pt_error_return(regs, EINVAL); - goto out; + goto out_tsk; } #ifdef DEBUG_PTRACE printk ("Original: %08lx %08lx\n", child->thread.kregs->pc, child->thread.kregs->npc); @@ -580,7 +586,7 @@ #endif wake_up_process(child); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } /* @@ -591,19 +597,19 @@ case PTRACE_KILL: { if (child->state == TASK_ZOMBIE) { /* already dead */ pt_succ_return(regs, 0); - goto out; + goto out_tsk; } wake_up_process(child); child->exit_code = SIGKILL; pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ unsigned long flags; if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); - goto out; + goto out_tsk; } child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); wake_up_process(child); @@ -614,15 +620,18 @@ SET_LINKS(child); write_unlock_irqrestore(&tasklist_lock, flags); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } /* PTRACE_DUMPCORE unsupported... */ default: pt_error_return(regs, EIO); - goto out; + goto out_tsk; } +out_tsk: + if (child) + free_task_struct(child); out: unlock_kernel(); } diff -u --recursive --new-file v2.4.2/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.4.2/linux/arch/sparc/kernel/sys_sparc.c Mon Dec 11 12:37:02 2000 +++ linux/arch/sparc/kernel/sys_sparc.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.67 2000/11/30 08:37:31 anton Exp $ +/* $Id: sys_sparc.c,v 1.68 2001/03/24 09:36:10 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -236,9 +236,9 @@ if (flags & MAP_SHARED) current->thread.flags |= SPARC_FLAG_MMAPSHARED; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); @@ -284,7 +284,7 @@ if (old_len > TASK_SIZE - PAGE_SIZE || new_len > TASK_SIZE - PAGE_SIZE) goto out; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); vma = find_vma(current->mm, addr); if (vma && (vma->vm_flags & VM_SHARED)) current->thread.flags |= SPARC_FLAG_MMAPSHARED; @@ -309,7 +309,7 @@ ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); out: return ret; } diff -u --recursive --new-file v2.4.2/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.4.2/linux/arch/sparc/kernel/sys_sunos.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc/kernel/sys_sunos.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.132 2001/02/13 01:16:43 davem Exp $ +/* $Id: sys_sunos.c,v 1.133 2001/03/24 09:36:10 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -116,9 +116,9 @@ } flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, off); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if(!ret_type) retval = ((retval < PAGE_OFFSET) ? 0 : retval); @@ -145,7 +145,7 @@ unsigned long rlim; unsigned long newbrk, oldbrk; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); if(ARCH_SUN4C_SUN4) { if(brk >= 0x20000000 && brk < 0xe0000000) { goto out; @@ -208,7 +208,7 @@ do_brk(oldbrk, newbrk-oldbrk); retval = 0; out: - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return retval; } diff -u --recursive --new-file v2.4.2/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.4.2/linux/arch/sparc/mm/fault.c Mon Jan 1 10:37:41 2001 +++ linux/arch/sparc/mm/fault.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.118 2000/12/29 07:52:41 anton Exp $ +/* $Id: fault.c,v 1.119 2001/03/24 09:36:10 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -224,7 +224,7 @@ if (in_interrupt() || !mm) goto no_context; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); /* * The kernel referencing a bad kernel pointer can lock up @@ -274,7 +274,7 @@ default: goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; /* @@ -282,7 +282,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ @@ -338,14 +338,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if (from_user) do_exit(SIGKILL); goto no_context; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; @@ -479,7 +479,7 @@ printk("wf\n", tsk->pid, write, address); #endif - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if(!vma) goto bad_area; @@ -500,10 +500,10 @@ } if (!handle_mm_fault(mm, vma, address, write)) goto do_sigbus; - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return; bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); #if 0 printk("Window whee %s [%d]: segfaults at %08lx\n", tsk->comm, tsk->pid, address); @@ -518,7 +518,7 @@ return; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; diff -u --recursive --new-file v2.4.2/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.4.2/linux/arch/sparc/mm/init.c Mon Dec 11 12:37:03 2000 +++ linux/arch/sparc/mm/init.c Sun Mar 25 18:14:21 2001 @@ -1,10 +1,10 @@ -/* $Id: init.c,v 1.96 2000/11/30 08:51:50 anton Exp $ +/* $Id: init.c,v 1.97 2001/02/26 02:57:34 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au) */ #include @@ -53,7 +53,7 @@ unsigned long highstart_pfn, highend_pfn; unsigned long totalram_pages; -static unsigned long totalhigh_pages; +unsigned long totalhigh_pages; /* * BAD_PAGE is the page that is used for page faults when linux @@ -134,42 +134,79 @@ #define DEBUG_BOOTMEM extern unsigned long cmdline_memory_size; -extern unsigned long last_valid_pfn; +unsigned long last_valid_pfn; + +unsigned long calc_highpages(void) +{ + int i; + int nr = 0; + + for (i = 0; sp_banks[i].num_bytes != 0; i++) { + unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT; + unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT; + + if (end_pfn <= max_low_pfn) + continue; -void __init bootmem_init(void) + if (start_pfn < max_low_pfn) + start_pfn = max_low_pfn; + + nr += end_pfn - start_pfn; + } + + return nr; +} + +unsigned long calc_max_low_pfn(void) +{ + int i; + unsigned long tmp = (SRMMU_MAXMEM >> PAGE_SHIFT); + unsigned long curr_pfn, last_pfn; + + last_pfn = (sp_banks[0].base_addr + sp_banks[0].num_bytes) >> PAGE_SHIFT; + for (i = 1; sp_banks[i].num_bytes != 0; i++) { + curr_pfn = sp_banks[i].base_addr >> PAGE_SHIFT; + + if (curr_pfn >= tmp) { + if (last_pfn < tmp) + tmp = last_pfn; + break; + } + + last_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT; + } + + return tmp; +} + +unsigned long __init bootmem_init(unsigned long *pages_avail) { unsigned long bootmap_size, start_pfn, max_pfn; unsigned long end_of_phys_memory = 0UL; - unsigned long bootmap_pfn; + unsigned long bootmap_pfn, bytes_avail, size; int i; - /* XXX It is a bit ambiguous here, whether we should - * XXX treat the user specified mem=xxx as total wanted - * XXX physical memory, or as a limit to the upper - * XXX physical address we allow. For now it is the - * XXX latter. -DaveM - */ #ifdef DEBUG_BOOTMEM prom_printf("bootmem_init: Scan sp_banks, "); #endif + bytes_avail = 0UL; for (i = 0; sp_banks[i].num_bytes != 0; i++) { end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes; + bytes_avail += sp_banks[i].num_bytes; if (cmdline_memory_size) { - if (end_of_phys_memory > cmdline_memory_size) { - if (cmdline_memory_size < sp_banks[i].base_addr) { - end_of_phys_memory = - sp_banks[i-1].base_addr + - sp_banks[i-1].num_bytes; + if (bytes_avail > cmdline_memory_size) { + unsigned long slack = bytes_avail - cmdline_memory_size; + + bytes_avail -= slack; + end_of_phys_memory -= slack; + + sp_banks[i].num_bytes -= slack; + if (sp_banks[i].num_bytes == 0) { sp_banks[i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; } else { - sp_banks[i].num_bytes -= - (end_of_phys_memory - - cmdline_memory_size); - end_of_phys_memory = cmdline_memory_size; - sp_banks[++i].base_addr = 0xdeadbeef; - sp_banks[i].num_bytes = 0; + sp_banks[i+1].num_bytes = 0; + sp_banks[i+1].base_addr = 0xdeadbeef; } break; } @@ -195,9 +232,9 @@ highstart_pfn = highend_pfn = max_pfn; if (max_low_pfn > (SRMMU_MAXMEM >> PAGE_SHIFT)) { - highstart_pfn = max_low_pfn = (SRMMU_MAXMEM >> PAGE_SHIFT); - printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", - (highend_pfn - highstart_pfn) >> (20-PAGE_SHIFT)); + highstart_pfn = (SRMMU_MAXMEM >> PAGE_SHIFT); + max_low_pfn = calc_max_low_pfn(); + printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", calc_highpages()); } #ifdef CONFIG_BLK_DEV_INITRD @@ -225,13 +262,14 @@ prom_printf("init_bootmem(spfn[%lx],bpfn[%lx],mlpfn[%lx])\n", start_pfn, bootmap_pfn, max_low_pfn); #endif - bootmap_size = init_bootmem(bootmap_pfn, max_low_pfn); + bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, phys_base>>PAGE_SHIFT, max_low_pfn); /* Now register the available physical memory with the * allocator. */ + *pages_avail = 0; for (i = 0; sp_banks[i].num_bytes != 0; i++) { - unsigned long curr_pfn, last_pfn, size; + unsigned long curr_pfn, last_pfn; curr_pfn = sp_banks[i].base_addr >> PAGE_SHIFT; if (curr_pfn >= max_low_pfn) @@ -249,7 +287,7 @@ continue; size = (last_pfn - curr_pfn) << PAGE_SHIFT; - + *pages_avail += last_pfn - curr_pfn; #ifdef DEBUG_BOOTMEM prom_printf("free_bootmem: base[%lx] size[%lx]\n", sp_banks[i].base_addr, @@ -259,29 +297,42 @@ size); } - /* Reserve the kernel text/data/bss, the bootmem bitmap and initrd. */ -#ifdef DEBUG_BOOTMEM #ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) + if (initrd_start) { + size = initrd_end - initrd_start; +#ifdef DEBUG_BOOTMEM prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - initrd_start, initrd_end - initrd_start); + initrd_start, size); #endif - prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - phys_base, (start_pfn << PAGE_SHIFT) - phys_base); - prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", - (bootmap_pfn << PAGE_SHIFT), bootmap_size); -#endif -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) { - reserve_bootmem(initrd_start, initrd_end - initrd_start); + /* Reserve the initrd image area. */ + reserve_bootmem(initrd_start, size); + *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; + initrd_start += PAGE_OFFSET; initrd_end += PAGE_OFFSET; } #endif - reserve_bootmem(phys_base, (start_pfn << PAGE_SHIFT) - phys_base); - reserve_bootmem((bootmap_pfn << PAGE_SHIFT), bootmap_size); + /* Reserve the kernel text/data/bss. */ + size = (start_pfn << PAGE_SHIFT) - phys_base; +#ifdef DEBUG_BOOTMEM + prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", phys_base, size); +#endif + reserve_bootmem(phys_base, size); + *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; + + /* Reserve the bootmem map. We do not account for it + * in pages_avail because we will release that memory + * in free_all_bootmem. + */ + size = bootmap_size; +#ifdef DEBUG_BOOTMEM + prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", + (bootmap_pfn << PAGE_SHIFT), size); +#endif + reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size); + *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT; - last_valid_pfn = max_pfn; + return max_pfn; } /* @@ -293,8 +344,6 @@ extern void srmmu_paging_init(void); extern void device_scan(void); -unsigned long last_valid_pfn; - void __init paging_init(void) { switch(sparc_cpu_model) { @@ -359,71 +408,6 @@ } } -void __init free_mem_map_range(struct page *first, struct page *last) -{ - first = (struct page *) PAGE_ALIGN((unsigned long)first); - last = (struct page *) ((unsigned long)last & PAGE_MASK); -#ifdef DEBUG_BOOTMEM - prom_printf("[%p,%p] ", first, last); -#endif - while (first < last) { - ClearPageReserved(virt_to_page(first)); - set_page_count(virt_to_page(first), 1); - free_page((unsigned long)first); - totalram_pages++; - num_physpages++; - - first = (struct page *)((unsigned long)first + PAGE_SIZE); - } -} - -/* Walk through holes in sp_banks regions, if the mem_map array - * areas representing those holes consume a page or more, free - * up such pages. This helps a lot on machines where physical - * ram is configured such that it begins at some hugh value. - * - * The sp_banks array is sorted by base address. - */ -void __init free_unused_mem_map(void) -{ - int i; - -#ifdef DEBUG_BOOTMEM - prom_printf("free_unused_mem_map: "); -#endif - for (i = 0; sp_banks[i].num_bytes; i++) { - if (i == 0) { - struct page *first, *last; - - first = mem_map; - last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT]; - free_mem_map_range(first, last); - } else { - struct page *first, *last; - unsigned long prev_end; - - prev_end = sp_banks[i-1].base_addr + - sp_banks[i-1].num_bytes; - prev_end = PAGE_ALIGN(prev_end); - first = &mem_map[prev_end >> PAGE_SHIFT]; - last = &mem_map[sp_banks[i].base_addr >> PAGE_SHIFT]; - - free_mem_map_range(first, last); - - if (!sp_banks[i+1].num_bytes) { - prev_end = sp_banks[i].base_addr + - sp_banks[i].num_bytes; - first = &mem_map[prev_end >> PAGE_SHIFT]; - last = &mem_map[last_valid_pfn]; - free_mem_map_range(first, last); - } - } - } -#ifdef DEBUG_BOOTMEM - prom_printf("\n"); -#endif -} - void map_high_region(unsigned long start_pfn, unsigned long end_pfn) { unsigned long tmp; @@ -458,9 +442,8 @@ /* Saves us work later. */ memset((void *)&empty_zero_page, 0, PAGE_SIZE); - i = last_valid_pfn >> (8 + 5); + i = last_valid_pfn >> ((20 - PAGE_SHIFT) + 5); i += 1; - sparc_valid_addr_bitmap = (unsigned long *) __alloc_bootmem(i << 2, SMP_CACHE_BYTES, 0UL); @@ -472,7 +455,7 @@ taint_real_pages(); - max_mapnr = last_valid_pfn; + max_mapnr = last_valid_pfn - (phys_base >> PAGE_SHIFT); high_memory = __va(max_low_pfn << PAGE_SHIFT); #ifdef DEBUG_BOOTMEM @@ -480,10 +463,6 @@ #endif num_physpages = totalram_pages = free_all_bootmem(); -#if 0 - free_unused_mem_map(); -#endif - for (i = 0; sp_banks[i].num_bytes != 0; i++) { unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT; unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT; @@ -513,19 +492,6 @@ initpages << (PAGE_SHIFT-10), totalhigh_pages << (PAGE_SHIFT-10), (unsigned long)PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT)); - - /* NOTE NOTE NOTE NOTE - * Please keep track of things and make sure this - * always matches the code in mm/page_alloc.c -DaveM - */ - i = nr_free_pages() >> 7; - if (i < 48) - i = 48; - if (i > 256) - i = 256; - freepages.min = i; - freepages.low = i << 1; - freepages.high = freepages.low + i; } void free_initmem (void) diff -u --recursive --new-file v2.4.2/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.4.2/linux/arch/sparc/mm/srmmu.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc/mm/srmmu.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.226 2001/02/13 01:16:44 davem Exp $ +/* $Id: srmmu.c,v 1.228 2001/03/16 06:56:20 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1124,6 +1124,15 @@ unsigned long pstart = (sp_banks[sp_entry].base_addr & SRMMU_PGDIR_MASK); unsigned long vstart = (vbase & SRMMU_PGDIR_MASK); unsigned long vend = SRMMU_PGDIR_ALIGN(vbase + sp_banks[sp_entry].num_bytes); + /* Map "low" memory only */ + const unsigned long min_vaddr = PAGE_OFFSET; + const unsigned long max_vaddr = PAGE_OFFSET + SRMMU_MAXMEM; + + if (vstart < min_vaddr || vstart >= max_vaddr) + return vstart; + + if (vend > max_vaddr || vend < min_vaddr) + vend = max_vaddr; while(vstart < vend) { do_large_mapping(vstart, pstart); @@ -1159,10 +1168,11 @@ extern void sparc_context_init(int); extern int linux_num_cpus; +extern unsigned long totalhigh_pages; void (*poke_srmmu)(void) __initdata = NULL; -extern void bootmem_init(void); +extern unsigned long bootmem_init(unsigned long *pages_avail); extern void sun_serial_setup(void); void __init srmmu_paging_init(void) @@ -1172,6 +1182,7 @@ pgd_t *pgd; pmd_t *pmd; pte_t *pte; + unsigned long pages_avail; sparc_iomap.start = SUN4M_IOBASE_VADDR; /* 16MB of IOSPACE on all sun4m's. */ @@ -1196,7 +1207,8 @@ prom_halt(); } - bootmem_init(); + pages_avail = 0; + last_valid_pfn = bootmem_init(&pages_avail); srmmu_nocache_init(); srmmu_inherit_prom_mappings(0xfe400000,(LINUX_OPPROM_ENDVM-PAGE_SIZE)); @@ -1245,11 +1257,25 @@ kmap_init(); { - unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long zholes_size[MAX_NR_ZONES]; + unsigned long npages; + int znum; - zones_size[ZONE_DMA] = max_low_pfn; - zones_size[ZONE_HIGHMEM] = highend_pfn - max_low_pfn; - free_area_init(zones_size); + for (znum = 0; znum < MAX_NR_ZONES; znum++) + zones_size[znum] = zholes_size[znum] = 0; + + npages = max_low_pfn - (phys_base >> PAGE_SHIFT); + + zones_size[ZONE_DMA] = npages; + zholes_size[ZONE_DMA] = npages - pages_avail; + + npages = highend_pfn - max_low_pfn; + zones_size[ZONE_HIGHMEM] = npages; + zholes_size[ZONE_HIGHMEM] = npages - calc_highpages(); + + free_area_init_node(0, NULL, NULL, zones_size, + phys_base, zholes_size); } } diff -u --recursive --new-file v2.4.2/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.4.2/linux/arch/sparc/mm/sun4c.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc/mm/sun4c.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.202 2000/12/01 03:17:31 anton Exp $ +/* $Id: sun4c.c,v 1.205 2001/03/16 06:57:41 davem Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include /* Because of our dynamic kernel TLB miss strategy, and how * our DVMA mapping allocation works, you _MUST_: @@ -2432,7 +2434,7 @@ extern void sparc_context_init(int); extern unsigned long end; -extern void bootmem_init(void); +extern unsigned long bootmem_init(unsigned long *pages_avail); extern unsigned long last_valid_pfn; extern void sun_serial_setup(void); @@ -2441,13 +2443,14 @@ int i, cnt; unsigned long kernel_end, vaddr; extern struct resource sparc_iomap; - unsigned long end_pfn; + unsigned long end_pfn, pages_avail; kernel_end = (unsigned long) &end; kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4); kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end); - bootmem_init(); + pages_avail = 0; + last_valid_pfn = bootmem_init(&pages_avail); end_pfn = last_valid_pfn; /* This does not logically belong here, but we need to @@ -2488,10 +2491,25 @@ sparc_context_init(num_contexts); { - unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long zholes_size[MAX_NR_ZONES]; + unsigned long npages; + int znum; - zones_size[ZONE_DMA] = end_pfn; - free_area_init(zones_size); + for (znum = 0; znum < MAX_NR_ZONES; znum++) + zones_size[znum] = zholes_size[znum] = 0; + + npages = max_low_pfn - (phys_base >> PAGE_SHIFT); + + zones_size[ZONE_DMA] = npages; + zholes_size[ZONE_DMA] = npages - pages_avail; + + npages = highend_pfn - max_low_pfn; + zones_size[ZONE_HIGHMEM] = npages; + zholes_size[ZONE_HIGHMEM] = npages - calc_highpages(); + + free_area_init_node(0, NULL, NULL, zones_size, + phys_base, zholes_size); } cnt = 0; 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.130 2001/01/18 04:47:44 davem Exp $ +# $Id: config.in,v 1.136 2001/03/24 06:04:24 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -47,6 +47,9 @@ define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y bool 'PCI support' CONFIG_PCI +if [ "$CONFIG_PCI" = "y" ] ; then + define_bool CONFIG_RTC y +fi source drivers/pci/Config.in tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS @@ -74,6 +77,7 @@ tristate 'SUNW, envctrl support' CONFIG_ENVCTRL tristate '7-Segment Display support' CONFIG_DISPLAY7SEG tristate 'CP1XXX Hardware Watchdog support' CONFIG_WATCHDOG_CP1XXX + tristate 'RIO Hardware Watchdog support' CONFIG_WATCHDOG_RIO fi endmenu @@ -165,12 +169,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 @@ -197,8 +203,6 @@ fi endmenu -source drivers/message/fusion/Config.in - source drivers/fc4/Config.in if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -284,6 +288,7 @@ bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I fi tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN + tristate 'Sun GEM support' CONFIG_SUNGEM fi tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS endmenu @@ -325,7 +330,11 @@ dep_tristate ' Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM endmenu +source drivers/input/Config.in + source fs/Config.in + +source drivers/usb/Config.in mainmenu_option next_comment comment 'Watchdog' 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 Sun Mar 25 18:14:21 2001 @@ -38,6 +38,7 @@ CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y +CONFIG_RTC=y CONFIG_PCI_NAMES=y CONFIG_SUN_OPENPROMFS=m CONFIG_NET=y @@ -70,6 +71,7 @@ CONFIG_ENVCTRL=m CONFIG_DISPLAY7SEG=m CONFIG_WATCHDOG_CP1XXX=m +CONFIG_WATCHDOG_RIO=m # # Console drivers @@ -125,8 +127,8 @@ # # Linux/SPARC audio subsystem (EXPERIMENTAL) # -CONFIG_SPARCAUDIO=y -CONFIG_SPARCAUDIO_CS4231=y +CONFIG_SPARCAUDIO=m +CONFIG_SPARCAUDIO_CS4231=m # CONFIG_SPARCAUDIO_DUMMY is not set # @@ -151,7 +153,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 +306,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 @@ -318,7 +321,7 @@ # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set CONFIG_SCSI_QLOGIC_ISP=m -CONFIG_SCSI_QLOGIC_FC=m +CONFIG_SCSI_QLOGIC_FC=y # # Fibre Channel support @@ -388,6 +391,7 @@ CONFIG_ACENIC=m # CONFIG_ACENIC_OMIT_TIGON_I is not set CONFIG_SK98LIN=m +CONFIG_SUNGEM=y CONFIG_MYRI_SBUS=m CONFIG_FDDI=y CONFIG_SKFP=m @@ -411,6 +415,17 @@ CONFIG_DRM_FFB=m # +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# # File systems # # CONFIG_QUOTA is not set @@ -522,6 +537,99 @@ # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_UTF8 is not set + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=y + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +CONFIG_USB_BLUETOOTH=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_WACOM=m + +# +# USB Imaging devices +# +CONFIG_USB_DC2XX=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +CONFIG_USB_MICROTEK=m + +# +# USB Multimedia devices +# +CONFIG_USB_IBMCAM=m +CONFIG_USB_OV511=m +CONFIG_USB_DSBR=m +CONFIG_USB_DABUSB=m + +# +# USB Network adaptors +# +CONFIG_USB_PLUSB=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_NET1080=m + +# +# USB port drivers +# +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_DEBUG is not set +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set +# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_OMNINET=m + +# +# USB misc drivers +# +CONFIG_USB_RIO500=m # # Watchdog 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/auxio.c linux/arch/sparc64/kernel/auxio.c --- v2.4.2/linux/arch/sparc64/kernel/auxio.c Tue Oct 3 09:24:41 2000 +++ linux/arch/sparc64/kernel/auxio.c Sun Mar 25 18:14:21 2001 @@ -18,6 +18,7 @@ #include #include #include +#include #include /* Probe and map in the Auxiliary I/O register */ @@ -56,7 +57,7 @@ return; } #endif - if(central_bus || this_is_starfire) { + if (central_bus || this_is_starfire || (tlb_type == cheetah)) { auxio_register = 0UL; return; } diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.4.2/linux/arch/sparc64/kernel/binfmt_aout32.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Sun Mar 25 18:14:21 2001 @@ -277,24 +277,24 @@ goto beyond_if; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (error != N_TXTADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; @@ -318,7 +318,8 @@ unsigned long pgd_cache; pgd_cache = ((unsigned long)current->mm->pgd[0])<<11UL; - __asm__ __volatile__("stxa\t%0, [%1] %2" + __asm__ __volatile__("stxa\t%0, [%1] %2\n\t" + "membar #Sync" : /* no outputs */ : "r" (pgd_cache), "r" (TSB_REG), "i" (ASI_DMMU)); @@ -368,12 +369,12 @@ start_addr = ex.a_entry & 0xfffff000; /* Now use mmap to map the library into memory. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); retval = error; if (error != start_addr) goto out; 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 Sun Mar 25 18:14:21 2001 @@ -34,7 +34,8 @@ { 0x22, 0x10, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x11, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"}, - { 0x17, 0x14, 0, "UltraSparc III integrated FPU"}, + { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"}, + { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"}, }; #define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info)) @@ -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/devices.c linux/arch/sparc64/kernel/devices.c --- v2.4.2/linux/arch/sparc64/kernel/devices.c Mon Dec 20 22:05:52 1999 +++ linux/arch/sparc64/kernel/devices.c Sun Mar 25 18:14:21 2001 @@ -13,6 +13,7 @@ #include #include #include +#include struct prom_cpuinfo linux_cpus[64] __initdata = { { 0 } }; unsigned prom_cpu_nodes[64]; @@ -50,8 +51,14 @@ if(strcmp(node_str, "cpu") == 0) { cpu_nds[cpu_ctr] = scan; linux_cpus[cpu_ctr].prom_node = scan; - prom_getproperty(scan, "upa-portid", - (char *) &thismid, sizeof(thismid)); + thismid = 0; + if (tlb_type == spitfire) { + prom_getproperty(scan, "upa-portid", + (char *) &thismid, sizeof(thismid)); + } else if (tlb_type == cheetah) { + prom_getproperty(scan, "portid", + (char *) &thismid, sizeof(thismid)); + } linux_cpus[cpu_ctr].mid = thismid; printk("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/dtlb_base.S linux/arch/sparc64/kernel/dtlb_base.S --- v2.4.2/linux/arch/sparc64/kernel/dtlb_base.S Sun Nov 12 20:37:16 2000 +++ linux/arch/sparc64/kernel/dtlb_base.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: dtlb_base.S,v 1.8 2000/11/10 08:28:45 davem Exp $ +/* $Id: dtlb_base.S,v 1.9 2001/03/22 00:12:32 davem Exp $ * dtlb_base.S: Front end to DTLB miss replacement strategy. * This is included directly into the trap table. * @@ -10,8 +10,6 @@ #define VPTE_SHIFT (PAGE_SHIFT - 3) #define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) -#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W) -#define KERN_IOBITS (KERN_LOWBITS ^ KERN_LOWBITS_IO) /* %g1 TLB_SFSR (%g1 + %g1 == TLB_TAG_ACCESS) * %g2 (KERN_HIGHBITS | KERN_LOWBITS) @@ -94,5 +92,3 @@ #undef VPTE_SHIFT #undef KERN_HIGHBITS #undef KERN_LOWBITS -#undef KERN_LOWBITS_IO -#undef KERN_IOBITS 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.54 2001/02/13 01:16:44 davem Exp $ +/* $Id: ebus.c,v 1.60 2001/03/15 02:11:09 davem Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -25,6 +25,7 @@ #ifdef CONFIG_SUN_AUXIO extern void auxio_probe(void); #endif +extern void rs_init(void); static inline void *ebus_alloc(size_t size) { @@ -159,7 +160,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 { @@ -200,7 +201,10 @@ dev->num_addrs = len / sizeof(struct linux_prom_registers); for (i = 0; i < dev->num_addrs; i++) { - n = (regs[i].which_io - 0x10) >> 2; + if (dev->bus->is_rio == 0) + n = (regs[i].which_io - 0x10) >> 2; + else + n = regs[i].which_io; dev->resource[i].start = dev->bus->self->resource[n].start; dev->resource[i].start += (unsigned long)regs[i].phys_addr; @@ -222,7 +226,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 { @@ -269,14 +273,19 @@ struct linux_ebus *ebus; struct pci_dev *pdev; struct pcidev_cookie *cookie; - int nd, ebusnd; + int nd, ebusnd, is_rio; int num_ebus = 0; if (!pci_present()) return; + is_rio = 0; pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0); if (!pdev) { + pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_EBUS, 0); + is_rio = 1; + } + if (!pdev) { printk("ebus: No EBus's found.\n"); return; } @@ -286,6 +295,7 @@ ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); ebus->next = 0; + ebus->is_rio = is_rio; while (ebusnd) { /* SUNW,pci-qfe uses four empty ebuses on it. @@ -295,8 +305,16 @@ we'd have to tweak with the ebus_chain in the runtime after initialization. -jj */ if (!prom_getchild (ebusnd)) { + struct pci_dev *orig_pdev = pdev; + + is_rio = 0; pdev = pci_find_device(PCI_VENDOR_ID_SUN, - PCI_DEVICE_ID_SUN_EBUS, pdev); + PCI_DEVICE_ID_SUN_EBUS, orig_pdev); + if (!pdev) { + pdev = pci_find_device(PCI_VENDOR_ID_SUN, + PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev); + is_rio = 1; + } if (!pdev) { if (ebus == ebus_chain) { ebus_chain = NULL; @@ -305,7 +323,7 @@ } break; } - + ebus->is_rio = is_rio; cookie = pdev->sysdata; ebusnd = cookie->prom_node; continue; @@ -346,10 +364,20 @@ next_ebus: printk("\n"); - pdev = pci_find_device(PCI_VENDOR_ID_SUN, - PCI_DEVICE_ID_SUN_EBUS, pdev); - if (!pdev) - break; + { + struct pci_dev *orig_pdev = pdev; + + is_rio = 0; + pdev = pci_find_device(PCI_VENDOR_ID_SUN, + PCI_DEVICE_ID_SUN_EBUS, orig_pdev); + if (!pdev) { + pdev = pci_find_device(PCI_VENDOR_ID_SUN, + PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev); + is_rio = 1; + } + if (!pdev) + break; + } cookie = pdev->sysdata; ebusnd = cookie->prom_node; @@ -357,9 +385,11 @@ ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; ebus->next = 0; + ebus->is_rio = is_rio; ++num_ebus; } + rs_init(); #ifdef CONFIG_SUN_AUXIO auxio_probe(); #endif diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.4.2/linux/arch/sparc64/kernel/entry.S Fri Sep 8 17:55:17 2000 +++ linux/arch/sparc64/kernel/entry.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.120 2000/09/08 13:58:12 jj Exp $ +/* $Id: entry.S,v 1.127 2001/03/23 07:56:30 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -42,13 +42,29 @@ /* This is trivial with the new code... */ .globl do_fpdis do_fpdis: - ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g5 ! Load Group sethi %hi(TSTATE_PEF), %g4 ! IEU0 + rdpr %tstate, %g5 + andcc %g5, %g4, %g0 + be,pt %xcc, 1f + nop + rd %fprs, %g5 + andcc %g5, FPRS_FEF, %g0 + be,pt %xcc, 1f + nop + + /* Legal state when DCR_IFPOE is set in Cheetah %dcr. */ + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + add %g0, %g0, %g0 + ba,a,pt %xcc, rtrap_clr_l6 + +1: ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g5 ! Load Group wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles andcc %g5, FPRS_FEF, %g0 ! IEU1 Group be,a,pt %icc, 1f ! CTI clr %g7 ! IEU0 - ldub [%g6 + AOFF_task_thread + AOFF_thread_gsr], %g7 ! Load Group + ldx [%g6 + AOFF_task_thread + AOFF_thread_gsr], %g7 ! Load Group 1: andcc %g5, FPRS_DL, %g0 ! IEU1 bne,pn %icc, 2f ! CTI fzero %f0 ! FPA @@ -92,10 +108,9 @@ ldxa [%g3] ASI_DMMU, %g5 add %g6, AOFF_task_fpregs + 0xc0, %g2 stxa %g0, [%g3] ASI_DMMU + membar #Sync faddd %f0, %f2, %f8 fmuld %f0, %f2, %f10 - flush %g6 - membar #StoreLoad | #LoadLoad ldda [%g1] ASI_BLK_S, %f32 ! grrr, where is ASI_BLK_NUCLEUS 8-( ldda [%g2] ASI_BLK_S, %f48 faddd %f0, %f2, %f12 @@ -118,11 +133,10 @@ ldxa [%g3] ASI_DMMU, %g5 add %g6, AOFF_task_fpregs, %g1 stxa %g0, [%g3] ASI_DMMU + membar #Sync add %g6, AOFF_task_fpregs + 0x40, %g2 faddd %f32, %f34, %f36 fmuld %f32, %f34, %f38 - flush %g6 - membar #StoreLoad | #LoadLoad ldda [%g1] ASI_BLK_S, %f0 ! grrr, where is ASI_BLK_NUCLEUS 8-( ldda [%g2] ASI_BLK_S, %f16 faddd %f32, %f34, %f40 @@ -137,15 +151,14 @@ fmuld %f32, %f34, %f58 faddd %f32, %f34, %f60 fmuld %f32, %f34, %f62 - b,pt %xcc, fpdis_exit + ba,pt %xcc, fpdis_exit membar #Sync 3: mov SECONDARY_CONTEXT, %g3 add %g6, AOFF_task_fpregs, %g1 ldxa [%g3] ASI_DMMU, %g5 mov 0x40, %g2 stxa %g0, [%g3] ASI_DMMU - flush %g6 - membar #StoreLoad | #LoadLoad + membar #Sync ldda [%g1] ASI_BLK_S, %f0 ! grrr, where is ASI_BLK_NUCLEUS 8-( ldda [%g1 + %g2] ASI_BLK_S, %f16 add %g1, 0x80, %g1 @@ -154,7 +167,7 @@ membar #Sync fpdis_exit: stxa %g5, [%g3] ASI_DMMU - flush %g6 + membar #Sync fpdis_exit2: wr %g7, 0, %gsr ldx [%g6 + AOFF_task_thread + AOFF_thread_xfsr], %fsr @@ -164,22 +177,152 @@ wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits retry + .align 32 +fp_other_bounce: + call do_fpother + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + + .globl do_fpother_check_fitos + .align 32 +do_fpother_check_fitos: + sethi %hi(fp_other_bounce - 4), %g7 + or %g7, %lo(fp_other_bounce - 4), %g7 + + /* NOTE: Need to preserve %g7 until we fully commit + * to the fitos fixup. + */ + stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr] + rdpr %tstate, %g3 + andcc %g3, TSTATE_PRIV, %g0 + bne,pn %xcc, do_fptrap_after_fsr + nop + ldx [%g6 + AOFF_task_thread + AOFF_thread_xfsr], %g3 + srlx %g3, 14, %g1 + and %g1, 7, %g1 + cmp %g1, 2 ! Unfinished FP-OP + bne,pn %xcc, do_fptrap_after_fsr + sethi %hi(1 << 23), %g1 ! Inexact + andcc %g3, %g1, %g0 + bne,pn %xcc, do_fptrap_after_fsr + rdpr %tpc, %g1 + lduwa [%g1] ASI_AIUP, %g3 ! This cannot ever fail +#define FITOS_MASK 0xc1f83fe0 +#define FITOS_COMPARE 0x81a01880 + sethi %hi(FITOS_MASK), %g1 + or %g1, %lo(FITOS_MASK), %g1 + and %g3, %g1, %g1 + sethi %hi(FITOS_COMPARE), %g2 + or %g2, %lo(FITOS_COMPARE), %g2 + cmp %g1, %g2 + bne,pn %xcc, do_fptrap_after_fsr + nop + std %f62, [%g6 + AOFF_task_fpregs + (62 * 4)] + sethi %hi(fitos_table_1), %g1 + and %g3, 0x1f, %g2 + or %g1, %lo(fitos_table_1), %g1 + sllx %g2, 2, %g2 + jmpl %g1 + %g2, %g0 + ba,pt %xcc, fitos_emul_continue + +fitos_table_1: + fitod %f0, %f62 + fitod %f1, %f62 + fitod %f2, %f62 + fitod %f3, %f62 + fitod %f4, %f62 + fitod %f5, %f62 + fitod %f6, %f62 + fitod %f7, %f62 + fitod %f8, %f62 + fitod %f9, %f62 + fitod %f10, %f62 + fitod %f11, %f62 + fitod %f12, %f62 + fitod %f13, %f62 + fitod %f14, %f62 + fitod %f15, %f62 + fitod %f16, %f62 + fitod %f17, %f62 + fitod %f18, %f62 + fitod %f19, %f62 + fitod %f20, %f62 + fitod %f21, %f62 + fitod %f22, %f62 + fitod %f23, %f62 + fitod %f24, %f62 + fitod %f25, %f62 + fitod %f26, %f62 + fitod %f27, %f62 + fitod %f28, %f62 + fitod %f29, %f62 + fitod %f30, %f62 + fitod %f31, %f62 + +fitos_emul_continue: + sethi %hi(fitos_table_2), %g1 + srl %g3, 25, %g2 + or %g1, %lo(fitos_table_2), %g1 + and %g2, 0x1f, %g2 + sllx %g2, 2, %g2 + jmpl %g1 + %g2, %g0 + ba,pt %xcc, fitos_emul_fini + +fitos_table_2: + fdtos %f62, %f0 + fdtos %f62, %f1 + fdtos %f62, %f2 + fdtos %f62, %f3 + fdtos %f62, %f4 + fdtos %f62, %f5 + fdtos %f62, %f6 + fdtos %f62, %f7 + fdtos %f62, %f8 + fdtos %f62, %f9 + fdtos %f62, %f10 + fdtos %f62, %f11 + fdtos %f62, %f12 + fdtos %f62, %f13 + fdtos %f62, %f14 + fdtos %f62, %f15 + fdtos %f62, %f16 + fdtos %f62, %f17 + fdtos %f62, %f18 + fdtos %f62, %f19 + fdtos %f62, %f20 + fdtos %f62, %f21 + fdtos %f62, %f22 + fdtos %f62, %f23 + fdtos %f62, %f24 + fdtos %f62, %f25 + fdtos %f62, %f26 + fdtos %f62, %f27 + fdtos %f62, %f28 + fdtos %f62, %f29 + fdtos %f62, %f30 + fdtos %f62, %f31 + +fitos_emul_fini: + ldd [%g6 + AOFF_task_fpregs + (62 * 4)], %f62 + done + .globl do_fptrap .align 32 do_fptrap: - ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3 stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr] +do_fptrap_after_fsr: + ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3 rd %fprs, %g1 or %g3, %g1, %g3 stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved] rd %gsr, %g3 - stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr] + stx %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr] mov SECONDARY_CONTEXT, %g3 add %g6, AOFF_task_fpregs, %g2 ldxa [%g3] ASI_DMMU, %g5 stxa %g0, [%g3] ASI_DMMU - flush %g6 - membar #StoreStore | #LoadStore + membar #Sync andcc %g1, FPRS_DL, %g0 be,pn %icc, 4f mov 0x40, %g3 @@ -193,7 +336,7 @@ 5: mov SECONDARY_CONTEXT, %g1 membar #Sync stxa %g5, [%g1] ASI_DMMU - flush %g6 + membar #Sync ba,pt %xcc, etrap wr %g0, 0, %fprs @@ -215,7 +358,7 @@ .globl do_ivec do_ivec: mov 0x40, %g3 - ldxa [%g3 + %g0] ASI_UDB_INTR_R, %g3 + ldxa [%g3 + %g0] ASI_INTR_R, %g3 sethi %hi(KERNBASE), %g4 cmp %g3, %g4 bgeu,pn %xcc, do_ivec_xcall @@ -242,10 +385,10 @@ do_ivec_xcall: mov 0x50, %g1 - ldxa [%g1 + %g0] ASI_UDB_INTR_R, %g1 + ldxa [%g1 + %g0] ASI_INTR_R, %g1 srl %g3, 0, %g3 mov 0x60, %g7 - ldxa [%g7 + %g0] ASI_UDB_INTR_R, %g7 + ldxa [%g7 + %g0] ASI_INTR_R, %g7 stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync jmpl %g3, %g0 @@ -1114,9 +1257,18 @@ ldx [%g3 + %lo(timer_tick_offset)], %g3 or %g2, %lo(xtime), %g2 or %g1, %lo(timer_tick_compare), %g1 -1: ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4 - rd %tick, %o1 - ldx [%g1], %g7 +1: rdpr %ver, %o2 + sethi %hi(0x003e0014), %o1 + srlx %o2, 32, %o2 + or %o1, %lo(0x003e0014), %o1 + ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4 + cmp %o2, %o1 + bne,pt %xcc, 2f + nop + ba,pt %xcc, 3f + rd %asr24, %o1 +2: rd %tick, %o1 +3: ldx [%g1], %g7 ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o2 xor %o4, %o2, %o2 xor %o5, %o3, %o3 diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S --- v2.4.2/linux/arch/sparc64/kernel/etrap.S Thu Mar 30 16:54:53 2000 +++ linux/arch/sparc64/kernel/etrap.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.43 2000/03/29 09:55:30 davem Exp $ +/* $Id: etrap.S,v 1.44 2001/03/22 00:51:25 davem Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -186,3 +186,5 @@ nop #undef TASK_REGOFF +#undef ETRAP_PSTATE1 +#undef ETRAP_PSTATE2 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.65 2000/05/09 17:40:13 davem Exp $ +/* $Id: head.S,v 1.75 2001/03/22 09:54:26 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,11 +78,145 @@ * 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_IFPOE | 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 + or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 + ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 + or %g5, %g3, %g5 + 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. */ mov (LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1 stxa %g1, [%g0] ASI_LSU_CONTROL + membar #Sync /* * Make sure we are in privileged mode, have address masking, @@ -93,7 +229,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 +240,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 +262,13 @@ 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 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 @@ -164,6 +300,7 @@ nop stxa %g0, [%l7] ASI_IMMU stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS + membar #Sync 2: cmp %l0, (63 << 3) blu,pt %xcc, 1b @@ -186,6 +323,7 @@ nop stxa %g0, [%l7] ASI_DMMU stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS + membar #Sync 2: cmp %l0, (63 << 3) blu,pt %xcc, 1b @@ -235,7 +373,47 @@ mov TLB_TAG_ACCESS, %g2 stxa %g3, [%g2] ASI_IMMU stxa %g3, [%g2] ASI_DMMU + 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_tlb_fixup + nop + +cheetah_tlb_fixup: + set (0 << 16) | (15 << 3), %g7 + ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1 + andn %g1, (_PAGE_G), %g1 + stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS + membar #Sync + ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1 + andn %g1, (_PAGE_G), %g1 + stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS + membar #Sync + + /* Kill instruction prefetch queues. */ + flush %g3 + membar #Sync + + /* Set TLB type to cheetah. */ + mov 1, %g2 + sethi %hi(tlb_type), %g5 + stw %g2, [%g5 + %lo(tlb_type)] + + /* Patch copy/page operations to cheetah optimized versions. */ + call cheetah_patch_copyops + nop + call cheetah_patch_pgcopyops + nop + + ba,pt %xcc, tlb_fixup_done + nop + +spitfire_tlb_fixup: mov (63 << 3), %g7 ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1 andn %g1, (_PAGE_G), %g1 @@ -251,6 +429,12 @@ flush %g3 membar #Sync + /* Set TLB type to spitfire. */ + mov 0, %g2 + sethi %hi(tlb_type), %g5 + stw %g2, [%g5 + %lo(tlb_type)] + +tlb_fixup_done: sethi %hi(init_task_union), %g6 or %g6, %lo(init_task_union), %g6 mov %sp, %l6 @@ -285,28 +469,19 @@ wrpr %g0, 0x0, %tl /* Clear the bss */ - sethi %hi(8191), %l2 - or %l2, %lo(8191), %l2 - sethi %hi(__bss_start), %l0 - or %l0, %lo(__bss_start), %l0 - sethi %hi(_end), %l1 - or %l1, %lo(_end), %l1 - add %l1, %l2, %l1 - andn %l1, %l2, %l1 - add %l2, 1, %l2 - add %l0, %g0, %o0 -1: - mov %l2, %o1 + sethi %hi(__bss_start), %o0 + or %o0, %lo(__bss_start), %o0 + sethi %hi(_end), %o1 + or %o1, %lo(_end), %o1 call __bzero - add %l0, %l2, %l0 - cmp %l0, %l1 - blu,pt %xcc, 1b - add %l0, %g0, %o0 + sub %o1, %o0, %o1 /* Now clear empty_zero_page */ - mov %l2, %o1 + sethi %hi(8192), %o1 + or %o1, %lo(8192), %o1 + sethi %hi(KERNBASE), %g3 call __bzero - mov %g3, %o0 + or %g3, %lo(KERNBASE), %o0 mov %l6, %o1 ! OpenPROM stack call prom_init @@ -340,14 +515,16 @@ wrpr %o1, (PSTATE_MG|PSTATE_IE), %pstate /* Set fixed globals used by dTLB miss handler. */ -#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) +#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 + +#define VPTE_BASE_SPITFIRE 0xfffffffe00000000 +#if 1 +#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE +#else +#define VPTE_BASE_CHEETAH 0xffe0000000000000 #endif + mov TSB_REG, %g1 stxa %g0, [%g1] ASI_DMMU membar #Sync @@ -356,13 +533,30 @@ 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 -#undef VPTE_BASE +#undef VPTE_BASE_SPITFIRE +#undef VPTE_BASE_CHEETAH /* Setup Interrupt globals */ wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate @@ -371,9 +565,6 @@ or %g5, %lo(__up_workvec), %g6 #else /* By definition of where we are, this is boot_cpu. */ - sethi %hi(cpu_data), %g5 - or %g5, %lo(cpu_data), %g5 - brz,pt %i0, not_starfire sethi %hi(0x1fff4000), %g1 or %g1, %lo(0x1fff4000), %g1 @@ -384,12 +575,27 @@ nop not_starfire: + rdpr %ver, %g1 + sethi %hi(0x003e0014), %g5 + srlx %g1, 32, %g1 + or %g7, %lo(0x003e0014), %g5 + cmp %g1, %g5 + bne,pt %icc, not_cheetah + nop + + ldxa [%g0] ASI_SAFARI_CONFIG, %g1 + srlx %g1, 17, %g1 + and %g1, 0x3ff, %g1 ! 10bit Safari Agent ID + +not_cheetah: ldxa [%g0] ASI_UPA_CONFIG, %g1 srlx %g1, 17, %g1 and %g1, 0x1f, %g1 /* In theory this is: &(cpu_data[boot_cpu_id].irq_worklists[0]) */ set_worklist: + sethi %hi(cpu_data), %g5 + or %g5, %lo(cpu_data), %g5 sllx %g1, 7, %g1 add %g5, %g1, %g5 add %g5, 64, %g6 @@ -398,9 +604,23 @@ /* Kill PROM timer */ wr %g0, 0, %tick_cmpr + rdpr %ver, %g1 + sethi %hi(0x003e0014), %g5 + srlx %g1, 32, %g1 + or %g7, %lo(0x003e0014), %g5 + cmp %g1, %g5 + bne,pt %icc, 1f + nop + + /* Disable STICK_INT interrupts. */ + sethi %hi(0x80000000), %g1 + sllx %g1, 32, %g1 + wr %g1, %asr25 + /* Ok, we're done setting up all the state our trap mechanims needs, * now get back into normal globals and let the PROM know what is up. */ +1: wrpr %g0, %g0, %wstate wrpr %o1, PSTATE_IE, %pstate 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.107 2001/02/13 01:16:44 davem Exp $ +/* $Id: ioctl32.c,v 1.110 2001/03/22 12:51:25 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -48,6 +48,7 @@ #include #include #include +#include #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) /* Ugh. This header really is not clean */ #define min min @@ -67,7 +68,6 @@ #include #include #include -#include #include #include #include @@ -2068,6 +2068,7 @@ u32 proc; u32 pv[ABS_MAX_PV + 1]; u32 lv[ABS_MAX_LV + 1]; + uint8_t vg_uuid[UUID_LEN+1]; /* volume group UUID */ } vg32_t; typedef struct { @@ -2093,6 +2094,7 @@ uint32_t pe_stale; u32 pe; u32 inode; + uint8_t pv_uuid[UUID_LEN+1]; } pv32_t; typedef struct { @@ -2103,9 +2105,16 @@ typedef struct { u32 lv_index; u32 lv; + /* Transfer size because user space and kernel space differ */ + uint16_t size; } lv_status_byindex_req32_t; typedef struct { + dev_t dev; + u32 lv; +} lv_status_bydev_req32_t; + +typedef struct { uint8_t lv_name[NAME_LEN]; kdev_t old_dev; kdev_t new_dev; @@ -2204,11 +2213,12 @@ if (l->lv_block_exception) { lbe32 = (lv_block_exception32_t *)A(ptr2); memset(lbe, 0, size); - for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) { - err |= get_user(lbe->rsector_org, &lbe32->rsector_org); - err |= __get_user(lbe->rdev_org, &lbe32->rdev_org); - err |= __get_user(lbe->rsector_new, &lbe32->rsector_new); - err |= __get_user(lbe->rdev_new, &lbe32->rdev_new); + for (i = 0; i < l->lv_remap_end; i++, lbe++, lbe32++) { + err |= get_user(lbe->rsector_org, &lbe32->rsector_org); + err |= __get_user(lbe->rdev_org, &lbe32->rdev_org); + err |= __get_user(lbe->rsector_new, &lbe32->rsector_new); + err |= __get_user(lbe->rdev_new, &lbe32->rdev_new); + } } } @@ -2239,8 +2249,9 @@ err |= __copy_to_user(&ul->lv_remap_ptr, &l->lv_remap_ptr, ((long)&ul->dummy[0]) - ((long)&ul->lv_remap_ptr)); size = l->lv_allocated_le * sizeof(pe_t); - err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size); - return -EFAULT; + if (ptr1) + err |= __copy_to_user((void *)A(ptr1), l->lv_current_pe, size); + return err ? -EFAULT : 0; } static int do_lvm_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -2250,7 +2261,8 @@ lv_req_t lv_req; le_remap_req_t le_remap; lv_status_byindex_req_t lv_byindex; - pv_status_req32_t pv_status; + lv_status_bydev_req_t lv_bydev; + pv_status_req_t pv_status; } u; pv_t p; int err; @@ -2273,6 +2285,11 @@ kfree(v); return -EFAULT; } + if (copy_from_user(v->vg_uuid, ((vg32_t *)arg)->vg_uuid, UUID_LEN+1)) { + kfree(v); + return -EFAULT; + } + karg = v; memset(v->pv, 0, sizeof(v->pv) + sizeof(v->lv)); if (v->pv_max > ABS_MAX_PV || v->lv_max > ABS_MAX_LV) @@ -2286,11 +2303,18 @@ err = -ENOMEM; break; } - err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8); + err = copy_from_user(v->pv[i], (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1); if (err) { err = -EFAULT; break; } + err = copy_from_user(v->pv[i]->pv_uuid, ((pv32_t *)A(ptr))->pv_uuid, UUID_LEN+1); + if (err) { + err = -EFAULT; + break; + } + + v->pv[i]->pe = NULL; v->pv[i]->inode = NULL; } } @@ -2309,8 +2333,9 @@ case LV_EXTEND: case LV_REDUCE: case LV_REMOVE: + case LV_RENAME: case LV_STATUS_BYNAME: - err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name)); + err = copy_from_user(&u.pv_status, arg, sizeof(u.pv_status.pv_name)); if (err) return -EFAULT; if (cmd != LV_REMOVE) { err = __get_user(ptr, &((lv_req32_t *)arg)->lv); @@ -2319,24 +2344,29 @@ } else u.lv_req.lv = NULL; break; + + case LV_STATUS_BYINDEX: err = get_user(u.lv_byindex.lv_index, &((lv_status_byindex_req32_t *)arg)->lv_index); err |= __get_user(ptr, &((lv_status_byindex_req32_t *)arg)->lv); if (err) return err; u.lv_byindex.lv = get_lv_t(ptr, &err); break; + case LV_STATUS_BYDEV: + err = get_user(u.lv_bydev.dev, &((lv_status_bydev_req32_t *)arg)->dev); + u.lv_bydev.lv = get_lv_t(ptr, &err); + if (err) return err; + u.lv_bydev.lv = &p; + p.pe = NULL; p.inode = NULL; + break; case VG_EXTEND: - err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8); + err = copy_from_user(&p, (void *)arg, sizeof(pv32_t) - 8 - UUID_LEN+1); + if (err) return -EFAULT; + err = copy_from_user(p.pv_uuid, ((pv32_t *)arg)->pv_uuid, UUID_LEN+1); if (err) return -EFAULT; p.pe = NULL; p.inode = NULL; karg = &p; break; - case LE_REMAP: - err = copy_from_user(&u.le_remap, (void *)arg, sizeof(le_remap_req32_t)); - if (err) return -EFAULT; - u.le_remap.new_pe = ((le_remap_req32_t *)&u.le_remap)->new_pe; - u.le_remap.old_pe = ((le_remap_req32_t *)&u.le_remap)->old_pe; - break; case PV_CHANGE: case PV_STATUS: err = copy_from_user(&u.pv_status, arg, sizeof(u.lv_req.lv_name)); @@ -2345,7 +2375,7 @@ if (err) return err; u.pv_status.pv = &p; if (cmd == PV_CHANGE) { - err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8); + err = copy_from_user(&p, (void *)A(ptr), sizeof(pv32_t) - 8 - UUID_LEN+1); if (err) return -EFAULT; p.pe = NULL; p.inode = NULL; } @@ -2361,6 +2391,9 @@ clear_user(&((vg32_t *)arg)->proc, sizeof(vg32_t) - (long)&((vg32_t *)0)->proc)) err = -EFAULT; } + if (copy_to_user(((vg32_t *)arg)->vg_uuid, v->vg_uuid, UUID_LEN+1)) { + err = -EFAULT; + } kfree(v); break; case VG_CREATE: @@ -2383,12 +2416,21 @@ if (!err) err = copy_lv_t(ptr, u.lv_byindex.lv); put_lv_t(u.lv_byindex.lv); } + break; case PV_STATUS: if (!err) { - err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8); - if (err) return -EFAULT; + err = copy_to_user((void *)A(ptr), &p, sizeof(pv32_t) - 8 - UUID_LEN+1); + if (err) return -EFAULT; + err = copy_to_user(((pv_t *)A(ptr))->pv_uuid, p.pv_uuid, UUID_LEN + 1); + if (err) return -EFAULT; } break; + case LV_STATUS_BYDEV: + if (!err) { + if (!err) err = copy_lv_t(ptr, u.lv_bydev.lv); + put_lv_t(u.lv_byindex.lv); + } + break; } return err; } @@ -3222,8 +3264,22 @@ COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int)) COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int)) /* Little p (/dev/rtc, /dev/envctrl, etc.) */ -COMPATIBLE_IOCTL(RTCGET) -COMPATIBLE_IOCTL(RTCSET) +COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */ +COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ +COMPATIBLE_IOCTL(RTC_AIE_ON) +COMPATIBLE_IOCTL(RTC_AIE_OFF) +COMPATIBLE_IOCTL(RTC_UIE_ON) +COMPATIBLE_IOCTL(RTC_UIE_OFF) +COMPATIBLE_IOCTL(RTC_PIE_ON) +COMPATIBLE_IOCTL(RTC_PIE_OFF) +COMPATIBLE_IOCTL(RTC_WIE_ON) +COMPATIBLE_IOCTL(RTC_WIE_OFF) +COMPATIBLE_IOCTL(RTC_ALM_SET) +COMPATIBLE_IOCTL(RTC_ALM_READ) +COMPATIBLE_IOCTL(RTC_RD_TIME) +COMPATIBLE_IOCTL(RTC_SET_TIME) +COMPATIBLE_IOCTL(RTC_WKALM_SET) +COMPATIBLE_IOCTL(RTC_WKALM_RD) COMPATIBLE_IOCTL(ENVCTRL_RD_WARNING_TEMPERATURE) COMPATIBLE_IOCTL(ENVCTRL_RD_SHUTDOWN_TEMPERATURE) COMPATIBLE_IOCTL(ENVCTRL_RD_CPU_TEMPERATURE) @@ -3331,6 +3387,7 @@ COMPATIBLE_IOCTL(PPPIOCCONNECT) COMPATIBLE_IOCTL(PPPIOCDISCONN) COMPATIBLE_IOCTL(PPPIOCATTCHAN) +COMPATIBLE_IOCTL(PPPIOCGCHAN) /* PPPOX */ COMPATIBLE_IOCTL(PPPOEIOCSFWD); COMPATIBLE_IOCTL(PPPOEIOCDFWD); @@ -3565,6 +3622,7 @@ COMPATIBLE_IOCTL(VG_STATUS_GET_COUNT) COMPATIBLE_IOCTL(VG_STATUS_GET_NAMELIST) COMPATIBLE_IOCTL(VG_REMOVE) +COMPATIBLE_IOCTL(VG_RENAME) COMPATIBLE_IOCTL(VG_REDUCE) COMPATIBLE_IOCTL(PE_LOCK_UNLOCK) COMPATIBLE_IOCTL(PV_FLUSH) @@ -3576,6 +3634,9 @@ COMPATIBLE_IOCTL(LV_SET_ACCESS) COMPATIBLE_IOCTL(LV_SET_STATUS) COMPATIBLE_IOCTL(LV_SET_ALLOCATION) +COMPATIBLE_IOCTL(LE_REMAP) +COMPATIBLE_IOCTL(LV_BMAP) +COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE) #endif /* LVM */ #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC) @@ -3749,9 +3810,9 @@ HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl) HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl) HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl) +HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl) HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl) HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl) -HANDLE_IOCTL(LE_REMAP, do_lvm_ioctl) HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl) HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl) #endif /* LVM */ @@ -3766,6 +3827,12 @@ HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma); HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx); #endif /* DRM */ +#if 0 +HANDLE_IOCTL(RTC32_IRQP_READ, do_rtc_ioctl) +HANDLE_IOCTL(RTC32_IRQP_SET, do_rtc_ioctl) +HANDLE_IOCTL(RTC32_EPOCH_READ, do_rtc_ioctl) +HANDLE_IOCTL(RTC32_EPOCH_SET, do_rtc_ioctl) +#endif IOCTL_TABLE_END unsigned int ioctl32_hash_table[1024]; diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.4.2/linux/arch/sparc64/kernel/irq.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/irq.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.95 2001/02/13 01:16:44 davem Exp $ +/* $Id: irq.c,v 1.99 2001/03/22 02:19:23 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -132,14 +132,23 @@ if (imap == 0UL) return; - if(this_is_starfire == 0) { + if (tlb_type == cheetah) { + /* We set it to our Safari AID. */ + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (tid) + : "i" (ASI_SAFARI_CONFIG)); + tid = ((tid & (0x3ffUL<<17)) << 9); + tid &= IMAP_AID_SAFARI; + } else if (this_is_starfire == 0) { /* We set it to our UPA MID. */ __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG)); tid = ((tid & UPA_CONFIG_MID) << 9); + tid &= IMAP_TID_UPA; } else { tid = (starfire_translate(imap, current->processor) << 26); + tid &= IMAP_TID_UPA; } /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product @@ -150,7 +159,7 @@ * * Things like FFB can now be handled via the new IRQ mechanism. */ - upa_writel(IMAP_VALID | (tid & IMAP_TID), imap); + upa_writel(tid | IMAP_VALID, imap); } /* This now gets passed true ino's as well. */ @@ -729,6 +738,10 @@ /* Voo-doo programming. */ if (cpu_data[buddy].idle_volume < FORWARD_VOLUME) should_forward = 0; + + /* This just so happens to be correct on Cheetah + * at the moment. + */ buddy <<= 26; } #endif @@ -737,10 +750,23 @@ /* * Check for TICK_INT on level 14 softint. */ - if ((irq == 14) && (get_softint() & (1UL << 0))) - irq = 0; -#endif + { + unsigned long clr_mask = 1 << irq; + unsigned long tick_mask; + + if (SPARC64_USE_STICK) + tick_mask = (1UL << 16); + else + tick_mask = (1UL << 0); + if ((irq == 14) && (get_softint() & tick_mask)) { + irq = 0; + clr_mask = tick_mask; + } + clear_softint(clr_mask); + } +#else clear_softint(1 << irq); +#endif irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; @@ -952,8 +978,13 @@ extern void smp_tick_init(void); #endif - node = linux_cpus[0].prom_node; - *clock = prom_getint(node, "clock-frequency"); + if (!SPARC64_USE_STICK) { + node = linux_cpus[0].prom_node; + *clock = prom_getint(node, "clock-frequency"); + } else { + node = prom_root_node; + *clock = prom_getint(node, "stick-frequency"); + } timer_tick_offset = *clock / HZ; #ifdef CONFIG_SMP smp_tick_init(); @@ -1003,6 +1034,7 @@ * at the start of an I-cache line, and perform a dummy * read back from %tick_cmpr right after writing to it. -DaveM */ + if (!SPARC64_USE_STICK) { __asm__ __volatile__(" rd %%tick, %%g1 ba,pt %%xcc, 1f @@ -1013,6 +1045,26 @@ : /* no outputs */ : "r" (timer_tick_offset) : "g1"); + } else { + /* Let the user get at STICK too. */ + __asm__ __volatile__(" + sethi %%hi(0x80000000), %%g1 + sllx %%g1, 32, %%g1 + rd %%asr24, %%g2 + andn %%g2, %%g1, %%g2 + wr %%g2, 0, %%asr24" + : /* no outputs */ + : /* no inputs */ + : "g1", "g2"); + + __asm__ __volatile__(" + rd %%asr24, %%g1 + add %%g1, %0, %%g1 + wr %%g1, 0x0, %%asr25" + : /* no outputs */ + : "r" (timer_tick_offset) + : "g1"); + } /* Restore PSTATE_IE. */ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" @@ -1033,12 +1085,17 @@ if (bucket->pil == 12) return goal_cpu; - if(this_is_starfire == 0) { + if (tlb_type == cheetah) { + tid = __cpu_logical_map[goal_cpu] << 26; + tid &= IMAP_AID_SAFARI; + } else if (this_is_starfire == 0) { tid = __cpu_logical_map[goal_cpu] << 26; + tid &= IMAP_TID_UPA; } else { tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26); + tid &= IMAP_TID_UPA; } - upa_writel(IMAP_VALID | (tid & IMAP_TID), imap); + upa_writel(tid | IMAP_VALID, imap); goal_cpu++; if(goal_cpu >= NR_CPUS || @@ -1120,7 +1177,7 @@ stxa %%g0, [%%g0] %0 membar #Sync " : /* no outputs */ - : "i" (ASI_INTR_RECEIVE), "i" (ASI_UDB_INTR_R) + : "i" (ASI_INTR_RECEIVE), "i" (ASI_INTR_R) : "g1", "g2"); } 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.21 2001/01/10 18:22:59 davem Exp $ +/* $Id: pci.c,v 1.23 2001/03/14 04:17:14 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; @@ -88,12 +86,11 @@ } pci_controller_table[] = { { "SUNW,sabre", sabre_init }, { "pci108e,a000", sabre_init }, + { "pci108e,a001", 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_iommu.c linux/arch/sparc64/kernel/pci_iommu.c --- v2.4.2/linux/arch/sparc64/kernel/pci_iommu.c Sat Feb 3 19:51:24 2001 +++ linux/arch/sparc64/kernel/pci_iommu.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: pci_iommu.c,v 1.12 2001/01/11 16:26:45 davem Exp $ +/* $Id: pci_iommu.c,v 1.13 2001/03/14 08:42:38 davem Exp $ * pci_iommu.c: UltraSparc PCI controller IOM/STC support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -213,9 +213,7 @@ first_page += PAGE_SIZE; } - if (iommu->iommu_ctxflush) { - pci_iommu_write(iommu->iommu_ctxflush, ctx); - } else { + { int i; u32 daddr = *dma_addrp; 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 Sun Mar 25 18:14:21 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.13 2001/03/21 00:29:58 davem Exp $ * pci_schizo.c: SCHIZO specific PCI controller support. * * Copyright (C) 2001 David S. Miller (davem@redhat.com) @@ -13,37 +13,244 @@ #include #include #include +#include #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 +262,1445 @@ 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) +{ + return SCHIZO_IMAP_BASE + (ino * 8UL); +} + +static unsigned long schizo_iclr_offset(unsigned long ino) { - /* IMPLEMENT ME */ + return SCHIZO_ICLR_BASE + (ino * 8UL); } -static unsigned int __init schizo_irq_build(struct pci_controller_info *p, +/* 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*/3, /* SCSI */ +/*0x19*/3, /* second SCSI */ +/*0x1a*/0, /* UNKNOWN */ +/*0x1b*/0, /* UNKNOWN */ +/*0x1c*/8, /* Parallel */ +/*0x1d*/5, /* Ethernet */ +/*0x1e*/8, /* Firewire-1394 */ +/*0x1f*/9, /* USB */ +/*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 < 0x18) + 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]; + +static void schizo_clear_other_err_intr(int irq) +{ + struct ino_bucket *bucket = __bucket(irq); + unsigned long iclr = bucket->iclr; + + iclr += (SCHIZO_PBM_B_REGS_OFF - SCHIZO_PBM_A_REGS_OFF); + upa_writel(ICLR_IDLE, iclr); +} + +#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); + + schizo_clear_other_err_intr(irq); +} + +#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"); + + schizo_clear_other_err_intr(irq); +} + +#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); + + schizo_clear_other_err_intr(irq); +} + +#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); + + schizo_clear_other_err_intr(irq); + return; + } + + printk("SCHIZO%d: Safari interrupt, UNMAPPED error, interrogating IOMMUs.\n", + p->index); + schizo_check_iommu_error(p, SAFARI_ERR); + + schizo_clear_other_err_intr(irq); +} + +/* 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_BUNUS (1UL << 63UL) +#define SCHIZO_PCICTRL_ESLCK (1UL << 51UL) +#define SCHIZO_PCICTRL_TTO_ERR (1UL << 38UL) +#define SCHIZO_PCICTRL_RTRY_ERR (1UL << 37UL) +#define SCHIZO_PCICTRL_DTO_ERR (1UL << 36UL) +#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) + +static void __init schizo_register_error_handlers(struct pci_controller_info *p) +{ + struct pci_pbm_info *pbm_a = &p->pbm_A; + struct pci_pbm_info *pbm_b = &p->pbm_B; + unsigned long base = p->controller_regs; + unsigned int irq, portid = p->portid; + struct ino_bucket *bucket; + u64 tmp; + + /* Build IRQs and register handlers. */ + irq = schizo_irq_build(pbm_a, 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(); + } + bucket = __bucket(irq); + tmp = readl(bucket->imap); + upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_UE_INO) + 4)); + + irq = schizo_irq_build(pbm_a, 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(); + } + bucket = __bucket(irq); + tmp = upa_readl(bucket->imap); + upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_CE_INO) + 4)); + + irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_A_INO); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "SCHIZO PCIERR", pbm_a) < 0) { + prom_printf("SCHIZO%d(PBMA): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + bucket = __bucket(irq); + tmp = upa_readl(bucket->imap); + upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); + + irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO); + if (request_irq(irq, schizo_pcierr_intr, + SA_SHIRQ, "SCHIZO PCIERR", pbm_b) < 0) { + prom_printf("SCHIZO%d(PBMB): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + bucket = __bucket(irq); + tmp = upa_readl(bucket->imap); + upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); + + irq = schizo_irq_build(pbm_a, 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(); + } + bucket = __bucket(irq); + tmp = upa_readl(bucket->imap); + upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); + + /* 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. + */ + tmp = schizo_read(base + SCHIZO_PCIA_CTRL); + tmp |= (SCHIZO_PCICTRL_BUNUS | + SCHIZO_PCICTRL_ESLCK | + SCHIZO_PCICTRL_TTO_ERR | + SCHIZO_PCICTRL_RTRY_ERR | + SCHIZO_PCICTRL_DTO_ERR | + 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_BUNUS | + SCHIZO_PCICTRL_ESLCK | + SCHIZO_PCICTRL_TTO_ERR | + SCHIZO_PCICTRL_RTRY_ERR | + SCHIZO_PCICTRL_DTO_ERR | + SCHIZO_PCICTRL_SBH_ERR | + SCHIZO_PCICTRL_SERR | + SCHIZO_PCICTRL_SBH_INT | + SCHIZO_PCICTRL_EEN); + schizo_write(base + SCHIZO_PCIB_CTRL, tmp); + + schizo_write(base + SCHIZO_PBM_A_REGS_OFF + SCHIZO_PCI_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(base + SCHIZO_PBM_B_REGS_OFF + SCHIZO_PCI_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)); + + /* 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 +1708,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,11 +1761,10 @@ 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) - * 3) Unknown... (0x7ffec000000 and 0x7ffee000000 on Excalibur) + * 3) PBM PCI config space */ err = prom_getproperty(node, "reg", (char *)&pr_regs[0], @@ -156,14 +1774,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/process.c linux/arch/sparc64/kernel/process.c --- v2.4.2/linux/arch/sparc64/kernel/process.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/process.c Mon Mar 26 11:01:17 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.114 2001/02/13 01:16:44 davem Exp $ +/* $Id: process.c,v 1.116 2001/03/24 09:36:01 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -416,14 +416,14 @@ unsigned long pgd_cache; if (pgd_none(*pgd0)) { - pmd_t *page = get_pmd_fast(); + pmd_t *page = pmd_alloc_one_fast(NULL, 0); if (!page) - (void) get_pmd_slow(pgd0, 0); - else - pgd_set(pgd0, page); + page = pmd_alloc_one(NULL, 0); + pgd_set(pgd0, page); } pgd_cache = pgd_val(*pgd0) << 11UL; - __asm__ __volatile__("stxa %0, [%1] %2" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : /* no outputs */ : "r" (pgd_cache), "r" (TSB_REG), diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.4.2/linux/arch/sparc64/kernel/ptrace.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/ptrace.c Sun Mar 25 18:14:21 2001 @@ -53,10 +53,10 @@ pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr) { if (current->thread.flags & SPARC_FLAG_32BIT) { - if(put_user(value, (unsigned int *)addr)) + if (put_user(value, (unsigned int *)addr)) return pt_error_return(regs, EFAULT); } else { - if(put_user(value, addr)) + if (put_user(value, addr)) return pt_error_return(regs, EFAULT); } regs->u_regs[UREG_I0] = 0; @@ -137,7 +137,7 @@ s, request, pid, addr, data, addr2); } #endif - if(request == PTRACE_TRACEME) { + if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) { pt_error_return(regs, EPERM); @@ -149,7 +149,7 @@ goto out; } #ifndef ALLOW_INIT_TRACING - if(pid == 1) { + if (pid == 1) { /* Can't dork with init. */ pt_error_return(regs, EPERM); goto out; @@ -157,9 +157,11 @@ #endif read_lock(&tasklist_lock); child = find_task_by_pid(pid); + if (child) + get_task_struct(child); read_unlock(&tasklist_lock); - if(!child) { + if (!child) { pt_error_return(regs, ESRCH); goto out; } @@ -168,32 +170,32 @@ || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { unsigned long flags; - if(child == current) { + if (child == current) { /* Try this under SunOS/Solaris, bwa haha * You'll never be able to kill the process. ;-) */ pt_error_return(regs, EPERM); - goto out; + goto out_tsk; } - if((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->uid) || - (current->uid != child->suid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->uid) || + (current->uid != child->suid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); - goto out; + goto out_tsk; } /* the same process cannot be attached many times */ if (child->ptrace & PT_PTRACED) { pt_error_return(regs, EPERM); - goto out; + goto out_tsk; } child->ptrace |= PT_PTRACED; write_lock_irqsave(&tasklist_lock, flags); - if(child->p_pptr != current) { + if (child->p_pptr != current) { REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); @@ -201,32 +203,32 @@ write_unlock_irqrestore(&tasklist_lock, flags); send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } if (!(child->ptrace & PT_PTRACED)) { pt_error_return(regs, ESRCH); - goto out; + goto out_tsk; } - if(child->state != TASK_STOPPED) { - if(request != PTRACE_KILL) { + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) { pt_error_return(regs, ESRCH); - goto out; + goto out_tsk; } } - if(child->p_pptr != current) { + if (child->p_pptr != current) { pt_error_return(regs, ESRCH); - goto out; + goto out_tsk; } - if(!(child->thread.flags & SPARC_FLAG_32BIT) && - ((request == PTRACE_READDATA64) || - (request == PTRACE_WRITEDATA64) || - (request == PTRACE_READTEXT64) || - (request == PTRACE_WRITETEXT64) || - (request == PTRACE_PEEKTEXT64) || - (request == PTRACE_POKETEXT64) || - (request == PTRACE_PEEKDATA64) || - (request == PTRACE_POKEDATA64))) { + if (!(child->thread.flags & SPARC_FLAG_32BIT) && + ((request == PTRACE_READDATA64) || + (request == PTRACE_WRITEDATA64) || + (request == PTRACE_READTEXT64) || + (request == PTRACE_WRITETEXT64) || + (request == PTRACE_PEEKTEXT64) || + (request == PTRACE_POKETEXT64) || + (request == PTRACE_PEEKDATA64) || + (request == PTRACE_POKEDATA64))) { addr = regs->u_regs[UREG_G2]; addr2 = regs->u_regs[UREG_G3]; request -= 30; /* wheee... */ @@ -278,7 +280,7 @@ if (copied == sizeof(tmp64)) res = 0; } - if(res < 0) + if (res < 0) pt_error_return(regs, -res); else pt_succ_return(regs, res); @@ -295,42 +297,45 @@ __put_user(cregs->tnpc, (&pregs->npc)) || __put_user(cregs->y, (&pregs->y))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } - for(rval = 1; rval < 16; rval++) + for (rval = 1; rval < 16; rval++) if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } pt_succ_return(regs, 0); #ifdef DEBUG_PTRACE printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); #endif - goto out; + goto out_tsk; } case PTRACE_GETREGS64: { struct pt_regs *pregs = (struct pt_regs *) addr; struct pt_regs *cregs = child->thread.kregs; + unsigned long tpc = cregs->tpc; int rval; + if ((child->thread.flags & SPARC_FLAG_32BIT) != 0) + tpc &= 0xffffffff; if (__put_user(cregs->tstate, (&pregs->tstate)) || - __put_user(cregs->tpc, (&pregs->tpc)) || + __put_user(tpc, (&pregs->tpc)) || __put_user(cregs->tnpc, (&pregs->tnpc)) || __put_user(cregs->y, (&pregs->y))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } - for(rval = 1; rval < 16; rval++) + for (rval = 1; rval < 16; rval++) if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } pt_succ_return(regs, 0); #ifdef DEBUG_PTRACE printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); #endif - goto out; + goto out_tsk; } case PTRACE_SETREGS: { @@ -347,23 +352,23 @@ __get_user(npc, (&pregs->npc)) || __get_user(y, (&pregs->y))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } cregs->tstate &= ~(TSTATE_ICC); cregs->tstate |= psr_to_tstate_icc(psr); - if(!((pc | npc) & 3)) { + if (!((pc | npc) & 3)) { cregs->tpc = pc; cregs->tnpc = npc; } cregs->y = y; - for(i = 1; i < 16; i++) { + for (i = 1; i < 16; i++) { if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } } pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_SETREGS64: { @@ -380,24 +385,28 @@ __get_user(tnpc, (&pregs->tnpc)) || __get_user(y, (&pregs->y))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; + } + if ((child->thread.flags & SPARC_FLAG_32BIT) != 0) { + tpc &= 0xffffffff; + tnpc &= 0xffffffff; } tstate &= (TSTATE_ICC | TSTATE_XCC); cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); cregs->tstate |= tstate; - if(!((tpc | tnpc) & 3)) { + if (!((tpc | tnpc) & 3)) { cregs->tpc = tpc; cregs->tnpc = tnpc; } cregs->y = y; - for(i = 1; i < 16; i++) { + for (i = 1; i < 16; i++) { if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } } pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_GETFPREGS: { @@ -422,10 +431,10 @@ __put_user(0, (&fps->extra)) || clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_GETFPREGS64: { @@ -439,10 +448,10 @@ (64 * sizeof(unsigned int))) || __put_user(child->thread.xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_SETFPREGS: { @@ -464,7 +473,7 @@ (32 * sizeof(unsigned int))) || __get_user(fsr, (&fps->fsr))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } child->thread.xfsr[0] &= 0xffffffff00000000UL; child->thread.xfsr[0] |= fsr; @@ -472,7 +481,7 @@ child->thread.gsr[0] = 0; child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_SETFPREGS64: { @@ -486,13 +495,13 @@ (64 * sizeof(unsigned int))) || __get_user(child->thread.xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); - goto out; + goto out_tsk; } if (!(child->thread.fpsaved[0] & FPRS_FEF)) child->thread.gsr[0] = 0; child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_READTEXT: @@ -528,19 +537,24 @@ case PTRACE_CONT: { /* restart after signal. */ if (data > _NSIG) { pt_error_return(regs, EIO); - goto out; + goto out_tsk; } if (addr != 1) { + unsigned long pc_mask = ~0UL; + + if ((child->thread.flags & SPARC_FLAG_32BIT) != 0) + pc_mask = 0xffffffff; + if (addr & 3) { pt_error_return(regs, EINVAL); - goto out; + goto out_tsk; } #ifdef DEBUG_PTRACE printk ("Original: %016lx %016lx\n", child->thread.kregs->tpc, child->thread.kregs->tnpc); printk ("Continuing with %016lx %016lx\n", addr, addr+4); #endif - child->thread.kregs->tpc = addr; - child->thread.kregs->tnpc = addr + 4; + child->thread.kregs->tpc = (addr & pc_mask); + child->thread.kregs->tnpc = ((addr + 4) & pc_mask); } if (request == PTRACE_SYSCALL) @@ -558,7 +572,7 @@ #endif wake_up_process(child); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } /* @@ -569,12 +583,12 @@ case PTRACE_KILL: { if (child->state == TASK_ZOMBIE) { /* already dead */ pt_succ_return(regs, 0); - goto out; + goto out_tsk; } child->exit_code = SIGKILL; wake_up_process(child); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ @@ -582,7 +596,7 @@ if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); - goto out; + goto out_tsk; } child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; @@ -595,29 +609,39 @@ wake_up_process(child); pt_succ_return(regs, 0); - goto out; + goto out_tsk; } /* PTRACE_DUMPCORE unsupported... */ default: pt_error_return(regs, EIO); - goto out; + goto out_tsk; } flush_and_out: { unsigned long va; - for(va = 0; va < (PAGE_SIZE << 1); va += 32) - spitfire_put_dcache_tag(va, 0x0); - if (request == PTRACE_PEEKTEXT || - request == PTRACE_POKETEXT || - request == PTRACE_READTEXT || - request == PTRACE_WRITETEXT) { - for(va = 0; va < (PAGE_SIZE << 1); va += 32) - spitfire_put_icache_tag(va, 0x0); - __asm__ __volatile__("flush %g6"); + + if (tlb_type == cheetah) { + for (va = 0; va < (1 << 16); va += (1 << 5)) + spitfire_put_dcache_tag(va, 0x0); + /* No need to mess with I-cache on Cheetah. */ + } else { + for (va = 0; va < (PAGE_SIZE << 1); va += 32) + spitfire_put_dcache_tag(va, 0x0); + if (request == PTRACE_PEEKTEXT || + request == PTRACE_POKETEXT || + request == PTRACE_READTEXT || + request == PTRACE_WRITETEXT) { + for (va = 0; va < (PAGE_SIZE << 1); va += 32) + spitfire_put_icache_tag(va, 0x0); + __asm__ __volatile__("flush %g6"); + } } } +out_tsk: + if (child) + free_task_struct(child); out: unlock_kernel(); } diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.4.2/linux/arch/sparc64/kernel/rtrap.S Wed Aug 9 13:49:56 2000 +++ linux/arch/sparc64/kernel/rtrap.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.53 2000/08/06 05:20:35 davem Exp $ +/* $Id: rtrap.S,v 1.54 2001/03/08 22:08:51 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -192,7 +192,7 @@ rd %fprs, %g5 wr %g5, FPRS_FEF, %fprs - ldub [%o1 + %o0], %g5 + ldx [%o1 + %o5], %g5 add %g6, AOFF_task_thread + AOFF_thread_xfsr, %o1 membar #StoreLoad | #LoadLoad sll %o0, 8, %o2 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.59 2001/02/13 01:16:44 davem Exp $ +/* $Id: setup.c,v 1.63 2001/03/09 22:04:25 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -43,8 +43,6 @@ #include #endif -#undef PROM_DEBUG_CONSOLE - struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ 0, /* unused */ @@ -166,10 +164,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 +255,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; @@ -285,14 +287,12 @@ /* Exported for mm/init.c:paging_init. */ unsigned long cmdline_memory_size = 0; -#ifdef PROM_DEBUG_CONSOLE static struct console prom_debug_console = { name: "debug", write: prom_console_write, flags: CON_PRINTBUFFER, index: -1, }; -#endif /* XXX Implement this at some point... */ void kernel_enter_debugger(void) @@ -326,6 +326,10 @@ prom_printf("boot_flags_init: Halt!\n"); prom_halt(); break; + case 'p': + /* Use PROM debug console. */ + register_console(&prom_debug_console); + break; default: printk("Unknown boot switch (-%c)\n", c); break; @@ -453,10 +457,6 @@ /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); strcpy(saved_command_line, *cmdline_p); - -#ifdef PROM_DEBUG_CONSOLE - register_console(&prom_debug_console); -#endif printk("ARCH: SUN4U\n"); diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.4.2/linux/arch/sparc64/kernel/signal.c Sat Feb 3 19:51:25 2001 +++ linux/arch/sparc64/kernel/signal.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.55 2001/01/24 21:05:13 davem Exp $ +/* $Id: signal.c,v 1.56 2001/03/21 11:46:20 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -108,6 +108,10 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); } + if ((tp->flags & SPARC_FLAG_32BIT) != 0) { + pc &= 0xffffffff; + npc &= 0xffffffff; + } regs->tpc = pc; regs->tnpc = npc; err |= __get_user(regs->y, &((*grp)[MC_Y])); @@ -190,9 +194,13 @@ grp = &mcp->mc_gregs; /* Skip over the trap instruction, first. */ - regs->tpc = regs->tnpc; - regs->tnpc += 4; - + if ((tp->flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc = (regs->tnpc & 0xffffffff); + regs->tnpc = (regs->tnpc + 4) & 0xffffffff; + } else { + regs->tpc = regs->tnpc; + regs->tnpc += 4; + } err = 0; if (_NSIG_WORDS == 1) err |= __put_user(current->blocked.sig[0], @@ -289,8 +297,13 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - regs->tpc = regs->tnpc; - regs->tnpc += 4; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc = (regs->tnpc & 0xffffffff); + regs->tnpc = (regs->tnpc + 4) & 0xffffffff; + } else { + regs->tpc = regs->tnpc; + regs->tnpc += 4; + } /* Condition codes and return value where set here for sigpause, * and so got used by setup_frame, which again causes sigreturn() @@ -344,8 +357,13 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - regs->tpc = regs->tnpc; - regs->tnpc += 4; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc = (regs->tnpc & 0xffffffff); + regs->tnpc = (regs->tnpc + 4) & 0xffffffff; + } else { + regs->tpc = regs->tnpc; + regs->tnpc += 4; + } /* Condition codes and return value where set here for sigpause, * and so got used by setup_frame, which again causes sigreturn() @@ -407,6 +425,10 @@ err = get_user(tpc, &sf->regs.tpc); err |= __get_user(tnpc, &sf->regs.tnpc); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + tpc &= 0xffffffff; + tnpc &= 0xffffffff; + } err |= ((tpc | tnpc) & 3); /* 2. Restore the state */ @@ -555,7 +577,10 @@ /* 5. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); - + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } /* 4. return to kernel instructions */ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; return; diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.4.2/linux/arch/sparc64/kernel/signal32.c Sat Feb 3 19:51:25 2001 +++ linux/arch/sparc64/kernel/signal32.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.68 2001/01/24 21:05:13 davem Exp $ +/* $Id: signal32.c,v 1.69 2001/03/21 11:46:20 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -155,6 +155,10 @@ regs->tpc = regs->tnpc; regs->tnpc += 4; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } /* Condition codes and return value where set here for sigpause, * and so got used by setup_frame, which again causes sigreturn() @@ -206,6 +210,10 @@ regs->tpc = regs->tnpc; regs->tnpc += 4; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } /* Condition codes and return value where set here for sigpause, * and so got used by setup_frame, which again causes sigreturn() @@ -268,6 +276,10 @@ if ((pc | npc) & 3) goto segv; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + pc &= 0xffffffff; + npc &= 0xffffffff; + } regs->tpc = pc; regs->tnpc = npc; @@ -355,6 +367,10 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + pc &= 0xffffffff; + npc &= 0xffffffff; + } regs->tpc = pc; regs->tnpc = npc; err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp); @@ -398,6 +414,10 @@ if ((pc | npc) & 3) goto segv; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + pc &= 0xffffffff; + npc &= 0xffffffff; + } regs->tpc = pc; regs->tnpc = npc; @@ -489,6 +509,11 @@ #endif unsigned psr; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + pc &= 0xffffffff; + npc &= 0xffffffff; + } + synchronize_user_stack(); save_and_clear_fpu(); @@ -615,6 +640,10 @@ regs->u_regs[UREG_FP] = (unsigned long) sframep; regs->tpc = (unsigned long) sa->sa_handler; regs->tnpc = (regs->tpc + 4); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } return; sigsegv: @@ -678,6 +707,10 @@ } /* 2. Save the current process state */ + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } err = put_user(regs->tpc, &sf->info.si_regs.pc); err |= __put_user(regs->tnpc, &sf->info.si_regs.npc); err |= __put_user(regs->y, &sf->info.si_regs.y); @@ -728,11 +761,15 @@ /* 4. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } /* 5. return to kernel instructions */ - if (ka->ka_restorer) + if (ka->ka_restorer) { regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; - else { + } else { /* Flush instruction space. */ unsigned long address = ((unsigned long)&(sf->insns[0])); pgd_t *pgdp = pgd_offset(current->mm, address); @@ -819,6 +856,10 @@ err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); /* Store registers */ + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } err |= __put_user(regs->tpc, &((*gr) [SVR4_PC])); err |= __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); psr = tstate_to_psr (regs->tstate); @@ -883,6 +924,10 @@ regs->u_regs[UREG_FP] = (unsigned long) sfp; regs->tpc = (unsigned long) sa->sa_handler; regs->tnpc = (regs->tpc + 4); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } #ifdef DEBUG_SIGNALS printk ("Solaris-frame: %x %x\n", (int) regs->tpc, (int) regs->tnpc); @@ -940,6 +985,10 @@ err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); /* Store registers */ + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } err |= __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); err |= __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]); #if 1 @@ -1037,6 +1086,10 @@ spin_unlock_irq(¤t->sigmask_lock); regs->tpc = pc; regs->tnpc = npc | 1; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } err |= __get_user(regs->y, &((*gr) [SVR4_Y])); err |= __get_user(psr, &((*gr) [SVR4_PSR])); regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); @@ -1095,6 +1148,10 @@ } /* 2. Save the current process state */ + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } err = put_user(regs->tpc, &sf->regs.pc); err |= __put_user(regs->tnpc, &sf->regs.npc); err |= __put_user(regs->y, &sf->regs.y); @@ -1150,6 +1207,10 @@ /* 4. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } /* 5. return to kernel instructions */ if (ka->ka_restorer) diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.4.2/linux/arch/sparc64/kernel/smp.c Sat Feb 3 19:51:25 2001 +++ linux/arch/sparc64/kernel/smp.c Sun Mar 25 18:14:21 2001 @@ -65,7 +65,7 @@ strcpy(buf, "State:\n"); for (i = 0; i < NR_CPUS; i++) - if(cpu_present_map & (1UL << i)) + if (cpu_present_map & (1UL << i)) len += sprintf(buf + len, "CPU%d:\t\tonline\n", i); return len; @@ -76,7 +76,7 @@ int len = 0, i; for (i = 0; i < NR_CPUS; i++) - if(cpu_present_map & (1UL << i)) + if (cpu_present_map & (1UL << i)) len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", i, cpu_data[i].udelay_val / (500000/HZ), @@ -99,7 +99,7 @@ cpu_data[id].pgd_cache = NULL; cpu_data[id].idle_volume = 1; - for(i = 0; i < 16; i++) + for (i = 0; i < 16; i++) cpu_data[id].irq_worklists[i] = 0; } @@ -153,6 +153,19 @@ : /* no inputs */ : "g1", "g2"); + if (SPARC64_USE_STICK) { + /* Let the user get at STICK too. */ + __asm__ __volatile__(" + sethi %%hi(0x80000000), %%g1 + sllx %%g1, 32, %%g1 + rd %%asr24, %%g2 + andn %%g2, %%g1, %%g2 + wr %%g2, 0, %%asr24" + : /* no outputs */ + : /* no inputs */ + : "g1", "g2"); + } + /* Restore PSTATE_IE. */ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : /* no outputs */ @@ -177,7 +190,7 @@ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - while(!smp_processors_ready) + while (!smp_processors_ready) membar("#LoadLoad"); } @@ -222,14 +235,14 @@ smp_tune_scheduling(); init_idle(); - if(linux_num_cpus == 1) + if (linux_num_cpus == 1) return; - for(i = 0; i < NR_CPUS; i++) { - if(i == boot_cpu_id) + for (i = 0; i < NR_CPUS; i++) { + if (i == boot_cpu_id) continue; - if(cpu_present_map & (1UL << i)) { + if (cpu_present_map & (1UL << i)) { unsigned long entry = (unsigned long)(&sparc64_cpu_startup); unsigned long cookie = (unsigned long)(&cpu_new_task); struct task_struct *p; @@ -256,12 +269,12 @@ cpu_new_task = p; prom_startcpu(linux_cpus[no].prom_node, entry, cookie); - for(timeout = 0; timeout < 5000000; timeout++) { - if(callin_flag) + for (timeout = 0; timeout < 5000000; timeout++) { + if (callin_flag) break; udelay(100); } - if(callin_flag) { + if (callin_flag) { __cpu_number_map[i] = cpucount; __cpu_logical_map[cpucount] = i; prom_cpu_nodes[i] = linux_cpus[no].prom_node; @@ -272,20 +285,20 @@ prom_printf("FAILED\n"); } } - if(!callin_flag) { + if (!callin_flag) { cpu_present_map &= ~(1UL << i); __cpu_number_map[i] = -1; } } cpu_new_task = NULL; - if(cpucount == 0) { + if (cpucount == 0) { printk("Error: only one processor found.\n"); cpu_present_map = (1UL << smp_processor_id()); } else { unsigned long bogosum = 0; - for(i = 0; i < NR_CPUS; i++) { - if(cpu_present_map & (1UL << i)) + for (i = 0; i < NR_CPUS; i++) { + if (cpu_present_map & (1UL << i)) bogosum += cpu_data[i].udelay_val; } printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", @@ -299,9 +312,7 @@ membar("#StoreStore | #StoreLoad"); } -/* #define XCALL_DEBUG */ - -static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu) +static void spitfire_xcall_helper(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu) { u64 result, target; int stuck, tmp; @@ -314,10 +325,6 @@ } target = (cpu << 14) | 0x70; -#ifdef XCALL_DEBUG - printk("CPU[%d]: xcall(data[%016lx:%016lx:%016lx],tgt[%016lx])\n", - smp_processor_id(), data0, data1, data2, target); -#endif again: /* Ok, this is the real Spitfire Errata #54. * One must read back from a UDB internal register @@ -340,7 +347,7 @@ ldxa [%%g1] 0x7f, %%g0 membar #Sync" : "=r" (tmp) - : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W), + : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_INTR_W), "r" (data0), "r" (data1), "r" (data2), "r" (target), "r" (0x10), "0" (tmp) : "g1"); @@ -350,46 +357,155 @@ __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (result) : "i" (ASI_INTR_DISPATCH_STAT)); - if(result == 0) { + if (result == 0) { __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); return; } stuck -= 1; - if(stuck == 0) + if (stuck == 0) break; - } while(result & 0x1); + } while (result & 0x1); __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); - if(stuck == 0) { -#ifdef XCALL_DEBUG + if (stuck == 0) { printk("CPU[%d]: mondo stuckage result[%016lx]\n", smp_processor_id(), result); -#endif } else { -#ifdef XCALL_DEBUG - printk("CPU[%d]: Penguin %d NACK's master.\n", smp_processor_id(), cpu); -#endif udelay(2); goto again; } } -void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2) +static __inline__ void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, unsigned long mask) { - if(smp_processors_ready) { - unsigned long mask = (cpu_present_map & ~(1UL< 32 +#error Fixup cheetah_xcall_deliver Dave... +#endif +static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, unsigned long mask) +{ + u64 pstate; + int nack_busy_id; + + if (!mask) + return; + + __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); + +retry: + __asm__ __volatile__("wrpr %0, %1, %%pstate\n\t" + : : "r" (pstate), "i" (PSTATE_IE)); + + /* Setup the dispatch data registers. */ + __asm__ __volatile__("stxa %0, [%3] %6\n\t" + "membar #Sync\n\t" + "stxa %1, [%4] %6\n\t" + "membar #Sync\n\t" + "stxa %2, [%5] %6\n\t" + "membar #Sync\n\t" + : /* no outputs */ + : "r" (data0), "r" (data1), "r" (data2), + "r" (0x40), "r" (0x50), "r" (0x60), + "i" (ASI_INTR_W)); + + nack_busy_id = 0; + { int i, ncpus = smp_num_cpus - 1; - __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); - for(i = 0; i < NR_CPUS; i++) { - if(mask & (1UL << i)) { - xcall_deliver(data0, data1, data2, pstate, i); + for (i = 0; (i < NR_CPUS) && ncpus; i++) { + if (mask & (1UL << i)) { + u64 target = (i << 14) | 0x70; + + target |= (nack_busy_id++ << 24); + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync\n\t" + : /* no outputs */ + : "r" (target), "i" (ASI_INTR_W)); ncpus--; } - if (!ncpus) break; } + } + + /* Now, poll for completion. */ + { + u64 dispatch_stat; + long stuck; + + stuck = 100000 * nack_busy_id; + do { + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (dispatch_stat) + : "i" (ASI_INTR_DISPATCH_STAT)); + if (dispatch_stat == 0UL) { + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : : "r" (pstate)); + return; + } + if (!--stuck) + break; + } while (dispatch_stat & 0x5555555555555555UL); + + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : : "r" (pstate)); + + if ((stuck & ~(0x5555555555555555UL)) == 0) { + /* Busy bits will not clear, continue instead + * of freezing up on this cpu. + */ + printk("CPU[%d]: mondo stuckage result[%016lx]\n", + smp_processor_id(), dispatch_stat); + } else { + int i, this_busy_nack = 0; + + /* Delay some random time with interrupts enabled + * to prevent deadlock. + */ + udelay(2 * nack_busy_id); + + /* Clear out the mask bits for cpus which did not + * NACK us. + */ + for (i = 0; i < NR_CPUS; i++) { + if (mask & (1UL << i)) { + if ((dispatch_stat & (0x2 << this_busy_nack)) == 0) + mask &= ~(1UL << i); + this_busy_nack += 2; + } + } + + goto retry; + } + } +} + +void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2) +{ + if (smp_processors_ready) { + unsigned long mask = (cpu_present_map & ~(1UL<tpc, regs->u_regs[UREG_RETPC]); @@ -740,6 +871,7 @@ * that %tick is not prone to this bug, but I am not * taking any chances. */ + if (!SPARC64_USE_STICK) { __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" "ba,pt %%xcc, 1f\n\t" " add %0, %2, %0\n\t" @@ -750,6 +882,14 @@ "mov %1, %1" : "=&r" (compare), "=r" (tick) : "r" (current_tick_offset)); + } else { + __asm__ __volatile__("rd %%asr25, %0\n\t" + "add %0, %2, %0\n\t" + "wr %0, 0x0, %%asr25\n\t" + "rd %%asr24, %1\n\t" + : "=&r" (compare), "=r" (tick) + : "r" (current_tick_offset)); + } /* Restore PSTATE_IE. */ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" @@ -782,6 +922,7 @@ * at the start of an I-cache line, and perform a dummy * read back from %tick_cmpr right after writing to it. -DaveM */ + if (!SPARC64_USE_STICK) { __asm__ __volatile__(" rd %%tick, %%g1 ba,pt %%xcc, 1f @@ -792,6 +933,15 @@ : /* no outputs */ : "r" (current_tick_offset) : "g1"); + } else { + __asm__ __volatile__(" + rd %%asr24, %%g1 + add %%g1, %0, %%g1 + wr %%g1, 0x0, %%asr25" + : /* no outputs */ + : "r" (current_tick_offset) + : "g1"); + } /* Restore PSTATE_IE. */ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" @@ -806,9 +956,9 @@ boot_cpu_id = hard_smp_processor_id(); current_tick_offset = timer_tick_offset; cpu_present_map = 0; - for(i = 0; i < linux_num_cpus; i++) + for (i = 0; i < linux_num_cpus; i++) cpu_present_map |= (1UL << linux_cpus[i].mid); - for(i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { __cpu_number_map[i] = -1; __cpu_logical_map[i] = -1; } @@ -827,11 +977,11 @@ size = PAGE_ALIGN(size); found = size; base = (unsigned long) page_address(p); - while(found != 0) { + while (found != 0) { /* Failure. */ - if(p >= (mem_map + max_mapnr)) + if (p >= (mem_map + max_mapnr)) return 0UL; - if(PageReserved(p)) { + if (PageReserved(p)) { found = size; base = (unsigned long) page_address(p); } else { @@ -924,12 +1074,12 @@ unsigned long flags; int i; - if((!multiplier) || (timer_tick_offset / multiplier) < 1000) + if ((!multiplier) || (timer_tick_offset / multiplier) < 1000) return -EINVAL; save_and_cli(flags); - for(i = 0; i < NR_CPUS; i++) { - if(cpu_present_map & (1UL << i)) + for (i = 0; i < NR_CPUS; i++) { + if (cpu_present_map & (1UL << i)) prof_multiplier(i) = multiplier; } current_tick_offset = (timer_tick_offset / multiplier); diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.4.2/linux/arch/sparc64/kernel/sparc64_ksyms.c Sat Feb 3 19:51:25 2001 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.100 2001/01/11 15:07:09 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.102 2001/03/24 09:36:01 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -179,6 +179,8 @@ EXPORT_SYMBOL(__flushw_user); +EXPORT_SYMBOL(tlb_type); + EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(__flush_dcache_page); @@ -232,8 +234,7 @@ /* Should really be in linux/kernel/ksyms.c */ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); -EXPORT_SYMBOL(get_pmd_slow); -EXPORT_SYMBOL(get_pte_slow); +EXPORT_SYMBOL(pte_alloc_one); #ifndef CONFIG_SMP EXPORT_SYMBOL(pgt_quicklists); #endif diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.4.2/linux/arch/sparc64/kernel/sys_sparc.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/sys_sparc.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.48 2001/02/13 01:16:44 davem Exp $ +/* $Id: sys_sparc.c,v 1.50 2001/03/24 09:36:10 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -243,9 +243,9 @@ if (flags & MAP_SHARED) current->thread.flags |= SPARC_FLAG_MMAPSHARED; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); retval = do_mmap(file, addr, len, prot, flags, off); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); @@ -263,9 +263,9 @@ if (len > -PAGE_OFFSET || (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET)) return -EINVAL; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); ret = do_munmap(current->mm, addr, len); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return ret; } @@ -285,7 +285,7 @@ goto out; if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET) goto out; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); vma = find_vma(current->mm, addr); if (vma && (vma->vm_flags & VM_SHARED)) current->thread.flags |= SPARC_FLAG_MMAPSHARED; @@ -305,7 +305,7 @@ ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); out: return ret; } @@ -335,6 +335,10 @@ { siginfo_t info; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } #ifdef DEBUG_SPARC_BREAKPOINT printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc); #endif @@ -384,6 +388,10 @@ regs->tpc = regs->tnpc; regs->tnpc += 4; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } if(++count <= 5) { printk ("For Solaris binary emulation you need solaris module loaded\n"); show_regs (regs); @@ -400,6 +408,10 @@ regs->tpc = regs->tnpc; regs->tnpc += 4; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } if(++count <= 20) printk ("SunOS binary emulation not compiled in\n"); force_sig(SIGSEGV, current); diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.4.2/linux/arch/sparc64/kernel/sys_sparc32.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/sys_sparc32.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.173 2001/02/13 01:16:44 davem Exp $ +/* $Id: sys_sparc32.c,v 1.174 2001/03/24 09:36:10 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -4133,7 +4133,7 @@ goto out; if (addr > 0xf0000000UL - old_len) goto out; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); vma = find_vma(current->mm, addr); if (vma && (vma->vm_flags & VM_SHARED)) current->thread.flags |= SPARC_FLAG_MMAPSHARED; @@ -4152,7 +4152,7 @@ ret = do_mremap(addr, old_len, new_len, flags, new_addr); out_sem: current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); out: return ret; } diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.4.2/linux/arch/sparc64/kernel/sys_sunos32.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/sys_sunos32.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.57 2001/02/13 01:16:44 davem Exp $ +/* $Id: sys_sunos32.c,v 1.59 2001/03/24 09:36:11 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -100,12 +100,12 @@ flags &= ~_MAP_NEW; flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); retval = do_mmap(file, (unsigned long) addr, (unsigned long) len, (unsigned long) prot, (unsigned long) flags, (unsigned long) off); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if(!ret_type) retval = ((retval < 0xf0000000) ? 0 : retval); out_putf: @@ -126,7 +126,7 @@ unsigned long rlim; unsigned long newbrk, oldbrk, brk = (unsigned long) baddr; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); if (brk < current->mm->end_code) goto out; newbrk = PAGE_ALIGN(brk); @@ -170,7 +170,7 @@ do_brk(oldbrk, newbrk-oldbrk); retval = 0; out: - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return retval; } @@ -456,6 +456,10 @@ static int cnt; regs = current->thread.kregs; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } info.si_signo = SIGSYS; info.si_errno = 0; info.si_code = __SI_FAULT|0x100; diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c --- v2.4.2/linux/arch/sparc64/kernel/time.c Sat Feb 3 19:51:25 2001 +++ linux/arch/sparc64/kernel/time.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.33 2001/01/11 15:07:09 davem Exp $ +/* $Id: time.c,v 1.36 2001/03/15 08:51:24 anton Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include @@ -35,7 +37,11 @@ extern rwlock_t xtime_lock; spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED; +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; unsigned long mstk48t02_regs = 0UL; +#ifdef CONFIG_PCI +unsigned long ds1287_regs = 0UL; +#endif static unsigned long mstk48t08_regs = 0UL; static unsigned long mstk48t59_regs = 0UL; @@ -77,6 +83,7 @@ extern int rwlock_impl_begin, rwlock_impl_end; extern int atomic_impl_begin, atomic_impl_end; extern int __memcpy_begin, __memcpy_end; + extern int __bzero_begin, __bzero_end; extern int __bitops_begin, __bitops_end; if ((pc >= (unsigned long) &atomic_impl_begin && @@ -85,6 +92,8 @@ pc < (unsigned long) &rwlock_impl_end) || (pc >= (unsigned long) &__memcpy_begin && pc < (unsigned long) &__memcpy_end) || + (pc >= (unsigned long) &__bzero_begin && + pc < (unsigned long) &__bzero_end) || (pc >= (unsigned long) &__bitops_begin && pc < (unsigned long) &__bitops_end)) pc = o7; @@ -135,6 +144,7 @@ * that %tick is not prone to this bug, but I am not * taking any chances. */ + if (!SPARC64_USE_STICK) { __asm__ __volatile__(" rd %%tick_cmpr, %0 ba,pt %%xcc, 1f @@ -146,6 +156,15 @@ mov %1, %1" : "=&r" (timer_tick_compare), "=r" (ticks) : "r" (timer_tick_offset)); + } else { + __asm__ __volatile__(" + rd %%asr25, %0 + add %0, %2, %0 + wr %0, 0, %%asr25 + rd %%asr24, %1" + : "=&r" (timer_tick_compare), "=r" (ticks) + : "r" (timer_tick_offset)); + } /* Restore PSTATE_IE. */ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" @@ -168,11 +187,19 @@ /* * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR. */ + if (!SPARC64_USE_STICK) { __asm__ __volatile__(" rd %%tick_cmpr, %0 add %0, %1, %0" : "=&r" (timer_tick_compare) : "r" (timer_tick_offset)); + } else { + __asm__ __volatile__(" + rd %%asr25, %0 + add %0, %1, %0" + : "=&r" (timer_tick_compare) + : "r" (timer_tick_offset)); + } timer_check_rtc(); @@ -282,41 +309,95 @@ return (data1 == data2); /* Was the write blocked? */ } +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) +#endif /* Probe for the real time clock chip. */ static void __init set_system_time(void) { unsigned int year, mon, day, hour, min, sec; unsigned long mregs = mstk48t02_regs; +#ifdef CONFIG_PCI + unsigned long dregs = ds1287_regs; +#else + unsigned long dregs = 0UL; +#endif u8 tmp; do_get_fast_time = do_gettimeofday; - if(!mregs) { + if (!mregs && !dregs) { prom_printf("Something wrong, clock regs not mapped yet.\n"); prom_halt(); } - spin_lock_irq(&mostek_lock); + if (mregs) { + spin_lock_irq(&mostek_lock); + + /* Traditional Mostek chip. */ + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); + + sec = MSTK_REG_SEC(mregs); + min = MSTK_REG_MIN(mregs); + hour = MSTK_REG_HOUR(mregs); + day = MSTK_REG_DOM(mregs); + mon = MSTK_REG_MONTH(mregs); + year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); + } else { + int i; + + /* Dallas 12887 RTC chip. */ + + /* Stolen from arch/i386/kernel/time.c, see there for + * credits and descriptive comments. + */ + for (i = 0; i < 1000000; i++) { + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + udelay(10); + } + for (i = 0; i < 1000000; i++) { + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + udelay(10); + } + do { + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + if ((year += 1900) < 1970) + year += 100; + } - tmp = mostek_read(mregs + MOSTEK_CREG); - tmp |= MSTK_CREG_READ; - mostek_write(mregs + MOSTEK_CREG, tmp); - - sec = MSTK_REG_SEC(mregs); - min = MSTK_REG_MIN(mregs); - hour = MSTK_REG_HOUR(mregs); - day = MSTK_REG_DOM(mregs); - mon = MSTK_REG_MONTH(mregs); - year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); xtime.tv_sec = mktime(year, mon, day, hour, min, sec); xtime.tv_usec = 0; - tmp = mostek_read(mregs + MOSTEK_CREG); - tmp &= ~MSTK_CREG_READ; - mostek_write(mregs + MOSTEK_CREG, tmp); + if (mregs) { + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); - spin_unlock_irq(&mostek_lock); + spin_unlock_irq(&mostek_lock); + } } void __init clock_probe(void) @@ -358,21 +439,22 @@ busnd = sbus_root->prom_node; } - if(busnd == -1) { + if (busnd == -1) { prom_printf("clock_probe: problem, cannot find bus to search.\n"); prom_halt(); } node = prom_getchild(busnd); - while(1) { + while (1) { if (!node) model[0] = 0; else prom_getstring(node, "model", model, sizeof(model)); - if(strcmp(model, "mk48t02") && - strcmp(model, "mk48t08") && - strcmp(model, "mk48t59")) { + if (strcmp(model, "mk48t02") && + strcmp(model, "mk48t08") && + strcmp(model, "mk48t59") && + strcmp(model, "ds1287")) { if (node) node = prom_getsibling(node); #ifdef CONFIG_PCI @@ -384,7 +466,7 @@ } } #endif - if(node == 0) { + if (node == 0) { prom_printf("clock_probe: Cannot find timer chip\n"); prom_halt(); } @@ -415,8 +497,12 @@ prom_halt(); } - mstk48t59_regs = edev->resource[0].start; - mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; + if (!strcmp(model, "ds1287")) { + ds1287_regs = edev->resource[0].start; + } else { + mstk48t59_regs = edev->resource[0].start; + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; + } break; } #endif @@ -456,27 +542,21 @@ break; } - /* Report a low battery voltage condition. */ - if (has_low_battery()) - prom_printf("NVRAM: Low battery voltage!\n"); - - /* Kick start the clock if it is completely stopped. */ - if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) - kick_start_clock(); + if (mstk48t02_regs != 0UL) { + /* Report a low battery voltage condition. */ + if (has_low_battery()) + prom_printf("NVRAM: Low battery voltage!\n"); + + /* Kick start the clock if it is completely stopped. */ + if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) + kick_start_clock(); + } set_system_time(); __restore_flags(flags); } -#ifndef BCD_TO_BIN -#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) -#endif - -#ifndef BIN_TO_BCD -#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) -#endif - extern void init_timers(void (*func)(int, void *, struct pt_regs *), unsigned long *); @@ -497,6 +577,7 @@ { unsigned long ticks; + if (!SPARC64_USE_STICK) { __asm__ __volatile__(" rd %%tick, %%g1 add %1, %%g1, %0 @@ -505,6 +586,14 @@ : "=r" (ticks) : "r" (timer_tick_offset), "r" (timer_tick_compare) : "g1", "g2"); + } else { + __asm__ __volatile__("rd %%asr24, %%g1\n\t" + "add %1, %%g1, %0\n\t" + "sub %0, %2, %0\n\t" + : "=&r" (ticks) + : "r" (timer_tick_offset), "r" (timer_tick_compare) + : "g1"); + } return (ticks * timer_ticks_per_usec_quotient) >> 32UL; } @@ -533,8 +622,13 @@ static int set_rtc_mmss(unsigned long nowtime) { - int real_seconds, real_minutes, mostek_minutes; - unsigned long regs = mstk48t02_regs; + int real_seconds, real_minutes, chip_minutes; + unsigned long mregs = mstk48t02_regs; +#ifdef CONFIG_PCI + unsigned long dregs = ds1287_regs; +#else + unsigned long dregs = 0UL; +#endif unsigned long flags; u8 tmp; @@ -542,52 +636,96 @@ * Not having a register set can lead to trouble. * Also starfire doesnt have a tod clock. */ - if (!regs) + if (!mregs && !dregs) return -1; - spin_lock_irqsave(&mostek_lock, flags); - - /* Read the current RTC minutes. */ - tmp = mostek_read(regs + MOSTEK_CREG); - tmp |= MSTK_CREG_READ; - mostek_write(regs + MOSTEK_CREG, tmp); - - mostek_minutes = MSTK_REG_MIN(regs); + if (mregs) { + spin_lock_irqsave(&mostek_lock, flags); - tmp = mostek_read(regs + MOSTEK_CREG); - tmp &= ~MSTK_CREG_READ; - mostek_write(regs + MOSTEK_CREG, tmp); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; + /* Read the current RTC minutes. */ + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); + + chip_minutes = MSTK_REG_MIN(mregs); + + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - chip_minutes) < 30) { + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(mregs + MOSTEK_CREG, tmp); + + MSTK_SET_REG_SEC(mregs,real_seconds); + MSTK_SET_REG_MIN(mregs,real_minutes); + + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(mregs + MOSTEK_CREG, tmp); - if (abs(real_minutes - mostek_minutes) < 30) { - tmp = mostek_read(regs + MOSTEK_CREG); - tmp |= MSTK_CREG_WRITE; - mostek_write(regs + MOSTEK_CREG, tmp); + spin_unlock_irqrestore(&mostek_lock, flags); - MSTK_SET_REG_SEC(regs,real_seconds); - MSTK_SET_REG_MIN(regs,real_minutes); + return 0; + } else { + spin_unlock_irqrestore(&mostek_lock, flags); - tmp = mostek_read(regs + MOSTEK_CREG); - tmp &= ~MSTK_CREG_WRITE; - mostek_write(regs + MOSTEK_CREG, tmp); + return -1; + } + } else { + int retval = 0; + unsigned char save_control, save_freq_select; - spin_unlock_irqrestore(&mostek_lock, flags); + /* Stolen from arch/i386/kernel/time.c, see there for + * credits and descriptive comments. + */ + spin_lock_irqsave(&rtc_lock, flags); + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + chip_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(chip_minutes); + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) + real_minutes += 30; + real_minutes %= 60; + + if (abs(real_minutes - chip_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + chip_minutes, real_minutes); + retval = -1; + } - return 0; - } else { - spin_unlock_irqrestore(&mostek_lock, flags); + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock_irqrestore(&rtc_lock, flags); - return -1; + return retval; } } 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.12 1999/12/15 15:45:12 davem Exp $ +/* $Id: trampoline.S,v 1.19 2001/03/22 09:54:26 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,246 @@ 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_IFPOE | 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 + or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 + ldxa [%g0] ASI_DCU_CONTROL_REG, %g3 + or %g5, %g3, %g5 + stxa %g5, [%g0] ASI_DCU_CONTROL_REG + membar #Sync + + /* Disable STICK_INT interrupts. */ + sethi %hi(0x80000000), %g5 + sllx %g5, 32, %g5 + wr %g5, %asr25 - 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 -#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) + 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 + +#define VPTE_BASE_SPITFIRE 0xfffffffe00000000 +#if 1 +#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE +#else +#define VPTE_BASE_CHEETAH 0xffe0000000000000 #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 + + 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 +#undef VPTE_BASE_SPITFIRE +#undef VPTE_BASE_CHEETAH /* 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/kernel/traps.c linux/arch/sparc64/kernel/traps.c --- v2.4.2/linux/arch/sparc64/kernel/traps.c Wed Feb 21 18:20:15 2001 +++ linux/arch/sparc64/kernel/traps.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.70 2001/02/09 05:46:44 davem Exp $ +/* $Id: traps.c,v 1.73 2001/03/22 07:26:03 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -26,6 +26,7 @@ #include #include #include +#include #include #ifdef CONFIG_KMOD #include @@ -263,6 +264,10 @@ } if (regs->tstate & TSTATE_PRIV) die_if_kernel ("Kernel bad trap", regs); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLTRP; @@ -291,6 +296,10 @@ #endif die_if_kernel("Iax", regs); } + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = SEGV_MAPERR; @@ -342,32 +351,41 @@ #ifdef CONFIG_PCI /* This is really pathetic... */ -/* #define DEBUG_PCI_POKES */ extern volatile int pci_poke_in_progress; extern volatile int pci_poke_faulted; #endif /* When access exceptions happen, we must do this. */ -static __inline__ void clean_and_reenable_l1_caches(void) +static void clean_and_reenable_l1_caches(void) { unsigned long va; - /* Clean 'em. */ - for(va = 0; va < (PAGE_SIZE << 1); va += 32) { - spitfire_put_icache_tag(va, 0x0); - spitfire_put_dcache_tag(va, 0x0); - } - - /* Re-enable. */ - __asm__ __volatile__("flush %%g6\n\t" - "membar #Sync\n\t" - "stxa %0, [%%g0] %1\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC | - LSU_CONTROL_IM | LSU_CONTROL_DM), - "i" (ASI_LSU_CONTROL) - : "memory"); + if (tlb_type == spitfire) { + /* Clean 'em. */ + for (va = 0; va < (PAGE_SIZE << 1); va += 32) { + spitfire_put_icache_tag(va, 0x0); + spitfire_put_dcache_tag(va, 0x0); + } + + /* Re-enable in LSU. */ + __asm__ __volatile__("flush %%g6\n\t" + "membar #Sync\n\t" + "stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC | + LSU_CONTROL_IM | LSU_CONTROL_DM), + "i" (ASI_LSU_CONTROL) + : "memory"); + } else if (tlb_type == cheetah) { + /* Flush D-cache */ + for (va = 0; va < (1 << 16); va += (1 << 5)) { + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (va), "i" (ASI_DCACHE_TAG)); + } + } } void do_iae(struct pt_regs *regs) @@ -387,20 +405,16 @@ void do_dae(struct pt_regs *regs) { #ifdef CONFIG_PCI - if(pci_poke_in_progress) { -#ifdef DEBUG_PCI_POKES - prom_printf(" (POKE tpc[%016lx] tnpc[%016lx] ", - regs->tpc, regs->tnpc); -#endif + if (pci_poke_in_progress) { + clean_and_reenable_l1_caches(); + pci_poke_faulted = 1; - regs->tnpc = regs->tpc + 4; + /* Why the fuck did they have to change this? */ + if (tlb_type == cheetah) + regs->tpc += 4; -#ifdef DEBUG_PCI_POKES - prom_printf("PCI) "); - /* prom_halt(); */ -#endif - clean_and_reenable_l1_caches(); + regs->tnpc = regs->tpc + 4; return; } #endif @@ -534,6 +548,10 @@ unsigned long fsr = current->thread.xfsr[0]; siginfo_t info; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } info.si_signo = SIGFPE; info.si_errno = 0; info.si_addr = (void *)regs->tpc; @@ -589,6 +607,10 @@ if(regs->tstate & TSTATE_PRIV) die_if_kernel("Penguin overflow trap from kernel mode", regs); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } info.si_signo = SIGEMT; info.si_errno = 0; info.si_code = EMT_TAGOVF; @@ -601,6 +623,10 @@ { siginfo_t info; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = FPE_INTDIV; @@ -700,8 +726,13 @@ (rw->ins[6] + STACK_BIAS); } instruction_dump ((unsigned int *) regs->tpc); - } else + } else { + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } user_instruction_dump ((unsigned int *) regs->tpc); + } #ifdef CONFIG_SMP smp_report_regs(); #endif @@ -765,6 +796,10 @@ { siginfo_t info; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_PRVOPC; @@ -907,6 +942,10 @@ regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate); regs->tpc = regs->tnpc; regs->tnpc += 4; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } } void trap_init(void) diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S --- v2.4.2/linux/arch/sparc64/kernel/ttable.S Mon May 22 09:50:54 2000 +++ linux/arch/sparc64/kernel/ttable.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.31 2000/05/09 17:40:14 davem Exp $ +/* $Id: ttable.S,v 1.32 2001/03/23 07:56:30 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -22,7 +22,7 @@ tl0_resv01e: BTRAP(0x1e) BTRAP(0x1f) tl0_fpdis: TRAP_NOSAVE(do_fpdis) tl0_fpieee: TRAP_SAVEFPU(do_fpieee) -tl0_fpother: TRAP_SAVEFPU(do_fpother) +tl0_fpother: TRAP_NOSAVE(do_fpother_check_fitos) tl0_tof: TRAP(do_tof) tl0_cwin: CLEAN_WINDOW tl0_div0: TRAP(do_div0) diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/unaligned.c linux/arch/sparc64/kernel/unaligned.c --- v2.4.2/linux/arch/sparc64/kernel/unaligned.c Wed May 3 01:47:57 2000 +++ linux/arch/sparc64/kernel/unaligned.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.20 2000/04/29 08:05:21 anton Exp $ +/* $Id: unaligned.c,v 1.21 2001/03/21 11:46:20 davem Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -334,6 +334,10 @@ { regs->tpc = regs->tnpc; regs->tnpc += 4; + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } } static inline int floating_point_load_or_store_p(unsigned int insn) diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/lib/U3copy_in_user.S linux/arch/sparc64/lib/U3copy_in_user.S --- v2.4.2/linux/arch/sparc64/lib/U3copy_in_user.S Thu Nov 9 15:57:41 2000 +++ linux/arch/sparc64/lib/U3copy_in_user.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: U3copy_in_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $ +/* $Id: U3copy_in_user.S,v 1.4 2001/03/21 05:58:47 davem Exp $ * U3memcpy.S: UltraSparc-III optimized copy within userspace. * * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com) @@ -231,25 +231,25 @@ .align 64 U3copy_in_user_begin: - prefetch [%o1 + 0x000], #one_read ! MS Group1 - prefetch [%o1 + 0x040], #one_read ! MS Group2 + prefetcha [%o1 + 0x000] %asi, #one_read ! MS Group1 + prefetcha [%o1 + 0x040] %asi, #one_read ! MS Group2 andn %o2, (0x40 - 1), %o4 ! A0 - prefetch [%o1 + 0x080], #one_read ! MS Group3 + prefetcha [%o1 + 0x080] %asi, #one_read ! MS Group3 cmp %o4, 0x140 ! A0 - prefetch [%o1 + 0x0c0], #one_read ! MS Group4 + prefetcha [%o1 + 0x0c0] %asi, #one_read ! MS Group4 EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8) bge,a,pt %icc, 1f ! BR - prefetch [%o1 + 0x100], #one_read ! MS Group6 + prefetcha [%o1 + 0x100] %asi, #one_read ! MS Group6 1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9) cmp %o4, 0x180 ! A1 bge,a,pt %icc, 1f ! BR - prefetch [%o1 + 0x140], #one_read ! MS Group7 + prefetcha [%o1 + 0x140] %asi, #one_read ! MS Group7 1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10) cmp %o4, 0x1c0 ! A1 bge,a,pt %icc, 1f ! BR - prefetch [%o1 + 0x180], #one_read ! MS Group8 + prefetcha [%o1 + 0x180] %asi, #one_read ! MS Group8 1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12) EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12) faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13) @@ -305,7 +305,7 @@ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19) EXBLK1(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19) - prefetch [%o1 + 0x180], #one_read ! MS + prefetcha [%o1 + 0x180] %asi, #one_read ! MS faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20) subcc %o4, 0x40, %o4 ! A0 add %o1, 0x40, %o1 ! A1 diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/lib/VISbzero.S linux/arch/sparc64/lib/VISbzero.S --- v2.4.2/linux/arch/sparc64/lib/VISbzero.S Thu May 27 09:55:21 1999 +++ linux/arch/sparc64/lib/VISbzero.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: VISbzero.S,v 1.10 1999/05/25 16:52:56 jj Exp $ +/* $Id: VISbzero.S,v 1.11 2001/03/15 08:51:24 anton Exp $ * VISbzero.S: High speed clear operations utilizing the UltraSparc * Visual Instruction Set. * @@ -83,6 +83,8 @@ .text .align 32 #ifdef __KERNEL__ + .globl __bzero_begin +__bzero_begin: .globl __bzero, __bzero_noasi __bzero_noasi: rd %asi, %g5 @@ -272,3 +274,5 @@ ba,pt %xcc, VISbzerofixup_ret0 sub %o1, %g2, %o0 #endif + .globl __bzero_end +__bzero_end: diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/lib/VISsave.S linux/arch/sparc64/lib/VISsave.S --- v2.4.2/linux/arch/sparc64/lib/VISsave.S Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/lib/VISsave.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: VISsave.S,v 1.4 1999/07/30 09:35:37 davem Exp $ +/* $Id: VISsave.S,v 1.5 2001/03/08 22:08:51 davem Exp $ * VISsave.S: Code for saving FPU register state for * VIS routines. One should not call this directly, * but use macros provided in . @@ -37,14 +37,15 @@ clr %g1 ba,pt %xcc, 3f - stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr] + stx %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr] 2: add %g6, %g1, %g3 cmp %o5, FPRS_DU be,pn %icc, 6f sll %g1, 3, %g1 stb %o5, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved] rd %gsr, %g2 - stb %g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr] + add %g6, %g1, %g3 + stx %g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr] add %g6, %g1, %g2 stx %fsr, [%g2 + AOFF_task_thread + AOFF_thread_xfsr] @@ -106,7 +107,8 @@ stb %g2, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved] rd %gsr, %g2 - stb %g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr] + add %g6, %g1, %g3 + stx %g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr] add %g6, %g1, %g2 stx %fsr, [%g2 + AOFF_task_thread + AOFF_thread_xfsr] sll %g1, 5, %g1 diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S --- v2.4.2/linux/arch/sparc64/lib/blockops.S Tue Jul 18 12:29:47 2000 +++ linux/arch/sparc64/lib/blockops.S Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.27 2000/07/14 01:12:49 davem Exp $ +/* $Id: blockops.S,v 1.30 2001/03/22 13:10:10 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996, 1998, 1999, 2000 David S. Miller (davem@redhat.com) @@ -83,6 +83,8 @@ or %g2, %g3, %g2 add %o0, %o3, %o0 add %o0, %o1, %o1 +#define FIX_INSN_1 0x96102068 /* mov (13 << 3), %o3 */ +cheetah_patch_1: mov TLBTEMP_ENT1, %o3 rdpr %pstate, %g3 wrpr %g3, PSTATE_IE, %pstate @@ -96,16 +98,14 @@ /* Spitfire Errata #32 workaround */ mov 0x8, %o4 stxa %g0, [%o4] ASI_DMMU - sethi %hi(empty_zero_page), %o4 - flush %o4 + membar #Sync ldxa [%o3] ASI_DTLB_TAG_READ, %o4 /* Spitfire Errata #32 workaround */ mov 0x8, %o5 stxa %g0, [%o5] ASI_DMMU - sethi %hi(empty_zero_page), %o5 - flush %o5 + membar #Sync ldxa [%o3] ASI_DTLB_DATA_ACCESS, %o5 stxa %o0, [%o2] ASI_DMMU @@ -116,16 +116,14 @@ /* Spitfire Errata #32 workaround */ mov 0x8, %g5 stxa %g0, [%g5] ASI_DMMU - sethi %hi(empty_zero_page), %g5 - flush %g5 + membar #Sync ldxa [%o3] ASI_DTLB_TAG_READ, %g5 /* Spitfire Errata #32 workaround */ mov 0x8, %g7 stxa %g0, [%g7] ASI_DMMU - sethi %hi(empty_zero_page), %g7 - flush %g7 + membar #Sync ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 stxa %o1, [%o2] ASI_DMMU @@ -136,6 +134,107 @@ bne,pn %xcc, copy_page_using_blkcommit nop + rdpr %ver, %g3 + sllx %g3, 16, %g3 + srlx %g3, 32 + 16, %g3 + cmp %g3, 0x14 + bne,pt %icc, spitfire_copy_user_page + nop + +cheetah_copy_user_page: + mov 121, %o2 ! A0 Group + prefetch [%o1 + 0x000], #one_read ! MS + prefetch [%o1 + 0x040], #one_read ! MS Group + prefetch [%o1 + 0x080], #one_read ! MS Group + prefetch [%o1 + 0x0c0], #one_read ! MS Group + ldd [%o1 + 0x000], %f0 ! MS Group + prefetch [%o1 + 0x100], #one_read ! MS Group + ldd [%o1 + 0x008], %f2 ! AX + prefetch [%o1 + 0x140], #one_read ! MS Group + ldd [%o1 + 0x010], %f4 ! AX + prefetch [%o1 + 0x180], #one_read ! MS Group + fmovd %f0, %f32 ! FGA Group + ldd [%o1 + 0x018], %f6 ! AX + fmovd %f2, %f34 ! FGA Group + ldd [%o1 + 0x020], %f8 ! MS + fmovd %f4, %f36 ! FGA Group + ldd [%o1 + 0x028], %f10 ! AX + membar #StoreStore ! MS + fmovd %f6, %f38 ! FGA Group + ldd [%o1 + 0x030], %f12 ! MS + fmovd %f8, %f40 ! FGA Group + ldd [%o1 + 0x038], %f14 ! AX + fmovd %f10, %f42 ! FGA Group + ldd [%o1 + 0x040], %f16 ! MS +1: ldd [%o1 + 0x048], %f2 ! AX (Group) + fmovd %f12, %f44 ! FGA + ldd [%o1 + 0x050], %f4 ! MS + fmovd %f14, %f46 ! FGA Group + stda %f32, [%o0] ASI_BLK_P ! MS + ldd [%o1 + 0x058], %f6 ! AX + fmovd %f16, %f32 ! FGA Group (8-cycle stall) + ldd [%o1 + 0x060], %f8 ! MS + fmovd %f2, %f34 ! FGA Group + ldd [%o1 + 0x068], %f10 ! AX + fmovd %f4, %f36 ! FGA Group + ldd [%o1 + 0x070], %f12 ! MS + fmovd %f6, %f38 ! FGA Group + ldd [%o1 + 0x078], %f14 ! AX + fmovd %f8, %f40 ! FGA Group + ldd [%o1 + 0x080], %f16 ! AX + prefetch [%o1 + 0x180], #one_read ! MS + fmovd %f10, %f42 ! FGA Group + subcc %o2, 1, %o2 ! A0 + add %o0, 0x40, %o0 ! A1 + bne,pt %xcc, 1b ! BR + add %o1, 0x40, %o1 ! A0 Group + + mov 5, %o2 ! A0 Group +1: ldd [%o1 + 0x048], %f2 ! AX + fmovd %f12, %f44 ! FGA + ldd [%o1 + 0x050], %f4 ! MS + fmovd %f14, %f46 ! FGA Group + stda %f32, [%o0] ASI_BLK_P ! MS + ldd [%o1 + 0x058], %f6 ! AX + fmovd %f16, %f32 ! FGA Group (8-cycle stall) + ldd [%o1 + 0x060], %f8 ! MS + fmovd %f2, %f34 ! FGA Group + ldd [%o1 + 0x068], %f10 ! AX + fmovd %f4, %f36 ! FGA Group + ldd [%o1 + 0x070], %f12 ! MS + fmovd %f6, %f38 ! FGA Group + ldd [%o1 + 0x078], %f14 ! AX + fmovd %f8, %f40 ! FGA Group + ldd [%o1 + 0x080], %f16 ! MS + fmovd %f10, %f42 ! FGA Group + subcc %o2, 1, %o2 ! A0 + add %o0, 0x40, %o0 ! A1 + bne,pt %xcc, 1b ! BR + add %o1, 0x40, %o1 ! A0 Group + + ldd [%o1 + 0x048], %f2 ! AX + fmovd %f12, %f44 ! FGA + ldd [%o1 + 0x050], %f4 ! MS + fmovd %f14, %f46 ! FGA Group + stda %f32, [%o0] ASI_BLK_P ! MS + ldd [%o1 + 0x058], %f6 ! AX + fmovd %f16, %f32 ! FGA Group (8-cycle stall) + ldd [%o1 + 0x060], %f8 ! MS + fmovd %f2, %f34 ! FGA Group + ldd [%o1 + 0x068], %f10 ! AX + fmovd %f4, %f36 ! FGA Group + ldd [%o1 + 0x070], %f12 ! MS + fmovd %f6, %f38 ! FGA Group + add %o0, 0x40, %o0 ! A0 + ldd [%o1 + 0x078], %f14 ! AX + fmovd %f8, %f40 ! FGA Group + fmovd %f10, %f42 ! FGA Group + fmovd %f12, %f44 ! FGA Group + fmovd %f14, %f46 ! FGA Group + stda %f32, [%o0] ASI_BLK_P ! MS + ba,a,pt %xcc, copy_user_page_continue + +spitfire_copy_user_page: ldda [%o1] ASI_BLK_P, %f0 add %o1, 0x40, %o1 ldda [%o1] ASI_BLK_P, %f16 @@ -237,6 +336,8 @@ or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3 or %g1, %g3, %g1 add %o0, %o3, %o0 +#define FIX_INSN_2 0x96102070 /* mov (14 << 3), %o3 */ +cheetah_patch_2: mov TLBTEMP_ENT2, %o3 rdpr %pstate, %g3 wrpr %g3, PSTATE_IE, %pstate @@ -244,16 +345,14 @@ /* Spitfire Errata #32 workaround */ mov 0x8, %g5 stxa %g0, [%g5] ASI_DMMU - sethi %hi(empty_zero_page), %g5 - flush %g5 + membar #Sync ldxa [%o3] ASI_DTLB_TAG_READ, %g5 /* Spitfire Errata #32 workaround */ mov 0x8, %g7 stxa %g0, [%g7] ASI_DMMU - sethi %hi(empty_zero_page), %g7 - flush %g7 + membar #Sync ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 stxa %o0, [%o2] ASI_DMMU @@ -299,3 +398,24 @@ membar #Sync jmpl %o7 + 0x8, %g0 wrpr %g3, 0x0, %pstate + + /* We will write cheetah optimized versions later. */ + .globl cheetah_patch_pgcopyops +cheetah_patch_pgcopyops: + sethi %hi(FIX_INSN_1), %g1 + or %g1, %lo(FIX_INSN_1), %g1 + sethi %hi(cheetah_patch_1), %g2 + or %g2, %lo(cheetah_patch_1), %g2 + stw %g1, [%g2] + flush %g2 + sethi %hi(FIX_INSN_2), %g1 + or %g1, %lo(FIX_INSN_2), %g1 + sethi %hi(cheetah_patch_2), %g2 + or %g2, %lo(cheetah_patch_2), %g2 + stw %g1, [%g2] + flush %g2 + retl + nop + +#undef FIX_INSN1 +#undef FIX_INSN2 diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.4.2/linux/arch/sparc64/mm/fault.c Sun Sep 17 10:01:50 2000 +++ linux/arch/sparc64/mm/fault.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.51 2000/09/14 06:22:32 anton Exp $ +/* $Id: fault.c,v 1.54 2001/03/24 09:36:11 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -142,7 +142,7 @@ { unsigned long g2; unsigned char asi = ASI_P; - + if (!insn) { if (regs->tstate & TSTATE_PRIV) { if (!regs->tpc || (regs->tpc & 0x3)) @@ -234,7 +234,12 @@ if (in_interrupt() || !mm) goto handle_kernel_fault; - down(&mm->mmap_sem); + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { + regs->tpc &= 0xffffffff; + address &= 0xffffffff; + } + + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; @@ -286,7 +291,12 @@ if (fault_code & FAULT_CODE_WRITE) { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; - if ((vma->vm_flags & VM_EXEC) != 0 && + + /* Spitfire has an icache which does not snoop + * processor stores. Later processors do... + */ + if (tlb_type == spitfire && + (vma->vm_flags & VM_EXEC) != 0 && vma->vm_file != NULL) current->thread.use_blkcommit = 1; } else { @@ -308,7 +318,7 @@ goto out_of_memory; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); goto fault_done; /* @@ -316,7 +326,7 @@ * Fix it, but check if it's kernel or user first.. */ bad_area: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); handle_kernel_fault: do_kernel_fault(regs, si_code, fault_code, insn, address); @@ -328,14 +338,14 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", current->comm); if (!(regs->tstate & TSTATE_PRIV)) do_exit(SIGKILL); goto handle_kernel_fault; do_sigbus: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/mm/generic.c linux/arch/sparc64/mm/generic.c --- v2.4.2/linux/arch/sparc64/mm/generic.c Wed Aug 9 13:49:56 2000 +++ linux/arch/sparc64/mm/generic.c Mon Mar 26 15:42:57 2001 @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.14 2000/08/09 00:00:15 davem Exp $ +/* $Id: generic.c,v 1.16 2001/03/25 04:40:05 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -104,12 +104,10 @@ end = PGDIR_SIZE; offset -= address; do { - pte_t * pte = pte_alloc(pmd, address); + pte_t * pte = pte_alloc(current->mm, pmd, address); if (!pte) return -ENOMEM; - spin_lock(¤t->mm->page_table_lock); io_remap_pte_range(pte, address, end - address, address + offset, prot, space); - spin_unlock(¤t->mm->page_table_lock); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end); @@ -122,13 +120,16 @@ pgd_t * dir; unsigned long beg = from; unsigned long end = from + size; + struct mm_struct *mm = current->mm; prot = __pgprot(pg_iobits); offset -= from; - dir = pgd_offset(current->mm, from); - flush_cache_range(current->mm, beg, end); + dir = pgd_offset(mm, from); + flush_cache_range(mm, beg, end); + + spin_lock(&mm->page_table_lock); while (from < end) { - pmd_t *pmd = pmd_alloc(dir, from); + pmd_t *pmd = pmd_alloc(current->mm, dir, from); error = -ENOMEM; if (!pmd) break; @@ -138,6 +139,8 @@ from = (from + PGDIR_SIZE) & PGDIR_MASK; dir++; } + spin_unlock(&mm->page_table_lock); + flush_tlb_range(current->mm, beg, end); return error; } 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 Mon Mar 26 15:30:06 2001 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.162 2001/02/13 01:16:44 davem Exp $ +/* $Id: init.c,v 1.172 2001/03/24 09:36:01 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]) - free_pte_slow(get_pte_fast(0)), freed++; - if(pte_quicklist[1]) - free_pte_slow(get_pte_fast(1)), freed++; - } while(pgtable_cache_size > low); + if (pte_quicklist[0]) + free_pte_slow(pte_alloc_one_fast(NULL, 0)), freed++; + if (pte_quicklist[1]) + free_pte_slow(pte_alloc_one_fast(NULL, 1 << (PAGE_SHIFT + 10))), freed++; + } while (pgtable_cache_size > low); } #ifndef CONFIG_SMP if (pgd_cache_size > high / 4) { @@ -107,7 +109,8 @@ if (VALID_PAGE(page) && page->mapping && test_bit(PG_dcache_dirty, &page->flags)) { - __flush_dcache_page(page->virtual, 1); + __flush_dcache_page(page->virtual, + (tlb_type == spitfire)); clear_bit(PG_dcache_dirty, &page->flags); } __update_mmu_cache(vma, address, pte); @@ -118,10 +121,13 @@ void flush_icache_range(unsigned long start, unsigned long end) { - unsigned long kaddr; + /* Cheetah has coherent I-cache. */ + if (tlb_type == spitfire) { + unsigned long kaddr; - for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) - __flush_icache_page(__get_phys(kaddr)); + for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE) + __flush_icache_page(__get_phys(kaddr)); + } } /* @@ -163,13 +169,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 +236,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 +259,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 +282,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_litlb_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 +345,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 +363,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_litlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR)), (unsigned long) &empty_zero_page, prom_get_mmu_ihandle()); @@ -320,8 +374,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 +426,43 @@ 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\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + spitfire_put_dtlb_data(i, 0x0UL); + } + } + } else if (tlb_type == cheetah) { + for (i = 0; i < 512; 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\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + cheetah_put_dtlb_data(i, 0x0UL); + } } + } else { + /* Implement me :-) */ + BUG(); } } @@ -401,7 +472,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,42 +497,53 @@ __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" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : : "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); - membar("#Sync"); + 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); } - 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)); - membar("#Sync"); - spitfire_put_itlb_data(prom_itlb[i].tlb_ent, - prom_itlb[i].tlb_data); - membar("#Sync"); + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" + : : "r" (prom_itlb[i].tlb_tag), + "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); + 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); } } } 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" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); - membar("#Sync"); + 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); } if (prom_itlb[i].tlb_ent != -1) { - __asm__ __volatile__("stxa %%g0, [%0] %1" - : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL); - membar("#Sync"); + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : : "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); + 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); } } } @@ -490,25 +572,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 +588,36 @@ : "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; + 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\n\t" + "membar #Sync" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + spitfire_put_dtlb_data(i, 0x0UL); + + 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 +626,84 @@ : "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"); + 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\n\t" + "membar #Sync" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + spitfire_put_itlb_data(i, 0x0UL); + + itlb_seen++; + if (itlb_seen > 15) + break; + } + } + } 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\n\t" + "membar #Sync" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + cheetah_put_ldtlb_data(i, 0x0UL); + + dtlb_seen++; + if (dtlb_seen > 15) + break; + } + } + + for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) { + unsigned long data; - itlb_seen++; - if(itlb_seen > 7) - break; + 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\n\t" + "membar #Sync" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + cheetah_put_litlb_data(i, 0x0UL); + + itlb_seen++; + if (itlb_seen > 15) + break; + } } + } else { + /* Implement me :-) */ + BUG(); } if (save_p) prom_ditlb_set = 1; @@ -581,25 +714,32 @@ { 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" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : : "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); - membar("#Sync"); + 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); } 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)); - membar("#Sync"); - spitfire_put_itlb_data(prom_itlb[i].tlb_ent, - prom_itlb[i].tlb_data); - membar("#Sync"); + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" + : : "r" (prom_itlb[i].tlb_tag), + "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); + 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); } } } @@ -607,22 +747,38 @@ void __flush_dcache_range(unsigned long start, unsigned long end) { unsigned long va; - int n = 0; - for (va = start; va < end; va += 32) { - spitfire_put_dcache_tag(va & 0x3fe0, 0x0); - if (++n >= 512) - break; + if (tlb_type == spitfire) { + int n = 0; + + for (va = start; va < end; va += 32) { + spitfire_put_dcache_tag(va & 0x3fe0, 0x0); + if (++n >= 512) + break; + } + } else { + start = __pa(start); + end = __pa(end); + for (va = start; va < end; va += 32) + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (va), + "i" (ASI_DCACHE_INVALIDATE)); } } void __flush_cache_all(void) { - unsigned long va; - - flushw_all(); - for(va = 0; va < (PAGE_SIZE << 1); va += 32) - spitfire_put_icache_tag(va, 0x0); + /* Cheetah should be fine here too. */ + if (tlb_type == spitfire) { + unsigned long va; + + flushw_all(); + for (va = 0; va < (PAGE_SIZE << 1); va += 32) + spitfire_put_icache_tag(va, 0x0); + __asm__ __volatile__("flush %g6"); + } } /* If not locked, zap it. */ @@ -636,38 +792,41 @@ "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 (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)); - 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 (!(spitfire_get_dtlb_data(i) & _PAGE_L)) { + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + spitfire_put_dtlb_data(i, 0x0UL); + } - /* 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_itlb_data(i) & _PAGE_L)) { + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + spitfire_put_itlb_data(i, 0x0UL); + } } + } else if (tlb_type == cheetah) { + cheetah_flush_dtlb_all(); + cheetah_flush_itlb_all(); } __asm__ __volatile__("wrpr %0, 0, %%pstate" : : "r" (pstate)); @@ -709,7 +868,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; @@ -731,23 +890,6 @@ struct pgtable_cache_struct pgt_quicklists; #endif -/* For PMDs we don't care about the color, writes are - * only done via Dcache which is write-thru, so non-Dcache - * reads will always see correct data. - */ -pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) -{ - pmd_t *pmd; - - pmd = (pmd_t *) __get_free_page(GFP_KERNEL); - if(pmd) { - memset(pmd, 0, PAGE_SIZE); - pgd_set(pgd, pmd); - return pmd + offset; - } - return NULL; -} - /* OK, we have to color these pages because during DTLB * protection faults we set the dirty bit via a non-Dcache * enabled mapping in the VPTE area. The kernel can end @@ -762,9 +904,10 @@ * 3) Process faults back in the page, the old pre-dirtied copy * is provided and here is the corruption. */ -pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset, unsigned long color) +pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) { struct page *page = alloc_pages(GFP_KERNEL, 1); + unsigned long color = ((address >> (PAGE_SHIFT + 10)) & 1UL); if (page) { unsigned long *to_free; @@ -788,8 +931,7 @@ pte_quicklist[color ^ 0x1] = to_free; pgtable_cache_size++; - pmd_set(pmd, pte); - return pte + offset; + return pte; } return NULL; } @@ -798,31 +940,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 +1147,35 @@ 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 + 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; + __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 @@ -982,9 +1185,24 @@ 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" ((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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.48 2000/11/06 06:59:04 davem Exp $ +/* $Id: ultra.S,v 1.54 2001/03/22 07:26:04 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com) @@ -10,6 +10,22 @@ #include #include + /* Basically, all this madness has to do with the + * fact that Cheetah does not support IMMU flushes + * out of the secondary context. Someone needs to + * throw a south lake birthday party for the folks + * in Microelectronics who refused to fix this shit. + */ +#define BRANCH_IF_CHEETAH(tmp1, tmp2, label) \ + rdpr %ver, %tmp1; \ + sethi %hi(0x003e0014), %tmp2; \ + srlx %tmp1, 32, %tmp1; \ + or %tmp2, %lo(0x003e0014), %tmp2; \ + cmp %tmp1, %tmp2; \ + be,pn %icc, label; \ + nop; \ + nop; + /* This file is meant to be read efficiently by the CPU, not humans. * Staraj sie tego nikomu nie pierdolnac... */ @@ -17,37 +33,77 @@ .align 32 .globl __flush_tlb_page, __flush_tlb_mm, __flush_tlb_range __flush_tlb_page: /* %o0=(ctx & 0x3ff), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */ -/*IC1*/ ldxa [%o2] ASI_DMMU, %g2 +/*IC1*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_page) +__spitfire_flush_tlb_page: +/*IC2*/ ldxa [%o2] ASI_DMMU, %g2 cmp %g2, %o0 - bne,pn %icc, __flush_tlb_page_slow + bne,pn %icc, __spitfire_flush_tlb_page_slow or %o1, 0x10, %g3 stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP retl flush %g6 +__cheetah_flush_tlb_page: +/*IC3*/ rdpr %pstate, %g5 + andn %g5, PSTATE_IE, %g2 + wrpr %g2, 0x0, %pstate + wrpr %g0, 1, %tl + mov PRIMARY_CONTEXT, %o2 + ldxa [%o2] ASI_DMMU, %g2 + stxa %o0, [%o2] ASI_DMMU + stxa %g0, [%o1] ASI_DMMU_DEMAP +/*IC4*/ stxa %g0, [%o1] ASI_IMMU_DEMAP + stxa %g2, [%o2] ASI_DMMU + flush %g6 + wrpr %g0, 0, %tl + retl + wrpr %g5, 0x0, %pstate + nop + nop __flush_tlb_mm: /* %o0=(ctx & 0x3ff), %o1=SECONDARY_CONTEXT */ -/*IC2*/ ldxa [%o1] ASI_DMMU, %g2 +/*IC5*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_mm) +__spitfire_flush_tlb_mm: +/*IC6*/ ldxa [%o1] ASI_DMMU, %g2 cmp %g2, %o0 - bne,pn %icc, __flush_tlb_mm_slow + bne,pn %icc, __spitfire_flush_tlb_mm_slow mov 0x50, %g3 stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP retl flush %g6 +__cheetah_flush_tlb_mm: +/*IC7*/ rdpr %pstate, %g5 + andn %g5, PSTATE_IE, %g2 + wrpr %g2, 0x0, %pstate + wrpr %g0, 1, %tl + mov PRIMARY_CONTEXT, %o2 + mov 0x40, %g3 + ldxa [%o2] ASI_DMMU, %g2 + stxa %o0, [%o2] ASI_DMMU +/*IC8*/ stxa %g0, [%g3] ASI_DMMU_DEMAP + stxa %g0, [%g3] ASI_IMMU_DEMAP + stxa %g2, [%o2] ASI_DMMU + flush %g6 + wrpr %g0, 0, %tl + retl + wrpr %g5, 0x0, %pstate + nop __flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT, * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start) */ +/*IC9*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_range) +__spitfire_flush_tlb_range: #define TLB_MAGIC 207 /* Students, do you know how I calculated this? -DaveM */ -/*IC3*/ cmp %o5, %o4 +/*IC10*/cmp %o5, %o4 bleu,pt %xcc, __flush_tlb_page srlx %o5, 13, %g5 cmp %g5, TLB_MAGIC - bgeu,pn %icc, __flush_tlb_range_constant_time + bgeu,pn %icc, __spitfire_flush_tlb_range_constant_time or %o1, 0x10, %g5 ldxa [%o2] ASI_DMMU, %g2 cmp %g2, %o0 -__flush_tlb_range_page_by_page: -/*IC4*/ bne,pn %icc, __flush_tlb_range_pbp_slow +__spitfire_flush_tlb_range_page_by_page: +/*IC11*/bne,pn %icc, __spitfire_flush_tlb_range_pbp_slow sub %o5, %o4, %o5 1: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP @@ -55,10 +111,11 @@ sub %o5, %o4, %o5 retl flush %g6 -__flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ -/*IC5*/ rdpr %pstate, %g1 +__spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ +/*IC12*/rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate mov TLB_TAG_ACCESS, %g3 + /* XXX Spitfire dependency... */ mov (62 << 3), %g2 /* Spitfire Errata #32 workaround. */ @@ -70,7 +127,7 @@ and %o4, 0x3ff, %o5 cmp %o5, %o0 bne,pt %icc, 2f -/*IC6*/ andn %o4, 0x3ff, %o4 +/*IC13*/ andn %o4, 0x3ff, %o4 cmp %o4, %o1 blu,pt %xcc, 2f cmp %o4, %o3 @@ -78,7 +135,7 @@ 2: ldxa [%g2] ASI_DTLB_TAG_READ, %o4 and %o4, 0x3ff, %o5 cmp %o5, %o0 -/*IC7*/ andn %o4, 0x3ff, %o4 +/*IC14*/andn %o4, 0x3ff, %o4 bne,pt %icc, 3f cmp %o4, %o1 blu,pt %xcc, 3f @@ -86,7 +143,7 @@ blu,pn %xcc, 5f nop 3: brnz,pt %g2, 1b -/*IC8*/ sub %g2, (1 << 3), %g2 +/*IC15*/ sub %g2, (1 << 3), %g2 retl wrpr %g1, 0x0, %pstate 4: stxa %g0, [%g3] ASI_IMMU @@ -102,7 +159,7 @@ nop 5: stxa %g0, [%g3] ASI_DMMU -/*IC9*/ stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS +/*IC16*/stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS flush %g6 /* Spitfire Errata #32 workaround. */ @@ -114,45 +171,70 @@ nop .align 32 -__flush_tlb_mm_slow: -/*IC10*/rdpr %pstate, %g1 +__cheetah_flush_tlb_range: + cmp %o5, %o4 + bleu,pt %xcc, __cheetah_flush_tlb_page + nop +/*IC17*/rdpr %pstate, %g5 + andn %g5, PSTATE_IE, %g2 + wrpr %g2, 0x0, %pstate + wrpr %g0, 1, %tl + mov PRIMARY_CONTEXT, %o2 + sub %o5, %o4, %o5 + ldxa [%o2] ASI_DMMU, %g2 + stxa %o0, [%o2] ASI_DMMU + +/*IC18*/ +1: stxa %g0, [%o1 + %o5] ASI_DMMU_DEMAP + stxa %g0, [%o1 + %o5] ASI_IMMU_DEMAP + membar #Sync + brnz,pt %o5, 1b + sub %o5, %o4, %o5 + + stxa %g2, [%o2] ASI_DMMU + flush %g6 + wrpr %g0, 0, %tl + retl +/*IC19*/ wrpr %g5, 0x0, %pstate + +__spitfire_flush_tlb_mm_slow: + rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o1] ASI_DMMU stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP flush %g6 stxa %g2, [%o1] ASI_DMMU - flush %g6 -/*IC11*/retl +/*IC18*/flush %g6 + retl wrpr %g1, 0, %pstate - .align 32 -__flush_tlb_page_slow: -/*IC12*/rdpr %pstate, %g1 +__spitfire_flush_tlb_page_slow: + rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o2] ASI_DMMU stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP - flush %g6 +/*IC20*/flush %g6 stxa %g2, [%o2] ASI_DMMU flush %g6 -/*IC13*/retl + retl wrpr %g1, 0, %pstate - .align 32 -__flush_tlb_range_pbp_slow: -/*IC13*/rdpr %pstate, %g1 +__spitfire_flush_tlb_range_pbp_slow: + rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o2] ASI_DMMU +/*IC21*/ 2: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP brnz,pt %o5, 2b sub %o5, %o4, %o5 flush %g6 -/*IC14*/stxa %g2, [%o2] ASI_DMMU + stxa %g2, [%o2] ASI_DMMU flush %g6 retl - wrpr %g1, 0x0, %pstate +/*IC22*/ wrpr %g1, 0x0, %pstate .align 32 .globl __flush_icache_page @@ -210,6 +292,27 @@ .globl __flush_dcache_page __flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */ sub %o0, %g4, %o0 + + rdpr %ver, %g1 + sethi %hi(0x003e0014), %g2 + srlx %g1, 32, %g1 + or %g2, %lo(0x003e0014), %g2 + cmp %g1, %g2 + bne,pt %icc, flush_dcpage_spitfire + nop + +flush_dcpage_cheetah: + sethi %hi(8192), %o4 +1: subcc %o4, (1 << 5), %o4 + stxa %g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE + membar #Sync + bne,pt %icc, 1b + nop + /* I-cache flush never needed on Cheetah, see callers. */ + retl + nop + +flush_dcpage_spitfire: clr %o4 srlx %o0, 11, %o0 sethi %hi(1 << 14), %o2 @@ -317,18 +420,18 @@ .align 32 .globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range xcall_flush_tlb_page: - mov SECONDARY_CONTEXT, %g2 - or %g1, 0x10, %g4 + mov PRIMARY_CONTEXT, %g2 ldxa [%g2] ASI_DMMU, %g3 stxa %g5, [%g2] ASI_DMMU - stxa %g0, [%g4] ASI_DMMU_DEMAP - stxa %g0, [%g4] ASI_IMMU_DEMAP + stxa %g0, [%g1] ASI_DMMU_DEMAP + stxa %g0, [%g1] ASI_IMMU_DEMAP stxa %g3, [%g2] ASI_DMMU retry + nop xcall_flush_tlb_mm: - mov SECONDARY_CONTEXT, %g2 - mov 0x50, %g4 + mov PRIMARY_CONTEXT, %g2 + mov 0x40, %g4 ldxa [%g2] ASI_DMMU, %g3 stxa %g5, [%g2] ASI_DMMU stxa %g0, [%g4] ASI_DMMU_DEMAP @@ -343,20 +446,21 @@ andn %g7, %g2, %g7 sub %g7, %g1, %g3 add %g2, 1, %g2 - orcc %g1, 0x10, %g1 srlx %g3, 13, %g4 - cmp %g4, 96 + bgu,pn %icc, xcall_flush_tlb_mm - mov SECONDARY_CONTEXT, %g4 + mov PRIMARY_CONTEXT, %g4 ldxa [%g4] ASI_DMMU, %g7 sub %g3, %g2, %g3 stxa %g5, [%g4] ASI_DMMU nop nop + nop 1: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP stxa %g0, [%g1 + %g3] ASI_IMMU_DEMAP + membar #Sync brnz,pt %g3, 1b sub %g3, %g2, %g3 stxa %g7, [%g4] ASI_DMMU @@ -433,7 +537,8 @@ /* These two are not performance critical... */ .globl xcall_flush_tlb_all xcall_flush_tlb_all: - + BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_tlb_all) +__spitfire_xcall_flush_tlb_all: /* Spitfire Errata #32 workaround. */ sethi %hi(errata32_hwbug), %g4 stx %g0, [%g4 + %lo(errata32_hwbug)] @@ -475,17 +580,33 @@ flush %g6 retry +__cheetah_xcall_flush_tlb_all: + mov 0x80, %g2 + stxa %g0, [%g2] ASI_DMMU_DEMAP + stxa %g0, [%g2] ASI_IMMU_DEMAP + retry + .globl xcall_flush_cache_all xcall_flush_cache_all: + BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_cache_all) +__spitfire_xcall_flush_cache_all: sethi %hi(16383), %g2 or %g2, %lo(16383), %g2 clr %g3 1: stxa %g0, [%g3] ASI_IC_TAG + membar #Sync add %g3, 32, %g3 cmp %g3, %g2 bleu,pt %xcc, 1b nop flush %g6 + retry + + /* Cheetah's caches are fully coherent in the sense that + * caches are flushed here. We need to verify this and + * really just not even send out the xcall at the top level. + */ +__cheetah_xcall_flush_cache_all: retry .globl xcall_call_function diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c --- v2.4.2/linux/arch/sparc64/solaris/misc.c Fri Dec 29 14:07:21 2000 +++ linux/arch/sparc64/solaris/misc.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.31 2000/12/14 22:57:25 davem Exp $ +/* $Id: misc.c,v 1.32 2001/03/24 09:36:11 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -92,12 +92,12 @@ ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, (unsigned long) addr, (unsigned long) len, (unsigned long) prot, (unsigned long) flags, off); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if(!ret_type) retval = ((retval < 0xf0000000) ? 0 : retval); 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/atm/Makefile linux/drivers/atm/Makefile --- v2.4.2/linux/drivers/atm/Makefile Sat Feb 3 19:51:26 2001 +++ linux/drivers/atm/Makefile Mon Mar 26 15:36:30 2001 @@ -50,6 +50,9 @@ EXTRA_CFLAGS=-g +list-multi := fore_200e.o +fore_200e-objs := fore200e.o $(FORE200E_FW_OBJS) + include $(TOPDIR)/Rules.make @@ -82,9 +85,8 @@ objcopy -Iihex $< -Obinary $@.gz gzip -df $@.gz -# module build -fore_200e.o: fore200e.o $(FORE200E_FW_OBJS) - $(LD) -r -o $@ $< $(FORE200E_FW_OBJS) +fore_200e.o: $(fore_200e-objs) + $(LD) -r -o $@ $(fore_200e-objs) # firmware dependency stuff taken from drivers/sound/Makefile FORE200E_FW_UP_TO_DATE := diff -u --recursive --new-file v2.4.2/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c --- v2.4.2/linux/drivers/atm/nicstar.c Wed Feb 21 18:20:17 2001 +++ linux/drivers/atm/nicstar.c Sun Mar 25 18:24:31 2001 @@ -207,12 +207,6 @@ #endif /* NS_DEBUG_SPINLOCKS */ -/* Version definition *********************************************************/ -/* -#include -char kernel_version[] = UTS_RELEASE; -*/ - /* Function declarations ******************************************************/ static u32 ns_read_sram(ns_dev *card, u32 sram_address); @@ -793,7 +787,7 @@ u32d[0] = NS_RCTE_RAWCELLINTEN; #else u32d[0] = 0x00000000; -#endif RCQ_SUPPORT +#endif /* RCQ_SUPPORT */ u32d[1] = 0x00000000; u32d[2] = 0x00000000; u32d[3] = 0xFFFFFFFF; 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 23 11:45:28 2001 @@ -954,6 +954,8 @@ */ void submit_bh(int rw, struct buffer_head * bh) { + int count = bh->b_size >> 9; + if (!test_bit(BH_Lock, &bh->b_state)) BUG(); @@ -964,16 +966,16 @@ * further remap this. */ bh->b_rdev = bh->b_dev; - bh->b_rsector = bh->b_blocknr * (bh->b_size >> 9); + bh->b_rsector = bh->b_blocknr * count; generic_make_request(rw, bh); switch (rw) { case WRITE: - kstat.pgpgout++; + kstat.pgpgout += count; break; default: - kstat.pgpgin++; + kstat.pgpgin += count; break; } } @@ -1238,9 +1240,6 @@ #endif #ifdef CONFIG_BLK_DEV_RAM rd_init(); -#endif -#ifdef CONFIG_BLK_DEV_LOOP - loop_init(); #endif #ifdef CONFIG_ISP16_CDI isp16_init(); 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/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.4.2/linux/drivers/cdrom/cdrom.c Wed Feb 21 18:20:18 2001 +++ linux/drivers/cdrom/cdrom.c Thu Mar 29 11:56:07 2001 @@ -1171,42 +1171,50 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) { - int ret, i; - u_char buf[4 + 4 * 20], *base; + unsigned char buf[20], *base; struct dvd_layer *layer; struct cdrom_generic_command cgc; struct cdrom_device_ops *cdo = cdi->ops; + int ret, layer_num = s->physical.layer_num; + + if (layer_num >= DVD_LAYERS) + return -EINVAL; init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; - cgc.cmd[6] = s->physical.layer_num; + cgc.cmd[6] = layer_num; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen & 0xff; + /* + * refrain from reporting errors on non-existing layers (mainly) + */ + cgc.quiet = 1; + if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; base = &buf[4]; - layer = &s->physical.layer[0]; + layer = &s->physical.layer[layer_num]; - /* place the data... really ugly, but at least we won't have to - worry about endianess in userspace or here. */ - for (i = 0; i < 4; ++i, base += 20, ++layer) { - memset(layer, 0, sizeof(*layer)); - layer->book_version = base[0] & 0xf; - layer->book_type = base[0] >> 4; - layer->min_rate = base[1] & 0xf; - layer->disc_size = base[1] >> 4; - layer->layer_type = base[2] & 0xf; - layer->track_path = (base[2] >> 4) & 1; - layer->nlayers = (base[2] >> 5) & 3; - layer->track_density = base[3] & 0xf; - layer->linear_density = base[3] >> 4; - layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; - layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; - layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; - layer->bca = base[16] >> 7; - } + /* + * place the data... really ugly, but at least we won't have to + * worry about endianess in userspace. + */ + memset(layer, 0, sizeof(*layer)); + layer->book_version = base[0] & 0xf; + layer->book_type = base[0] >> 4; + layer->min_rate = base[1] & 0xf; + layer->disc_size = base[1] >> 4; + layer->layer_type = base[2] & 0xf; + layer->track_path = (base[2] >> 4) & 1; + layer->nlayers = (base[2] >> 5) & 3; + layer->track_density = base[3] & 0xf; + layer->linear_density = base[3] >> 4; + layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; + layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; + layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; + layer->bca = base[16] >> 7; return 0; } @@ -1985,7 +1993,7 @@ } case CDROMREADAUDIO: { struct cdrom_read_audio ra; - int lba; + int lba, nr; IOCTL_IN(arg, struct cdrom_read_audio, ra); @@ -2002,7 +2010,19 @@ if (lba < 0 || ra.nframes <= 0) return -EINVAL; - if ((cgc.buffer = (char *) kmalloc(CD_FRAMESIZE_RAW, GFP_KERNEL)) == NULL) + /* + * start with will ra.nframes size, back down if alloc fails + */ + nr = ra.nframes; + do { + cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL); + if (cgc.buffer) + break; + + nr >>= 1; + } while (nr); + + if (!nr) return -ENOMEM; if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) { @@ -2011,12 +2031,16 @@ } cgc.data_direction = CGC_DATA_READ; while (ra.nframes > 0) { - ret = cdrom_read_block(cdi, &cgc, lba, 1, 1, CD_FRAMESIZE_RAW); - if (ret) break; - __copy_to_user(ra.buf, cgc.buffer, CD_FRAMESIZE_RAW); - ra.buf += CD_FRAMESIZE_RAW; - ra.nframes--; - lba++; + if (nr > ra.nframes) + nr = ra.nframes; + + ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); + if (ret) + break; + __copy_to_user(ra.buf, cgc.buffer, CD_FRAMESIZE_RAW*nr); + ra.buf += CD_FRAMESIZE_RAW * nr; + ra.nframes -= nr; + lba += nr; } kfree(cgc.buffer); return ret; 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/Makefile linux/drivers/char/agp/Makefile --- v2.4.2/linux/drivers/char/agp/Makefile Fri Dec 29 14:07:21 2000 +++ linux/drivers/char/agp/Makefile Mon Mar 26 15:36:30 2001 @@ -7,7 +7,7 @@ export-objs := agpgart_be.o -multi-objs := agpgart.o +list-multi := agpgart.o agpgart-objs := agpgart_fe.o agpgart_be.o obj-$(CONFIG_AGP) += agpgart.o 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/Makefile linux/drivers/char/drm/Makefile --- v2.4.2/linux/drivers/char/drm/Makefile Wed Feb 21 18:20:19 2001 +++ linux/drivers/char/drm/Makefile Mon Mar 26 15:36:30 2001 @@ -3,12 +3,10 @@ # the Direct Rendering Infrastructure (DRI) in XFree86 4.x. # -# drm.o is a fake target -- it is never built -# The real targets are in the module-list O_TARGET := drm.o -module-list := gamma.o tdfx.o r128.o ffb.o mga.o i810.o -export-objs := $(patsubst %.o,%_drv.o,$(module-list)) +export-objs := gamma_drv.o tdfx_drv.o r128_drv.o ffb_drv.o mga_drv.o \ + i810_drv.o # lib-objs are included in every module so that radical changes to the # architecture of the DRM support library can be made at a later time. @@ -42,6 +40,7 @@ endif endif +list-multi := gamma.o tdfx.o r128.o ffb.o mga.o i810.o gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o tdfx_context.o r128-objs := r128_drv.o r128_cce.o r128_context.o r128_bufs.o r128_state.o diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c --- v2.4.2/linux/drivers/char/drm/bufs.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/bufs.c Mon Mar 19 12:35:08 2001 @@ -485,10 +485,10 @@ return -EFAULT; if (request.count >= dma->buf_count) { - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (virtual > -1024UL) { /* Real error */ retcode = (signed long)virtual; diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h --- v2.4.2/linux/drivers/char/drm/drmP.h Thu Jan 4 14:50:49 2001 +++ linux/drivers/char/drm/drmP.h Mon Mar 26 15:48:31 2001 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/ffb_drv.c linux/drivers/char/drm/ffb_drv.c --- v2.4.2/linux/drivers/char/drm/ffb_drv.c Sun Nov 12 20:37:16 2000 +++ linux/drivers/char/drm/ffb_drv.c Sun Mar 25 18:14:20 2001 @@ -1,4 +1,4 @@ -/* $Id: ffb_drv.c,v 1.7 2000/11/12 10:01:41 davem Exp $ +/* $Id: ffb_drv.c,v 1.9 2001/03/23 07:58:39 davem Exp $ * ffb_drv.c: Creator/Creator3D direct rendering driver. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) @@ -244,7 +244,37 @@ }; } -static int __init ffb_init_one(int prom_node, int instance) +static void __init ffb_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs) +{ + struct linux_prom64_ranges ranges[PROMREG_MAX]; + char name[128]; + int len, i; + + prom_getproperty(parent, "name", name, sizeof(name)); + if (strcmp(name, "upa") != 0) + return; + + len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges)); + if (len <= 0) + return; + + len /= sizeof(struct linux_prom64_ranges); + for (i = 0; i < len; i++) { + struct linux_prom64_ranges *rng = &ranges[i]; + u64 phys_addr = regs->phys_addr; + + if (phys_addr >= rng->ot_child_base && + phys_addr < (rng->ot_child_base + rng->or_size)) { + regs->phys_addr -= rng->ot_child_base; + regs->phys_addr += rng->ot_parent_base; + return; + } + } + + return; +} + +static int __init ffb_init_one(int prom_node, int parent_node, int instance) { struct linux_prom64_registers regs[2*PROMREG_MAX]; drm_device_t *dev; @@ -266,6 +296,7 @@ kfree(dev); return -EINVAL; } + ffb_apply_upa_parent_ranges(parent_node, ®s[0]); ffb_priv->card_phys_base = regs[0].phys_addr; ffb_priv->regs = (ffb_fbcPtr) (regs[0].phys_addr + 0x00600000UL); @@ -305,15 +336,30 @@ return 0; } +static int __init ffb_count_siblings(int root) +{ + int node, child, count = 0; + + child = prom_getchild(root); + for (node = prom_searchsiblings(child, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) + count++; + + return count; +} + static int __init ffb_init_dev_table(void) { - int root, node; - int total = 0; + int root, total; + total = ffb_count_siblings(prom_root_node); root = prom_getchild(prom_root_node); - for (node = prom_searchsiblings(root, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) - total++; + for (root = prom_searchsiblings(root, "upa"); root; + root = prom_searchsiblings(prom_getsibling(root), "upa")) + total += ffb_count_siblings(root); + + if (!total) + return -ENODEV; ffb_dev_table = kmalloc(sizeof(drm_device_t *) * total, GFP_KERNEL); if (!ffb_dev_table) @@ -324,23 +370,34 @@ return 0; } +static int __init ffb_scan_siblings(int root, int instance) +{ + int node, child; + + child = prom_getchild(root); + for (node = prom_searchsiblings(child, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) { + ffb_init_one(node, root, instance); + instance++; + } + + return instance; +} + int __init ffb_init(void) { - int root, node, instance, ret; + int root, instance, ret; ret = ffb_init_dev_table(); if (ret) return ret; - instance = 0; + instance = ffb_scan_siblings(prom_root_node, 0); + root = prom_getchild(prom_root_node); - for (node = prom_searchsiblings(root, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) { - ret = ffb_init_one(node, instance); - if (ret) - return ret; - instance++; - } + for (root = prom_searchsiblings(root, "upa"); root; + root = prom_searchsiblings(prom_getsibling(root), "upa")) + instance = ffb_scan_siblings(root, instance); return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c --- v2.4.2/linux/drivers/char/drm/i810_dma.c Mon Dec 11 12:39:44 2000 +++ linux/drivers/char/drm/i810_dma.c Mon Mar 19 12:35:08 2001 @@ -192,7 +192,7 @@ if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL; if(VM_DONTCOPY != 0) { - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); old_fops = filp->f_op; filp->f_op = &i810_buffer_fops; dev_priv->mmap_buffer = buf; @@ -208,7 +208,7 @@ retcode = (signed int)buf_priv->virtual; buf_priv->virtual = 0; } - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } else { buf_priv->virtual = buf_priv->kernel_virtual; buf_priv->currently_mapped = I810_BUF_MAPPED; @@ -224,7 +224,7 @@ if(VM_DONTCOPY != 0) { if(buf_priv->currently_mapped != I810_BUF_MAPPED) return -EINVAL; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); #if LINUX_VERSION_CODE < 0x020399 retcode = do_munmap((unsigned long)buf_priv->virtual, (size_t) buf->total); @@ -233,7 +233,7 @@ (unsigned long)buf_priv->virtual, (size_t) buf->total); #endif - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } buf_priv->currently_mapped = I810_BUF_UNMAPPED; buf_priv->virtual = 0; diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/mga_bufs.c linux/drivers/char/drm/mga_bufs.c --- v2.4.2/linux/drivers/char/drm/mga_bufs.c Sun Oct 1 20:00:00 2000 +++ linux/drivers/char/drm/mga_bufs.c Mon Mar 19 12:35:08 2001 @@ -549,17 +549,17 @@ DRM_DEBUG("map->flags : %x\n", map->flags); DRM_DEBUG("map->handle : %p\n", map->handle); DRM_DEBUG("map->mtrr : %d\n", map->mtrr); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, MAP_SHARED, (unsigned long)map->offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } else { - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } if (virtual > -1024UL) { /* Real error */ diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/r128_bufs.c linux/drivers/char/drm/r128_bufs.c --- v2.4.2/linux/drivers/char/drm/r128_bufs.c Thu Jan 4 13:03:20 2001 +++ linux/drivers/char/drm/r128_bufs.c Mon Mar 19 12:35:08 2001 @@ -249,17 +249,17 @@ goto done; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, MAP_SHARED, (unsigned long)map->offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } else { - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } if (virtual > -1024UL) { /* Real error */ 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/drm/radeon_bufs.c linux/drivers/char/drm/radeon_bufs.c --- v2.4.2/linux/drivers/char/drm/radeon_bufs.c Sat Feb 3 19:51:27 2001 +++ linux/drivers/char/drm/radeon_bufs.c Mon Mar 19 12:35:08 2001 @@ -240,17 +240,17 @@ goto done; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, MAP_SHARED, (unsigned long)map->offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } else { - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } if (virtual > -1024UL) { /* Real error */ 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 Sun Mar 25 18:24:31 2001 @@ -1,184 +1,18 @@ /* 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/ - - - Based on: - Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet - May 1999 Order Number: 290658-002 R - - Intel 82802 Firmware Hub: Random Number Generator - Programmer's Reference Manual - December 1999 Order Number: 298029-001 R - - Intel 82802 Firmware HUB Random Number Generator Driver - Copyright (c) 2000 Matt Sottek - - Special thanks to Matt Sottek. I did the "guts", he - did the "brains" and all the testing. (Anybody wanna send - me an i810 or i820?) + Please read Documentation/i810_rng.txt for details on use. ---------------------------------------------------------- This software may be used and distributed according to the terms of the GNU General Public License, incorporated herein by reference. - ---------------------------------------------------------- - - From the firmware hub datasheet: - - The Firmware Hub integrates a Random Number Generator (RNG) - using thermal noise generated from inherently random quantum - mechanical properties of silicon. When not generating new random - bits the RNG circuitry will enter a low power state. Intel will - provide a binary software driver to give third party software - access to our RNG for use as a security feature. At this time, - the RNG is only to be used with a system in an OS-present state. - - ---------------------------------------------------------- - - Theory of operation: - - This driver has TWO modes of operation: - - Mode 1 - ------ - Character driver. Using the standard open() - and read() system calls, you can read random data from - the i810 RNG device. This data is NOT CHECKED by any - fitness tests, and could potentially be bogus (if the - hardware is faulty or has been tampered with). - - /dev/intel_rng is char device major 10, minor 183. - - - Mode 2 - ------ - Injection of entropy into the kernel entropy pool via a - timer function. - - A timer is run at rng_timer_len intervals, reading 8 bits - of data from the RNG. If the RNG has previously passed a - FIPS test, then the data will be added to the /dev/random - entropy pool. Then, those 8 bits are added to an internal - test data pool. When that pool is full, a FIPS test is - run to verify that the last N bytes read are decently random. - - Thus, the RNG will never be enabled until it passes a - FIPS test. And, data will stop flowing into the system - entropy pool if the data is determined to be non-random. - - Finally, note that the timer defaults to OFF. This ensures - that the system entropy pool will not be polluted with - RNG-originated data unless a conscious decision is made - by the user. - - HOWEVER NOTE THAT UP TO 2499 BYTES OF DATA CAN BE BOGUS - BEFORE THE SYSTEM WILL NOTICE VIA THE FIPS TEST. - - ---------------------------------------------------------- - - Driver notes: - - * You may enable and disable the RNG timer via sysctl: - - # disable RNG - echo 0 > /proc/sys/dev/i810_rng_timer - - # enable RNG - echo 1 > /proc/sys/dev/i810_rng_timer - - * The default number of entropy bits added by default is - the full 8 bits. If you wish to reduce this value for - paranoia's sake, you can do so via sysctl as well: - - # Add only 4 bits of entropy to /dev/random - echo 4 > /proc/sys/dev/i810_rng_entropy - - * The default number of entropy bits can also be set via - a module parameter "rng_entropy" at module load time. - - * When the RNG timer is enabled, the driver reads 1 byte - from the hardware RNG every N jiffies. By default, every - half-second. If you would like to change the timer interval, - do so via another sysctl: - - echo 200 > /proc/sys/dev/i810_rng_interval - - NOTE THIS VALUE IS IN JIFFIES, NOT SECONDS OR MILLISECONDS. - 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, - 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: It is possible for the timer function to read, - and shove into the kernel entropy pool, 2499 bytes of data - before the internal FIPS test notices that the data is bad. - The kernel should handle this (I think???), but we should use a - 2500-byte array, and re-run the FIPS test for every byte read. - This will slow things down but guarantee that bad data is - never passed upstream. - - * FIXME: module unload is racy. To fix this, struct ctl_table - needs an owner member a la struct file_operations. - - * 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. - - ---------------------------------------------------------- - - Change history: - - Version 0.6.2: - * Clean up spinlocks. Since we don't have any interrupts - to worry about, but we do have a timer to worry about, - we use spin_lock_bh everywhere except the timer function - itself. - * Fix module load/unload. - * Fix timer function and h/w enable/disable logic - * New timer interval sysctl - * Clean up sysctl names - - Version 0.9.0: - * Don't register a pci_driver, because we are really - using PCI bridge vendor/device ids, and someone - may want to register a driver for the bridge. (bug fix) - * Don't let the usage count go negative (bug fix) - * Clean up spinlocks (bug fix) - * Enable PCI device, if necessary (bug fix) - * iounmap on module unload (bug fix) - * If RNG chrdev is already in use when open(2) is called, - sleep until it is available. - * Remove redundant globals rng_allocated, rng_use_count - * Convert numeric globals to unsigned - * Module unload cleanup - - Version 0.9.1: - * Support i815 chipsets too (Matt Sottek) - * Fix reference counting when statically compiled (prumpf) - * Rewrite rng_dev_read (prumpf) - * Make module races less likely (prumpf) - * Small miscellaneous bug fixes (prumpf) - * Use pci table for PCI id list - - Version 0.9.2: - * Simplify open blocking logic - */ @@ -190,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -202,7 +35,7 @@ /* * core module and version information */ -#define RNG_VERSION "0.9.2" +#define RNG_VERSION "0.9.5" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION #define PFX RNG_MODULE_NAME ": " @@ -211,7 +44,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 +53,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) \ @@ -233,13 +66,6 @@ /* - * prototypes - */ -static void rng_fips_test_store (int rng_data); -static void rng_run_fips_test (void); - - -/* * RNG registers (offsets from rng_mem) */ #define RNG_HW_STATUS 0 @@ -249,6 +75,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 @@ -258,13 +87,6 @@ /* - * Frequency that data is added to kernel entropy pool - * HZ>>1 == every half-second - */ -#define RNG_DEF_TIMER_LEN (HZ >> 1) - - -/* * number of bytes required for a FIPS test. * do not alter unless you really, I mean * REALLY know what you are doing. @@ -277,18 +99,7 @@ * as we only support a single RNG device */ static int rng_hw_enabled; /* is the RNG h/w enabled? */ -static int rng_timer_enabled; /* is the RNG timer enabled? */ -static int rng_trusted; /* does FIPS trust out data? */ -static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */ -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 */ -static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */ -static struct timer_list rng_timer; /* kernel timer for RNG hardware reads and tests */ static struct pci_dev *rng_pdev; /* Firmware Hub PCI device found during PCI probe */ static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */ @@ -313,7 +124,7 @@ static inline int rng_data_present (void) { assert (rng_mem != NULL); - assert (rng_hw_enabled == 1); + assert (rng_hw_enabled > 0); return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0; } @@ -322,55 +133,13 @@ static inline int rng_data_read (void) { assert (rng_mem != NULL); - assert (rng_hw_enabled == 1); + assert (rng_hw_enabled > 0); return readb (rng_mem + RNG_DATA); } /* - * rng_timer_ticker - executes every rng_timer_len jiffies, - * adds a single byte to system entropy - * and internal FIPS test pools - */ -static void rng_timer_tick (unsigned long data) -{ - int rng_data; - - spin_lock (&rng_lock); - - if (rng_data_present ()) { - /* gimme some thermal noise, baby */ - rng_data = rng_data_read (); - - spin_unlock (&rng_lock); - - /* - * if RNG has been verified in the past, add - * data just read to the /dev/random pool, - * with the entropy specified by the user - * via sysctl (defaults to 8 bits) - */ - if (rng_trusted) - batch_entropy_store (rng_data, jiffies, rng_entropy); - - /* fitness testing via FIPS, if we have enough data */ - rng_fips_test_store (rng_data); - if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD) - rng_run_fips_test (); - } else { - spin_unlock (&rng_lock); - } - - /* run the timer again, if enabled */ - if (rng_timer_enabled) { - rng_timer.expires = jiffies + rng_timer_len; - add_timer (&rng_timer); - } -} - - -/* * rng_enable - enable or disable the RNG hardware */ static int rng_enable (int enable) @@ -380,8 +149,6 @@ DPRINTK ("ENTER\n"); - spin_lock_bh (&rng_lock); - hw_status = rng_hwstatus (); if (enable) { @@ -406,18 +173,16 @@ new_status = rng_hwstatus (); - spin_unlock_bh (&rng_lock); - - if (action == 1) - printk (KERN_INFO PFX "RNG h/w enabled\n"); - else if (action == 2) - printk (KERN_INFO PFX "RNG h/w disabled\n"); - - /* too bad C doesn't have ^^ */ - if ((!enable) != (!(new_status & RNG_ENABLED))) { - printk (KERN_ERR PFX "Unable to %sable the RNG\n", - enable ? "en" : "dis"); - rc = -EIO; + if (action == 1) { + if (new_status & RNG_ENABLED) + printk (KERN_INFO PFX "RNG h/w enabled\n"); + else + printk (KERN_ERR PFX "Unable to enable the RNG\n"); + } else if (action == 2) { + if ((new_status & RNG_ENABLED) == 0) + printk (KERN_INFO PFX "RNG h/w disabled\n"); + else + printk (KERN_ERR PFX "Unable to disable the RNG\n"); } DPRINTK ("EXIT, returning %d\n", rc); @@ -425,209 +190,12 @@ } -/* - * rng_handle_sysctl_enable - handle a read or write of our enable/disable sysctl - */ - -static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *filp, - void *buffer, size_t * lenp) -{ - int enabled_save, rc; - - DPRINTK ("ENTER\n"); - - MOD_INC_USE_COUNT; - spin_lock_bh (&rng_lock); - rng_enabled_sysctl = enabled_save = rng_timer_enabled; - spin_unlock_bh (&rng_lock); - - rc = proc_dointvec (table, write, filp, buffer, lenp); - if (rc) - return rc; - - spin_lock_bh (&rng_lock); - if (enabled_save != rng_enabled_sysctl) { - rng_timer_enabled = rng_enabled_sysctl; - spin_unlock_bh (&rng_lock); - - /* enable/disable hardware */ - rng_enable (rng_enabled_sysctl); - - /* enable/disable timer */ - if (rng_enabled_sysctl) { - rng_timer.expires = jiffies + rng_timer_len; - add_timer (&rng_timer); - } else { - del_timer_sync (&rng_timer); - } - } else { - spin_unlock_bh (&rng_lock); - } - - /* This needs to be in a higher layer */ - MOD_DEC_USE_COUNT; - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -/* - * rng_handle_sysctl_entropy - handle a read or write of our entropy bits sysctl - */ - -static int rng_handle_sysctl_entropy (ctl_table * table, int write, struct file *filp, - void *buffer, size_t * lenp) -{ - int entropy_bits_save, rc; - - DPRINTK ("ENTER\n"); - - spin_lock_bh (&rng_lock); - rng_entropy_sysctl = entropy_bits_save = rng_entropy; - spin_unlock_bh (&rng_lock); - - rc = proc_dointvec (table, write, filp, buffer, lenp); - if (rc) - return rc; - - if (entropy_bits_save == rng_entropy_sysctl) - goto out; - - if ((rng_entropy_sysctl >= 0) && - (rng_entropy_sysctl <= 8)) { - spin_lock_bh (&rng_lock); - rng_entropy = rng_entropy_sysctl; - spin_unlock_bh (&rng_lock); - - printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl); - } else { - printk (KERN_INFO PFX "ignoring invalid entropy setting (%d)\n", - rng_entropy_sysctl); - } - -out: - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - -/* - * rng_handle_sysctl_interval - handle a read or write of our timer interval len sysctl - */ - -static int rng_handle_sysctl_interval (ctl_table * table, int write, struct file *filp, - void *buffer, size_t * lenp) -{ - int timer_len_save, rc; - - DPRINTK ("ENTER\n"); - - spin_lock_bh (&rng_lock); - rng_interval_sysctl = timer_len_save = rng_timer_len; - spin_unlock_bh (&rng_lock); - - rc = proc_dointvec (table, write, filp, buffer, lenp); - if (rc) - return rc; - - if (timer_len_save == rng_interval_sysctl) - goto out; - - if ((rng_interval_sysctl > 0) && - (rng_interval_sysctl < (HZ*86400))) { - spin_lock_bh (&rng_lock); - rng_timer_len = rng_interval_sysctl; - spin_unlock_bh (&rng_lock); - - printk (KERN_INFO PFX "timer interval now %d\n", rng_interval_sysctl); - } else { - printk (KERN_INFO PFX "ignoring invalid timer interval (%d)\n", - rng_interval_sysctl); - } - -out: - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -/* - * rng_sysctl - add or remove the rng sysctl - */ -static void rng_sysctl (int add) -{ -#define DEV_I810_TIMER 1 -#define DEV_I810_ENTROPY 2 -#define DEV_I810_INTERVAL 3 - - /* Definition of the sysctl */ - /* FIXME: use new field:value style of struct initialization */ - static ctl_table rng_sysctls[] = { - {DEV_I810_TIMER, /* ID */ - RNG_MODULE_NAME "_timer", /* name in /proc */ - &rng_enabled_sysctl, - sizeof (rng_enabled_sysctl), /* data ptr, data size */ - 0644, /* mode */ - 0, /* child */ - rng_handle_sysctl_enable, /* proc handler */ - 0, /* strategy */ - 0, /* proc control block */ - 0, 0} - , - {DEV_I810_ENTROPY, /* ID */ - RNG_MODULE_NAME "_entropy", /* name in /proc */ - &rng_entropy_sysctl, - sizeof (rng_entropy_sysctl), /* data ptr, data size */ - 0644, /* mode */ - 0, /* child */ - rng_handle_sysctl_entropy, /* proc handler */ - 0, /* strategy */ - 0, /* proc control block */ - 0, 0} - , - {DEV_I810_INTERVAL, /* ID */ - RNG_MODULE_NAME "_interval", /* name in /proc */ - &rng_interval_sysctl, - sizeof (rng_interval_sysctl), /* data ptr, data size */ - 0644, /* mode */ - 0, /* child */ - rng_handle_sysctl_interval, /* proc handler */ - 0, /* strategy */ - 0, /* proc control block */ - 0, 0} - , - {0} - }; - - /* Define the parent file : /proc/sys/dev */ - static ctl_table sysctls_root[] = { - {CTL_DEV, - "dev", - NULL, 0, - 0555, - rng_sysctls}, - {0} - }; - static struct ctl_table_header *sysctls_root_header = NULL; - - if (add) { - if (!sysctls_root_header) - sysctls_root_header = register_sysctl_table (sysctls_root, 0); - } else if (sysctls_root_header) { - unregister_sysctl_table (sysctls_root_header); - sysctls_root_header = NULL; - } -} - - 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 +207,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; } @@ -662,12 +226,13 @@ static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size, loff_t * offp) { + static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; int have_data; u8 data = 0; ssize_t ret = 0; while (size) { - spin_lock_bh (&rng_lock); + spin_lock (&rng_lock); have_data = 0; if (rng_data_present ()) { @@ -675,7 +240,7 @@ have_data = 1; } - spin_unlock_bh (&rng_lock); + spin_unlock (&rng_lock); if (have_data) { if (put_user (data, buf++)) { @@ -686,20 +251,35 @@ ret++; } - if (current->need_resched) - schedule (); + if (filp->f_flags & O_NONBLOCK) + return ret ? : -EAGAIN; + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); 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 */ @@ -710,19 +290,19 @@ DPRINTK ("ENTER\n"); - 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 */ @@ -734,13 +314,6 @@ goto err_out_free_map; } - if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY) - rng_entropy = RNG_MAX_ENTROPY; - - /* init core RNG timer, but do not add it */ - init_timer (&rng_timer); - rng_timer.function = rng_timer_tick; - /* turn RNG h/w off, if it's on */ rc = rng_enable (0); if (rc) { @@ -748,17 +321,14 @@ goto err_out_free_map; } - /* add sysctls */ - rng_sysctl (1); - DPRINTK ("EXIT, returning 0\n"); return 0; 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; } @@ -771,7 +341,7 @@ * register a pci_driver, because someone else might one day * want to register another driver on the same PCI id. */ -const static struct pci_device_id rng_pci_tbl[] __initdata = { +static struct pci_device_id rng_pci_tbl[] __initdata = { { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, }, @@ -780,25 +350,8 @@ MODULE_DEVICE_TABLE (pci, rng_pci_tbl); -MODULE_AUTHOR("Jeff Garzik, Matt Sottek"); +MODULE_AUTHOR("Jeff Garzik, Philipp Rumpf, Matt Sottek"); MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver"); -MODULE_PARM(rng_entropy, "1i"); -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, -}; /* @@ -826,15 +379,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; @@ -851,16 +395,13 @@ { DPRINTK ("ENTER\n"); - assert (rng_timer_enabled == 0); assert (rng_hw_enabled == 0); misc_deregister (&rng_miscdev); - 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"); } @@ -868,136 +409,3 @@ module_init (rng_init); module_exit (rng_cleanup); - - - - -/* These are the startup tests suggested by the FIPS 140-1 spec section -* 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm) -* The Monobit, Poker, Runs, and Long Runs tests are implemented below. -* This test is run at periodic intervals to verify -* data is sufficiently random. If the tests are failed the RNG module -* will no longer submit data to the entropy pool, but the tests will -* continue to run at the given interval. If at a later time the RNG -* passes all tests it will be re-enabled for the next period. -* The reason for this is that it is not unlikely that at some time -* during normal operation one of the tests will fail. This does not -* necessarily mean the RNG is not operating properly, it is just a -* statistically rare event. In that case we don't want to forever -* disable the RNG, we will just leave it disabled for the period of -* time until the tests are rerun and passed. -* -* For argument sake I tested /dev/urandom with these tests and it -* took 142,095 tries before I got a failure, and urandom isn't as -* random as random :) -*/ - -static int poker[16] = { 0, }, runs[12] = { 0, }; -static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0; - - -/* - * rng_fips_test_store - store 8 bits of entropy in FIPS - * internal test data pool - */ -static void rng_fips_test_store (int rng_data) -{ - int j; - static int last_bit = 0; - - DPRINTK ("ENTER, rng_data = %d\n", rng_data); - - poker[rng_data >> 4]++; - poker[rng_data & 15]++; - - /* Note in the loop below rlength is always one less than the actual - run length. This makes things easier. */ - last_bit = (rng_data & 128) >> 7; - for (j = 7; j >= 0; j--) { - ones += current_bit = (rng_data & 1 << j) >> j; - if (current_bit != last_bit) { - /* If runlength is 1-6 count it in correct bucket. 0's go in - runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */ - if (rlength < 5) { - runs[rlength + - (6 * current_bit)]++; - } else { - runs[5 + (6 * current_bit)]++; - } - - /* Check if we just failed longrun test */ - if (rlength >= 33) - rng_test &= 8; - rlength = 0; - /* flip the current run type */ - last_bit = current_bit; - } else { - rlength++; - } - } - - DPRINTK ("EXIT\n"); -} - - -/* - * now that we have some data, run a FIPS test - */ -static void rng_run_fips_test (void) -{ - int j, i; - - DPRINTK ("ENTER\n"); - - /* add in the last (possibly incomplete) run */ - if (rlength < 5) - runs[rlength + (6 * current_bit)]++; - else { - runs[5 + (6 * current_bit)]++; - if (rlength >= 33) - rng_test &= 8; - } - /* Ones test */ - if ((ones >= 10346) || (ones <= 9654)) - 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; - if ((runs[0] < 2267) || (runs[0] > 2733) || - (runs[1] < 1079) || (runs[1] > 1421) || - (runs[2] < 502) || (runs[2] > 748) || - (runs[3] < 223) || (runs[3] > 402) || - (runs[4] < 90) || (runs[4] > 223) || - (runs[5] < 90) || (runs[5] > 223) || - (runs[6] < 2267) || (runs[6] > 2733) || - (runs[7] < 1079) || (runs[7] > 1421) || - (runs[8] < 502) || (runs[8] > 748) || - (runs[9] < 223) || (runs[9] > 402) || - (runs[10] < 90) || (runs[10] > 223) || - (runs[11] < 90) || (runs[11] > 223)) { - rng_test &= 4; - } - - rng_test = !rng_test; - DPRINTK ("FIPS test %sed\n", rng_test ? "pass" : "fail"); - - /* enable/disable RNG with results of the tests */ - if (rng_test && !rng_trusted) - printk (KERN_WARNING PFX "FIPS test passed, enabling RNG\n"); - else if (!rng_test && rng_trusted) - printk (KERN_WARNING PFX "FIPS test failed, disabling RNG\n"); - - rng_trusted = rng_test; - - /* finally, clear out FIPS variables for start of next run */ - memset (poker, 0, sizeof (poker)); - memset (runs, 0, sizeof (runs)); - ones = 0; - rlength = -1; - current_bit = 0; - rng_test = 0; - - DPRINTK ("EXIT\n"); -} 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 Mon Mar 26 15:41:19 2001 @@ -135,8 +135,8 @@ #include #include -/* if you have more than 3 printers, remember to increase LP_NO */ -#define LP_NO 3 +/* if you have more than 8 printers, remember to increase LP_NO */ +#define LP_NO 8 /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) @@ -344,26 +344,7 @@ return -EINTR; parport_claim_or_block (lp_table[minor].dev); - - for (;;) { - retval = parport_read (port, kbuf, count); - - if (retval) - break; - - if (file->f_flags & O_NONBLOCK) - break; - - /* Wait for an interrupt. */ - interruptible_sleep_on_timeout (&lp_table[minor].waitq, - LP_TIMEOUT_POLLED); - - if (signal_pending (current)) { - retval = -EINTR; - break; - } - } - + retval = parport_read (port, kbuf, count); parport_release (lp_table[minor].dev); if (retval > 0 && copy_to_user (buf, kbuf, retval)) @@ -500,7 +481,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 Mon Mar 19 12:35:08 2001 @@ -353,7 +353,7 @@ mm = current->mm; /* Oops, this was forgotten before. -ben */ - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); /* For private mappings, just map in zero pages. */ for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { @@ -367,10 +367,8 @@ if (count > size) count = size; - flush_cache_range(mm, addr, addr + count); zap_page_range(mm, addr, count); zeromap_page_range(addr, count, PAGE_COPY); - flush_tlb_range(mm, addr, addr + count); size -= count; buf += count; @@ -379,7 +377,7 @@ goto out_up; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* The shared case is hard. Let's do the conventional zeroing. */ do { @@ -394,7 +392,7 @@ return size; out_up: - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return size; } @@ -641,6 +639,9 @@ #endif #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(); diff -u --recursive --new-file v2.4.2/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.4.2/linux/drivers/char/misc.c Wed Feb 21 18:20:20 2001 +++ linux/drivers/char/misc.c Sun Mar 25 18:24:31 2001 @@ -75,7 +75,6 @@ extern int ds1286_init(void); extern int dsp56k_init(void); extern int radio_init(void); -extern int pc110pad_init(void); extern int pmu_device_init(void); extern int qpmouse_init(void); extern int tosh_init(void); @@ -248,9 +247,6 @@ create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL); #if defined CONFIG_82C710_MOUSE qpmouse_init(); -#endif -#ifdef CONFIG_PC110_PAD - pc110pad_init(); #endif #ifdef CONFIG_MVME16x rtc_MK48T08_init(); 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 Sun Mar 25 18:24:31 2001 @@ -46,21 +46,6 @@ #define ENABLE_PCI #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 #include @@ -137,13 +122,6 @@ #undef TIME_STAT_VERBOSE /* Undef this if you want a terse log message. */ #define _INLINE_ inline - -#ifndef NEW_MODULES -/* - * NB. we must include the kernel idenfication string in to install the module. - */ -/*static*/ char kernel_version[] = UTS_RELEASE; -#endif static struct r_port *rp_table[MAX_RP_PORTS]; static struct tty_struct *rocket_table[MAX_RP_PORTS]; 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/char/tty_io.c linux/drivers/char/tty_io.c --- v2.4.2/linux/drivers/char/tty_io.c Wed Feb 21 18:20:21 2001 +++ linux/drivers/char/tty_io.c Thu Mar 22 09:20:45 2001 @@ -60,6 +60,9 @@ * * Reduced memory usage for older ARM systems * -- Russell King + * + * Move do_SAK() into process context. Less stack use in devfs functions. + * alloc_tty_struct() always uses kmalloc() -- Andrew Morton 17Mar01 */ #include @@ -159,26 +162,19 @@ #define MAX(a,b) ((a) < (b) ? (b) : (a)) #endif -static inline struct tty_struct *alloc_tty_struct(void) +static struct tty_struct *alloc_tty_struct(void) { struct tty_struct *tty; - if (PAGE_SIZE > 8192) { - tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL); - if (tty) - memset(tty, 0, sizeof(struct tty_struct)); - } else - tty = (struct tty_struct *)get_zeroed_page(GFP_KERNEL); - + tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL); + if (tty) + memset(tty, 0, sizeof(struct tty_struct)); return tty; } static inline void free_tty_struct(struct tty_struct *tty) { - if (PAGE_SIZE > 8192) - kfree(tty); - else - free_page((unsigned long) tty); + kfree(tty); } /* @@ -1814,12 +1810,16 @@ * Now, if it would be correct ;-/ The current code has a nasty hole - * it doesn't catch files in flight. We may send the descriptor to ourselves * via AF_UNIX socket, close it and later fetch from socket. FIXME. + * + * Nasty bug: do_SAK is being called in interrupt context. This can + * deadlock. We punt it up to process context. AKPM - 16Mar2001 */ -void do_SAK( struct tty_struct *tty) +static void __do_SAK(void *arg) { #ifdef TTY_SOFT_SAK tty_hangup(tty); #else + struct tty_struct *tty = arg; struct task_struct *p; int session; int i; @@ -1842,7 +1842,6 @@ task_lock(p); if (p->files) { read_lock(&p->files->file_lock); - /* FIXME: p->files could change */ for (i=0; i < p->files->max_fds; i++) { filp = fcheck_files(p->files, i); if (filp && (filp->f_op == &tty_fops) && @@ -1860,6 +1859,19 @@ } /* + * The tq handling here is a little racy - tty->SAK_tq may already be queued. + * But there's no mechanism to fix that without futzing with tqueue_lock. + * Fortunately we don't need to worry, because if ->SAK_tq is already queued, + * the values which we write to it will be identical to the values which it + * already has. --akpm + */ +void do_SAK(struct tty_struct *tty) +{ + PREPARE_TQUEUE(&tty->SAK_tq, __do_SAK, tty); + schedule_task(&tty->SAK_tq); +} + +/* * This routine is called out of the software interrupt to flush data * from the flip buffer to the line discipline. */ @@ -1973,6 +1985,7 @@ sema_init(&tty->atomic_write, 1); spin_lock_init(&tty->read_lock); INIT_LIST_HEAD(&tty->tty_files); + INIT_TQUEUE(&tty->SAK_tq, 0, 0); } /* @@ -1986,17 +1999,15 @@ /* * Register a tty device described by , with minor number . */ -void tty_register_devfs (struct tty_driver *driver, unsigned int flags, - unsigned int minor) +void tty_register_devfs (struct tty_driver *driver, unsigned int flags, unsigned minor) { #ifdef CONFIG_DEVFS_FS umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR; - struct tty_struct tty; + kdev_t device = MKDEV (driver->major, minor); + int idx = minor - driver->minor_start; char buf[32]; - tty.driver = *driver; - tty.device = MKDEV (driver->major, minor); - switch (tty.device) { + switch (device) { case TTY_DEV: case PTMX_DEV: mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; @@ -2017,7 +2028,8 @@ (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) flags |= DEVFS_FL_CURRENT_OWNER; # endif - devfs_register (NULL, tty_name (&tty, buf), flags | DEVFS_FL_DEFAULT, + sprintf(buf, driver->name, idx + driver->name_base); + devfs_register (NULL, buf, flags | DEVFS_FL_DEFAULT, driver->major, minor, mode, &tty_fops, NULL); #endif /* CONFIG_DEVFS_FS */ } @@ -2026,14 +2038,11 @@ { #ifdef CONFIG_DEVFS_FS void * handle; - struct tty_struct tty; + int idx = minor - driver->minor_start; char buf[32]; - tty.driver = *driver; - tty.device = MKDEV(driver->major, minor); - - handle = devfs_find_handle (NULL, tty_name (&tty, buf), - driver->major, minor, + sprintf(buf, driver->name, idx + driver->name_base); + handle = devfs_find_handle (NULL, buf, driver->major, minor, DEVFS_SPECIAL_CHR, 0); devfs_unregister (handle); #endif /* CONFIG_DEVFS_FS */ @@ -2218,9 +2227,6 @@ */ void __init tty_init(void) { - if (sizeof(struct tty_struct) > PAGE_SIZE) - panic("size of tty structure > PAGE_SIZE!"); - /* * dev_tty_driver and dev_console_driver are actually magic * devices which get redirected at open time. Nevertheless, diff -u --recursive --new-file v2.4.2/linux/drivers/fc4/Makefile linux/drivers/fc4/Makefile --- v2.4.2/linux/drivers/fc4/Makefile Fri Dec 29 14:07:21 2000 +++ linux/drivers/fc4/Makefile Mon Mar 26 15:36:30 2001 @@ -14,7 +14,7 @@ obj-$(CONFIG_FC4_SOC) += soc.o obj-$(CONFIG_FC4_SOCAL) += socal.o +include $(TOPDIR)/Rules.make + fc4.o: $(fc4-objs) $(LD) -r -o $@ $(fc4-objs) - -include $(TOPDIR)/Rules.make 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 Sun Mar 18 09:25:02 2001 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-probe.c Version 1.06 June 9, 2000 + * linux/drivers/ide/ide-probe.c Version 1.07 March 18, 2001 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -25,6 +25,8 @@ * allowed for secondary flash card to be detectable * with new flag : drive->ata_flash : 1; * Version 1.06 stream line request queue and prep for cascade project. + * Version 1.07 max_sect <= 255; slower disks would get behind and + * then fall over when they get to 256. Paul G. */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -614,9 +616,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 +657,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; @@ -763,10 +774,10 @@ for (unit = 0; unit < minors; ++unit) { *bs++ = BLOCK_SIZE; #ifdef CONFIG_BLK_DEV_PDC4030 - *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 256); + *max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 255); #else /* IDE can do up to 128K per request. */ - *max_sect++ = 256; + *max_sect++ = 255; #endif *max_ra++ = MAX_READAHEAD; } 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 Tue Mar 20 15:42:18 2001 @@ -470,8 +470,6 @@ lynx->phy_reg0 = -1; lynx->async.queue = NULL; - spin_lock_init(&lynx->async.queue_lock); - spin_lock_init(&lynx->phy_reg_lock); pcl.next = pcl_bus(lynx, lynx->rcv_pcl); put_pcl(lynx, lynx->rcv_pcl_start, &pcl); @@ -1127,7 +1125,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"); @@ -1357,7 +1355,10 @@ lynx->id = num_of_cards-1; lynx->dev = dev; - if (!pci_dma_supported(dev, 0xffffffff)) { + lynx->lock = SPIN_LOCK_UNLOCKED; + lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED; + + if (pci_set_dma_mask(dev, 0xffffffff)) { FAIL("DMA address limits not supported for PCILynx hardware %d", lynx->id); } @@ -1456,8 +1457,6 @@ lynx->iso_rcv.pcl_start = alloc_pcl(lynx); /* all allocations successful - simple init stuff follows */ - - lynx->lock = SPIN_LOCK_UNLOCKED; reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); diff -u --recursive --new-file v2.4.2/linux/drivers/input/keybdev.c linux/drivers/input/keybdev.c --- v2.4.2/linux/drivers/input/keybdev.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/input/keybdev.c Sun Mar 25 18:14:21 2001 @@ -37,9 +37,13 @@ #include #include -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__) || defined(CONFIG_SPARC64) static int x86_sysrq_alt = 0; +#ifdef CONFIG_SPARC64 +static int sparc_l1_a_state = 0; +extern void batten_down_hatches(void); +#endif static unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -75,6 +79,13 @@ return 0; } +#ifdef CONFIG_SPARC64 + if (keycode == KEY_A && sparc_l1_a_state) { + sparc_l1_a_state = 0; + batten_down_hatches(); + } +#endif + if (x86_keycodes[keycode] & 0x100) handle_scancode(0xe0, 1); @@ -87,6 +98,10 @@ if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT) x86_sysrq_alt = down; +#ifdef CONFIG_SPARC64 + if (keycode == KEY_STOP) + sparc_l1_a_state = down; +#endif return 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/input/mousedev.c linux/drivers/input/mousedev.c --- v2.4.2/linux/drivers/input/mousedev.c Wed Feb 21 18:20:22 2001 +++ linux/drivers/input/mousedev.c Sun Mar 25 18:14:20 2001 @@ -278,7 +278,8 @@ for (i = 0; i < count; i++) { - c = buffer[i]; + if (get_user(c, &buffer[i])) + return -EFAULT; if (c == mousedev_genius_seq[list->genseq]) { if (++list->genseq == MOUSEDEV_GENIUS_LEN) { 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 Mon Mar 26 15:38:19 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' @@ -76,6 +76,8 @@ bool ' Am7930' CONFIG_HISAX_AMD7930 fi fi + + dep_tristate ' Sedlbauer PCMCIA cs module' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA fi endmenu @@ -92,7 +94,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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,20 @@ /* - * $Id: b1.c,v 1.20 2000/11/23 20:45:14 kai Exp $ + * $Id: b1.c,v 1.20.6.3 2001/03/21 08:52:20 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.3 2001/03/21 08:52:20 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.20.6.2 2001/03/15 15:11:23 kai + * *** empty log message *** + * + * 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 +126,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.20 $"; +static char *revision = "$Revision: 1.20.6.3 $"; /* ------------------------------------------------------------- */ @@ -747,12 +756,13 @@ static int __init b1_init(void) { char *p; - char rev[10]; + char rev[32]; - if ((p = strchr(revision, ':'))) { - strncpy(rev, p + 1, sizeof(rev)); - p = strchr(rev, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(rev, p + 2, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; } else strcpy(rev, "1.0"); 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,20 @@ /* - * $Id: b1dma.c,v 1.11 2000/11/19 17:02:47 kai Exp $ + * $Id: b1dma.c,v 1.11.6.3 2001/03/21 08:52:21 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.3 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.11.6.2 2001/03/15 15:11:23 kai + * *** empty log message *** + * + * 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 +71,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.11 $"; +static char *revision = "$Revision: 1.11.6.3 $"; /* ------------------------------------------------------------- */ @@ -988,12 +997,13 @@ int b1dma_init(void) { char *p; - char rev[10]; + char rev[32]; - if ((p = strchr(revision, ':'))) { - strncpy(rev, p + 1, sizeof(rev)); - p = strchr(rev, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(rev, p + 2, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; } else strcpy(rev, "1.0"); 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,23 @@ /* - * $Id: b1isa.c,v 1.10 2000/11/23 20:45:14 kai Exp $ + * $Id: b1isa.c,v 1.10.6.4 2001/03/21 08:52:21 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.4 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.10.6.3 2001/03/15 15:11:23 kai + * *** empty log message *** + * + * 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 +36,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 +95,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.10 $"; +static char *revision = "$Revision: 1.10.6.4 $"; /* ------------------------------------------------------------- */ @@ -278,11 +290,12 @@ MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { - strncpy(driver->revision, p + 1, sizeof(driver->revision)); - p = strchr(driver->revision, '$'); - *p = 0; - } + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(driver->revision, p + 2, sizeof(driver->revision)); + driver->revision[sizeof(driver->revision)-1] = 0; + if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) + *(p-1) = 0; + } printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c --- v2.4.2/linux/drivers/isdn/avmb1/b1pci.c Tue Nov 28 21:44:41 2000 +++ linux/drivers/isdn/avmb1/b1pci.c Sun Mar 25 18:20:44 2001 @@ -1,11 +1,14 @@ /* - * $Id: b1pci.c,v 1.29.6.1 2000/11/28 12:02:45 kai Exp $ + * $Id: b1pci.c,v 1.29.6.2 2001/03/21 08:52:21 kai Exp $ * * Module for AVM B1 PCI-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pci.c,v $ + * Revision 1.29.6.2 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * * Revision 1.29.6.1 2000/11/28 12:02:45 kai * MODULE_DEVICE_TABLE for 2.4 * @@ -119,7 +122,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.29.6.1 $"; +static char *revision = "$Revision: 1.29.6.2 $"; /* ------------------------------------------------------------- */ @@ -571,17 +574,20 @@ MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { - strncpy(driver->revision, p + 1, sizeof(driver->revision)); - p = strchr(driver->revision, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(driver->revision, p + 2, sizeof(driver->revision)); + driver->revision[sizeof(driver->revision)-1] = 0; + if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) + *(p-1) = 0; + } #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - p = strchr(revision, ':'); - strncpy(driverv4->revision, p + 1, sizeof(driverv4->revision)); - p = strchr(driverv4->revision, '$'); - *p = 0; -#endif + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(driverv4->revision, p + 2, sizeof(driverv4->revision)); + driverv4->revision[sizeof(driverv4->revision)-1] = 0; + if ((p = strchr(driverv4->revision, '$')) != 0 && p > driverv4->revision) + *(p-1) = 0; } +#endif printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,20 @@ /* - * $Id: b1pcmcia.c,v 1.12 2000/11/23 20:45:14 kai Exp $ + * $Id: b1pcmcia.c,v 1.12.6.3 2001/03/21 08:52:21 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.3 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * 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 +42,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 +102,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.12 $"; +static char *revision = "$Revision: 1.12.6.3 $"; /* ------------------------------------------------------------- */ @@ -318,10 +327,11 @@ MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { - strncpy(driver->revision, p + 1, sizeof(driver->revision)); - p = strchr(driver->revision, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(driver->revision, p + 2, sizeof(driver->revision)); + driver->revision[sizeof(driver->revision)-1] = 0; + if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) + *(p-1) = 0; } printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,23 @@ /* - * $Id: c4.c,v 1.20.6.1 2000/11/28 12:02:45 kai Exp $ + * $Id: c4.c,v 1.20.6.5 2001/03/21 08:52:21 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.5 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.20.6.4 2001/03/15 15:11:23 kai + * *** empty log message *** + * + * 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 +87,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 +118,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.20.6.1 $"; +static char *revision = "$Revision: 1.20.6.5 $"; #undef CONFIG_C4_DEBUG #undef CONFIG_C4_POLLDEBUG @@ -1331,7 +1343,6 @@ add_card: 0, /* no add_card function */ }; - static int ncards = 0; static int __init c4_init(void) @@ -1343,10 +1354,11 @@ MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { - strncpy(driver->revision, p + 1, sizeof(driver->revision)); - p = strchr(driver->revision, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(driver->revision, p + 2, sizeof(driver->revision)); + driver->revision[sizeof(driver->revision)-1] = 0; + if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) + *(p-1) = 0; } printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,26 @@ /* - * $Id: capi.c,v 1.44.6.3 2000/12/17 22:45:08 kai Exp $ + * $Id: capi.c,v 1.44.6.8 2001/03/21 08:52:21 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.8 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.44.6.7 2001/03/15 15:11:24 kai + * *** empty log message *** + * + * Revision 1.44.6.6 2001/03/13 16:17:07 kai + * spelling fixes from 2.4.3-pre + * + * 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 +268,7 @@ #include "capifs.h" #endif -static char *revision = "$Revision: 1.44.6.3 $"; +static char *revision = "$Revision: 1.44.6.8 $"; MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)"); @@ -1317,7 +1332,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; @@ -2097,7 +2111,7 @@ callback: lower_callback, }; -static char rev[10]; +static char rev[32]; static int __init capi_init(void) { @@ -2105,12 +2119,13 @@ MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 2); - p = strchr(rev, '$'); - *(p-1) = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(rev, p + 2, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; } else - strcpy(rev, "???"); + strcpy(rev, "1.0"); if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); @@ -2209,7 +2224,7 @@ } #endif (void) detach_capi_interface(&cuser); - printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev); + printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev); } module_init(capi_init); 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,23 @@ /* - * $Id: capidrv.c,v 1.39 2000/11/23 20:45:14 kai Exp $ + * $Id: capidrv.c,v 1.39.6.4 2001/03/21 08:52:21 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.4 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.39.6.3 2001/03/13 16:17:07 kai + * spelling fixes from 2.4.3-pre + * + * 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 +231,7 @@ #include "capicmd.h" #include "capidrv.h" -static char *revision = "$Revision: 1.39 $"; +static char *revision = "$Revision: 1.39.6.4 $"; static int debugmode = 0; MODULE_AUTHOR("Carsten Paeth "); @@ -488,7 +500,7 @@ } -/* -------- controller managment ------------------------------------- */ +/* -------- controller management ------------------------------------- */ static inline capidrv_contr *findcontrbydriverid(int driverid) { @@ -2484,7 +2496,7 @@ { struct capi_register_params rparam; capi_profile profile; - char rev[10]; + char rev[32]; char *p; __u32 ncontr, contr; __u16 errcode; @@ -2498,12 +2510,13 @@ return -EIO; } - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(rev, p + 2, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; } else - strcpy(rev, " ??? "); + strcpy(rev, "1.0"); rparam.level3cnt = -2; /* number of bchannels twice */ rparam.datablkcnt = 16; @@ -2534,7 +2547,7 @@ } proc_init(); - printk(KERN_NOTICE "capidrv: Rev%s: loaded\n", rev); + printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev); MOD_DEC_USE_COUNT; return 0; 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,23 @@ /* - * $Id: capifs.c,v 1.14.6.1 2000/11/28 12:02:45 kai Exp $ + * $Id: capifs.c,v 1.14.6.5 2001/03/21 08:52:21 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.5 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.14.6.4 2001/03/15 15:11:24 kai + * *** empty log message *** + * + * 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 +105,7 @@ MODULE_AUTHOR("Carsten Paeth "); -static char *revision = "$Revision: 1.14.6.1 $"; +static char *revision = "$Revision: 1.14.6.5 $"; struct capifs_ncci { struct inode *inode; @@ -581,16 +593,17 @@ static int __init capifs_init(void) { - char rev[10]; + char rev[32]; char *p; int err; MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(rev, p + 2, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; } else strcpy(rev, "1.0"); @@ -600,9 +613,9 @@ return err; } #ifdef MODULE - printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev); + printk(KERN_NOTICE "capifs: Rev %s: loaded\n", rev); #else - printk(KERN_NOTICE "capifs: Rev%s: started\n", rev); + printk(KERN_NOTICE "capifs: Rev %s: started\n", rev); #endif MOD_DEC_USE_COUNT; return 0; 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 Sun Mar 25 18:20:44 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.2 2001/03/15 15:11:24 kai Exp $ * * CAPI 2.0 convert capi message to capi message struct * @@ -7,6 +7,12 @@ * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capiutil.c,v $ + * Revision 1.13.6.2 2001/03/15 15:11:24 kai + * *** empty log message *** + * + * 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. @@ -93,7 +99,6 @@ #include #include #include - #include "capiutil.h" /* from CAPI2.0 DDK AVM Berlin GmbH */ 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,23 @@ /* - * $Id: kcapi.c,v 1.21.6.1 2000/12/10 23:39:19 kai Exp $ + * $Id: kcapi.c,v 1.21.6.5 2001/03/21 08:52:21 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.5 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.21.6.4 2001/03/15 15:11:24 kai + * *** empty log message *** + * + * Revision 1.21.6.3 2001/03/13 16:17:08 kai + * spelling fixes from 2.4.3-pre + * + * 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 +148,7 @@ #include #endif -static char *revision = "$Revision: 1.21.6.1 $"; +static char *revision = "$Revision: 1.21.6.5 $"; /* ------------------------------------------------------------- */ @@ -814,7 +826,7 @@ } } /* - * ncci managment + * ncci management */ static void controllercb_new_ncci(struct capi_ctr * card, @@ -1752,7 +1764,7 @@ static int __init kcapi_init(void) { char *p; - char rev[10]; + char rev[32]; MOD_INC_USE_COUNT; @@ -1766,17 +1778,18 @@ proc_capi_init(); - if ((p = strchr(revision, ':'))) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(rev, p + 2, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0 && p > rev) + *(p-1) = 0; } else strcpy(rev, "1.0"); #ifdef MODULE - printk(KERN_NOTICE "CAPI-driver Rev%s: loaded\n", rev); + printk(KERN_NOTICE "CAPI-driver Rev %s: loaded\n", rev); #else - printk(KERN_NOTICE "CAPI-driver Rev%s: started\n", rev); + printk(KERN_NOTICE "CAPI-driver Rev %s: started\n", rev); #endif MOD_DEC_USE_COUNT; return 0; 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,23 @@ /* - * $Id: t1isa.c,v 1.16 2000/11/23 20:45:14 kai Exp $ + * $Id: t1isa.c,v 1.16.6.4 2001/03/21 08:52:21 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.4 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * Revision 1.16.6.3 2001/03/15 15:11:24 kai + * *** empty log message *** + * + * 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 +45,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 +116,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.16 $"; +static char *revision = "$Revision: 1.16.6.4 $"; /* ------------------------------------------------------------- */ @@ -625,10 +637,11 @@ MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { - strncpy(driver->revision, p + 1, sizeof(driver->revision)); - p = strchr(driver->revision, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(driver->revision, p + 2, sizeof(driver->revision)); + driver->revision[sizeof(driver->revision)-1] = 0; + if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) + *(p-1) = 0; } printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); 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 Sun Mar 25 18:20:44 2001 @@ -1,11 +1,17 @@ /* - * $Id: t1pci.c,v 1.13.6.1 2000/11/28 12:02:45 kai Exp $ + * $Id: t1pci.c,v 1.13.6.3 2001/03/21 08:52:21 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.3 2001/03/21 08:52:21 kai + * merge from main branch: fix buffer for revision string (calle) + * + * 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 +94,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.13.6.1 $"; +static char *revision = "$Revision: 1.13.6.3 $"; #undef CONFIG_T1PCI_DEBUG #undef CONFIG_T1PCI_POLLDEBUG @@ -302,10 +308,11 @@ MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { - strncpy(driver->revision, p + 1, sizeof(driver->revision)); - p = strchr(driver->revision, '$'); - *p = 0; + if ((p = strchr(revision, ':')) != 0 && p[1]) { + strncpy(driver->revision, p + 2, sizeof(driver->revision)); + driver->revision[sizeof(driver->revision)-1] = 0; + if ((p = strchr(driver->revision, '$')) != 0 && p > driver->revision) + *(p-1) = 0; } printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision); 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 Mon Mar 26 15:38:19 2001 @@ -54,7 +54,8 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o +obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o +obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o MD5FILES := isac.c isdnl1.c isdnl2.c isdnl3.c \ tei.c callc.c cert.c l3dss1.c l3_1tr6.c \ 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 Mon Mar 26 15:38:19 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.2 2001/03/13 16:17:08 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.2 $"; 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 Mon Mar 26 15:38:19 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.11 2001/03/13 16:17:08 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 Mon Mar 26 15:38:19 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.2 2001/03/13 16:17:08 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 Mon Mar 26 15:38:19 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.2 2001/03/13 16:17:08 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 Mon Mar 26 15:38:19 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.2 2001/03/13 16:17:08 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 Sun Mar 25 18:24:31 2001 @@ -0,0 +1,679 @@ +/*====================================================================== + + 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 + +/* + 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 Mon Mar 26 15:38:19 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.3 2001/03/13 16:17:09 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 Mon Mar 26 15:38:19 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.3 2001/03/13 16:17:09 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 Mon Mar 26 15:38:19 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_procconf.c,v 1.8 2000/11/13 22:51:47 kai Exp $ +/* $Id: hysdn_procconf.c,v 1.8.6.1 2001/03/13 16:17:09 kai Exp $ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -31,7 +31,7 @@ #include "hysdn_defs.h" -static char *hysdn_procconf_revision = "$Revision: 1.8 $"; +static char *hysdn_procconf_revision = "$Revision: 1.8.6.1 $"; #define INFO_OUT_LEN 80 /* length of info line including lf */ @@ -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 Mon Mar 26 15:38:19 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_sched.c,v 1.5 2000/11/22 17:13:13 kai Exp $ +/* $Id: hysdn_sched.c,v 1.5.6.1 2001/03/13 16:17:09 kai Exp $ * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc. * @@ -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 Mon Mar 26 15:38:19 2001 @@ -1,5 +1,5 @@ /* - * $Id: interrupt.c,v 1.4 1998/01/31 22:10:52 keil Exp $ + * $Id: interrupt.c,v 1.4.8.1 2001/03/13 16:17:09 kai Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify @@ -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/3c505.c linux/drivers/net/3c505.c --- v2.4.2/linux/drivers/net/3c505.c Wed Feb 21 18:20:24 2001 +++ linux/drivers/net/3c505.c Tue Mar 20 12:05:00 2001 @@ -601,15 +601,16 @@ printk("%s: memory squeeze, dropping packet\n", dev->name); target = adapter->dma_buffer; adapter->current_dma.target = NULL; + return; + } + + skb_reserve(skb, 2); + target = skb_put(skb, rlen); + if (virt_to_bus(target + rlen) >= MAX_DMA_ADDRESS) { + adapter->current_dma.target = target; + target = adapter->dma_buffer; } else { - skb_reserve(skb, 2); - target = skb_put(skb, rlen); - if (virt_to_bus(target + rlen) >= MAX_DMA_ADDRESS) { - adapter->current_dma.target = target; - target = adapter->dma_buffer; - } else { - adapter->current_dma.target = NULL; - } + adapter->current_dma.target = NULL; } /* if this happens, we die */ 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 Sun Mar 25 18:14:25 2001 @@ -1,8 +1,8 @@ /* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ /* - Written 1993-1998 by Donald Becker. + Written 1993-2000 by Donald Becker. - Copyright 1994-1998 by Donald Becker. + Copyright 1994-2000 by Donald Becker. Copyright 1993 United States Government as represented by the Director, National Security Agency. This software may be used and distributed according to the terms of the GNU General Public License, @@ -39,9 +39,11 @@ v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb v1.15 1/31/98 Faster recovery for Tx errors. -djb v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb + v1.18 12Mar2001 Andrew Morton + - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz) + - Reviewed against 1.18 from scyld.com */ -static char *version = "3c509.c:1.16 (2.2) 2/3/98 becker@cesdis.gsfc.nasa.gov.\n"; /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -61,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -71,10 +74,13 @@ #include #include +static char versionA[] __initdata = "3c509.c:1.18 12Mar2001 becker@scyld.com\n"; +static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n"; + #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 @@ -137,7 +143,7 @@ struct sk_buff *queue[SKB_QUEUE_SIZE]; char mca_slot; }; -static int id_port = 0x110; /* Start with 0x110 to avoid new sound cards.*/ +static int id_port __initdata = 0x110; /* Start with 0x110 to avoid new sound cards.*/ static struct net_device *el3_root_dev = NULL; static ushort id_read_eeprom(int index); @@ -158,7 +164,7 @@ int id; }; -struct el3_mca_adapters_struct el3_mca_adapters[] = { +static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = { { "3Com 3c529 EtherLink III (10base2)", 0x627c }, { "3Com 3c529 EtherLink III (10baseT)", 0x627d }, { "3Com 3c529 EtherLink III (test mode)", 0x62db }, @@ -166,29 +172,38 @@ { "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[] __initdata = { + { 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) +int __init el3_probe(struct net_device *dev) { struct el3_private *lp; short lrs_state = 0xff, i; @@ -196,9 +211,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); @@ -207,6 +222,8 @@ if (EISA_bus) { static int eisa_addr = 0x1000; while (eisa_addr < 0x9000) { + int device_id; + ioaddr = eisa_addr; eisa_addr += 0x1000; @@ -214,6 +231,12 @@ if (inw(ioaddr + 0xC80) != 0x6d50) continue; + /* Avoid conflict with 3c590, 3c592, 3c597, etc */ + device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83); + if ((device_id & 0xFF00) == 0x5900) { + continue; + } + /* Change the register set to the configuration window 0. */ outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD); @@ -294,7 +317,7 @@ } #endif /* CONFIG_MCA */ -#ifdef __ISAPNP__ +#ifdef CONFIG_ISAPNP if (nopnp == 1) goto no_pnp; @@ -318,7 +341,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 +353,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 +399,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 +419,7 @@ } } } -#endif /* __ISAPNP__ */ +#endif /* CONFIG_ISAPNP */ { unsigned int iobase = id_read_eeprom(8); @@ -451,7 +474,7 @@ { const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; - printk("%s: 3c509 at %#3.3lx, %s port, address ", + printk("%s: 3c5x9 at %#3.3lx, %s port, address ", dev->name, dev->base_addr, if_names[dev->if_port]); } @@ -474,7 +497,7 @@ el3_root_dev = dev; if (el3_debug > 0) - printk(version); + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); /* The EL3-specific entries in the device structure. */ dev->open = &el3_open; @@ -493,7 +516,7 @@ /* Read a word from the EEPROM using the regular EEPROM access register. Assume that we are in register window zero. */ -static ushort read_eeprom(int ioaddr, int index) +static ushort __init read_eeprom(int ioaddr, int index) { outw(EEPROM_READ + index, ioaddr + 10); /* Pause for at least 162 us. for the read to take place. */ @@ -502,7 +525,7 @@ } /* Read a word from the EEPROM when in the ISA ID probe state. */ -static ushort id_read_eeprom(int index) +static ushort __init id_read_eeprom(int index) { int bit, word = 0; @@ -984,7 +1007,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 Tue Mar 20 12:05:00 2001 @@ -46,6 +46,7 @@ #define RX_RING_SIZE 16 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ +#include #include #include #include @@ -105,9 +106,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 +352,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, @@ -419,7 +419,7 @@ printk(version); root_corkscrew_dev = NULL; - cards_found = corkscrew_scan(0); + cards_found = corkscrew_scan(NULL); return cards_found ? 0 : -ENODEV; } @@ -443,12 +443,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 +475,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 +506,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. */ @@ -590,11 +590,11 @@ ether_setup(dev); vp->next_module = root_corkscrew_dev; root_corkscrew_dev = dev; + SET_MODULE_OWNER(dev); if (register_netdev(dev) != 0) { kfree(dev); return NULL; } - SET_MODULE_OWNER(dev); #else /* not a MODULE */ /* Caution: quad-word alignment required for rings! */ dev->priv = @@ -1219,7 +1219,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 Sun Mar 25 18:24:31 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: @@ -133,8 +134,6 @@ problem by having an MMIO register write be immediately followed by an MMIO register read. -2) The RTL-8129 is only supported in Donald Becker's rtl8139 driver. - */ #include @@ -150,7 +149,7 @@ #include -#define RTL8139_VERSION "0.9.13" +#define RTL8139_VERSION "0.9.15c" #define MODNAME "8139too" #define RTL8139_DRIVER_NAME MODNAME " Fast Ethernet driver " RTL8139_VERSION #define PFX MODNAME ": " @@ -188,7 +187,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 +231,7 @@ enum { + HAS_MII_XCVR = 0x010000, HAS_CHIP_XCVR = 0x020000, HAS_LNK_CHNG = 0x040000, }; @@ -237,6 +239,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 +249,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 +277,18 @@ /* {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 }, + +#ifdef CONFIG_8139TOO_8129 + {0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 }, +#endif + + /* 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); @@ -391,10 +411,17 @@ Cfg1_VPD_Enable = 0x02, Cfg1_PIO = 0x04, Cfg1_MMIO = 0x08, - Cfg1_LWAKE = 0x10, + LWAKE = 0x10, /* not on 8139, 8139A */ Cfg1_Driver_Load = 0x20, Cfg1_LED0 = 0x40, Cfg1_LED1 = 0x80, + SLEEP = (1 << 1), /* only on 8139, 8139A */ + PWRDN = (1 << 0), /* only on 8139, 8139A */ +}; + +/* Bits in Config4 */ +enum Config4Bits { + LWPTN = (1 << 2), /* not on 8139, 8139A */ }; enum RxConfigBits { @@ -463,48 +490,59 @@ CH_8139C, } chip_t; +enum chip_flags { + HasPwrDn = (1 << 0), + HasLWake = (1 << 1), +}; + /* directly indexed by chip_t, above */ const static struct { const char *name; u8 version; /* from RTL8139C docs */ u32 RxConfigMask; /* should clear the bits supported by this chip */ + u32 flags; } rtl_chip_info[] = { { "RTL-8139", 0x40, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ + HasPwrDn, }, { "RTL-8139 rev K", 0x60, 0xf0fe0040, + HasPwrDn, }, { "RTL-8139A", 0x70, 0xf0fe0040, + 0, }, { "RTL-8139B", 0x78, - 0xf0fc0040 + 0xf0fc0040, + HasLWake, }, { "RTL-8130", 0x7C, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ + HasLWake, }, { "RTL-8139C", 0x74, 0xf0fc0040, /* XXX copied from RTL8139B, verify */ + HasLWake, }, }; struct rtl8139_private { - board_t board; void *mmio_addr; int drv_flags; struct pci_dev *pci_dev; @@ -512,15 +550,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 +578,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); @@ -627,11 +667,43 @@ (RX_DMA_BURST << RxCfgDMAShift); +static void __rtl8139_cleanup_dev (struct net_device *dev) +{ + struct rtl8139_private *tp; + struct pci_dev *pdev; + + assert (dev != NULL); + assert (dev->priv != NULL); + + tp = dev->priv; + assert (tp->pci_dev != NULL); + pdev = tp->pci_dev; + +#ifndef USE_IO_OPS + if (tp->mmio_addr) + iounmap (tp->mmio_addr); +#endif /* !USE_IO_OPS */ + + /* it's ok to call this even if we have no regions to free */ + pci_release_regions (pdev); + +#ifndef RTL8139_NDEBUG + /* poison memory before freeing */ + memset (dev, 0xBC, + sizeof (struct net_device) + + sizeof (struct rtl8139_private)); +#endif /* RTL8139_NDEBUG */ + + kfree (dev); + + pci_set_drvdata (pdev, NULL); +} + + static int __devinit rtl8139_init_board (struct pci_dev *pdev, - struct net_device **dev_out, - void **ioaddr_out) + struct net_device **dev_out) { - void *ioaddr = NULL; + void *ioaddr; struct net_device *dev; struct rtl8139_private *tp; u8 tmp8; @@ -643,20 +715,24 @@ DPRINTK ("ENTER\n"); assert (pdev != NULL); - assert (ioaddr_out != NULL); - *ioaddr_out = NULL; *dev_out = NULL; - /* dev zeroed in init_etherdev */ - dev = init_etherdev (NULL, sizeof (*tp)); + /* dev and dev->priv zeroed in alloc_etherdev */ + dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { - printk (KERN_ERR PFX "unable to alloc new ethernet\n"); + printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pdev->slot_name); DPRINTK ("EXIT, returning -ENOMEM\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); tp = dev->priv; + tp->pci_dev = pdev; + + /* 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); @@ -677,14 +753,14 @@ /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { - printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n"); + printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pdev->slot_name); rc = -ENODEV; goto err_out; } /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { - printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); + printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pdev->slot_name); rc = -ENODEV; goto err_out; } @@ -692,75 +768,83 @@ /* check for weird/broken PCI region reporting */ if ((pio_len < RTL_MIN_IO_SIZE) || (mmio_len < RTL_MIN_IO_SIZE)) { - printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); + printk (KERN_ERR PFX "%s: Invalid PCI region size(s), aborting\n", pdev->slot_name); rc = -ENODEV; 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, "8139too"); if (rc) - goto err_out_free_mmio; + goto err_out; + /* enable PCI bus-mastering */ pci_set_master (pdev); #ifdef USE_IO_OPS ioaddr = (void *) pio_start; + dev->base_addr = pio_start; #else /* ioremap MMIO region */ ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { - printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); + printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pdev->slot_name); rc = -EIO; - goto err_out_free_mmio; + goto err_out; } + dev->base_addr = (long) ioaddr; + tp->mmio_addr = ioaddr; #endif /* USE_IO_OPS */ + /* Bring the chip out of low-power mode. */ + if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { + tmp8 = RTL_R8 (Config1); + if (tmp8 & (SLEEP|PWRDN)) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tmp8 & ~(SLEEP|PWRDN)); + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } + } else { + u8 new_tmp8 = tmp8 = RTL_R8 (Config1); + if ((rtl_chip_info[tp->chipset].flags & HasLWake) && + (tmp8 & LWAKE)) + new_tmp8 &= ~LWAKE; + new_tmp8 |= Cfg1_PM_Enable; + if (new_tmp8 != tmp8) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W8 (Config1, tmp8); + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } + if (rtl_chip_info[tp->chipset].flags & HasLWake) { + tmp8 = RTL_R8 (Config4); + if (tmp8 & LWPTN) + RTL_W8 (Config4, tmp8 & ~LWPTN); + } + } + /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) + for (i = 1000; i > 0; i--) { + barrier(); + udelay (10); if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; - else - udelay (10); - - /* Bring the chip out of low-power mode. */ - if (tp->chipset == CH_8139B) { - RTL_W8 (Config1, RTL_R8 (Config1) & ~(1<<4)); - RTL_W8 (Config4, RTL_R8 (Config4) & ~(1<<2)); - } else { - /* handle RTL8139A and RTL8139 cases */ - /* XXX from becker driver. is this right?? */ - RTL_W8 (Config1, 0); } /* make sure chip thinks PIO and MMIO are enabled */ tmp8 = RTL_R8 (Config1); if ((tmp8 & Cfg1_PIO) == 0) { - printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); + printk (KERN_ERR PFX "%s: PIO not enabled, Cfg1=%02X, aborting\n", + pdev->slot_name, tmp8); rc = -EIO; - goto err_out_iounmap; + goto err_out; } if ((tmp8 & Cfg1_MMIO) == 0) { - printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); + printk (KERN_ERR PFX "%s: MMIO not enabled, Cfg1=%02X, aborting\n", + pdev->slot_name, tmp8); rc = -EIO; - goto err_out_iounmap; + goto err_out; } /* identify chip attached to board */ @@ -772,9 +856,9 @@ } /* if unknown chip, assume array element #0, original RTL-8139 in this case */ - printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n", + printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n", pdev->slot_name); - printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pdev->slot_name, RTL_R32 (TxConfig)); + printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pdev->slot_name, RTL_R32 (TxConfig)); tp->chipset = 0; match: @@ -784,22 +868,11 @@ rtl_chip_info[tp->chipset].name); DPRINTK ("EXIT, returning 0\n"); - *ioaddr_out = ioaddr; *dev_out = dev; return 0; -err_out_iounmap: - assert (ioaddr > 0); -#ifndef USE_IO_OPS - iounmap (ioaddr); -#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); + __rtl8139_cleanup_dev (dev); DPRINTK ("EXIT, returning %d\n", rc); return rc; } @@ -811,10 +884,9 @@ struct net_device *dev = NULL; struct rtl8139_private *tp; int i, addr_len, option; - void *ioaddr = NULL; + void *ioaddr; static int board_idx = -1; - static int printed_version = 0; - u8 tmp; + static int printed_version; DPRINTK ("ENTER\n"); @@ -828,13 +900,14 @@ printed_version = 1; } - i = rtl8139_init_board (pdev, &dev, &ioaddr); + i = rtl8139_init_board (pdev, &dev); if (i < 0) { DPRINTK ("EXIT, returning %d\n", i); return i; } tp = dev->priv; + ioaddr = tp->mmio_addr; assert (ioaddr != NULL); assert (dev != NULL); @@ -856,24 +929,23 @@ dev->watchdog_timeo = TX_TIMEOUT; dev->irq = pdev->irq; - dev->base_addr = (unsigned long) ioaddr; /* dev->priv/tp zeroed and aligned in init_etherdev */ 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->pci_dev = pdev; - tp->board = ent->driver_data; + tp->drv_flags = board_info[ent->driver_data].hw_flags; 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; + /* dev is fully set up and ready to use now */ + DPRINTK("about to register device named %s (%p)...\n", dev->name, dev); + i = register_netdev (dev); + if (i) goto err_out; - 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,70 +961,89 @@ printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", dev->name, rtl_chip_info[tp->chipset].name); - /* Put the chip into low-power mode. */ - RTL_W8_F (Cfg9346, Cfg9346_Unlock); - - tmp = RTL_R8 (Config1) & Config1Clear; - tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ - RTL_W8_F (Config1, tmp); + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, but + takes too much time. */ +#ifdef CONFIG_8139TOO_8129 + 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 +#endif + tp->phys[0] = 32; - RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ + /* Put the chip into low-power mode. */ + if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { + RTL_W8_F (Cfg9346, Cfg9346_Unlock); + RTL_W8_F (Config1, RTL_R8 (Config1) | PWRDN); + RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ + RTL_W8_F (Cfg9346, Cfg9346_Lock); + } /* 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; + +err_out: + __rtl8139_cleanup_dev (dev); + DPRINTK ("EXIT - returning %d\n", i); + return i; } 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"); assert (dev != NULL); - - np = (struct rtl8139_private *) (dev->priv); + np = dev->priv; assert (np != NULL); unregister_netdev (dev); -#ifndef USE_IO_OPS - 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)); - -#ifndef RTL8139_NDEBUG - /* poison memory before freeing */ - memset (dev, 0xBC, - sizeof (struct net_device) + - sizeof (struct rtl8139_private)); -#endif /* RTL8139_NDEBUG */ - - kfree (dev); - - pdev->driver_data = NULL; + __rtl8139_cleanup_dev (dev); DPRINTK ("EXIT\n"); } @@ -1035,7 +1126,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 +1150,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"); @@ -1083,27 +1174,28 @@ return location < 8 && mii_2_8139_map[location] ? readw (tp->mmio_addr + mii_2_8139_map[location]) : 0; } + +#ifdef CONFIG_8139TOO_8129 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; 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); } +#endif DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff); return (retval >> 1) & 0xffff; @@ -1115,21 +1207,23 @@ { 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; } + +#ifdef CONFIG_8139TOO_8129 mdio_sync (mdio_addr); /* Shift the command bits out. */ @@ -1137,20 +1231,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"); +#endif } @@ -1231,6 +1323,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,22 +1340,25 @@ /* 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; - if (tp->chipset >= CH_8139A) { - tmp = RTL_R8 (Config1) & Config1Clear; - tmp |= Cfg1_Driver_Load; - tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ - RTL_W8_F (Config1, tmp); - } else { - u8 foo = RTL_R8 (Config1) & Config1Clear; - RTL_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20)); + /* 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); } + RTL_W8 (Config1, RTL_R8 (Config1) | Cfg1_Driver_Load); + if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ @@ -1269,7 +1366,7 @@ RTL_W8 (Config4, tmp); /* disable magic packet scanning, which is enabled - * when PM is enabled above (Config1) */ + * when PM is enabled in Config1 */ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); } @@ -1442,9 +1539,11 @@ " partner ability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); +#if 0 RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); RTL_W8 (Cfg9346, Cfg9346_Lock); +#endif } } @@ -1544,7 +1643,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 +1658,8 @@ /* ...and finally, reset everything */ rtl8139_hw_start (dev); + + netif_wake_queue (dev); } @@ -1593,11 +1694,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 +1714,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 +1778,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 +1787,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 +1959,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); @@ -1875,9 +1978,11 @@ || tp->duplex_lock; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; +#if 0 RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); RTL_W8 (Cfg9346, Cfg9346_Lock); +#endif } status &= ~RxUnderrun; } @@ -1917,8 +2022,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 +2052,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", @@ -1967,11 +2070,16 @@ rtl8139_weird_interrupt (dev, tp, ioaddr, status, link_changed); - if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ + if (netif_running (dev) && + status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ rtl8139_rx_interrupt (dev, tp, ioaddr); - if (status & (TxOK | TxErr)) + if (netif_running (dev) && + status & (TxOK | TxErr)) { + spin_lock (&tp->lock); rtl8139_tx_interrupt (dev, tp, ioaddr); + spin_unlock (&tp->lock); + } boguscnt--; } while (boguscnt > 0); @@ -1986,8 +2094,6 @@ RTL_W16 (IntrStatus, 0xffff); } - spin_unlock (&tp->lock); - DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); } @@ -2043,8 +2149,11 @@ /* Green! Put the chip in low-power mode. */ RTL_W8 (Cfg9346, Cfg9346_Unlock); - RTL_W8 (Config1, 0x03); - RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + + if (rtl_chip_info[tp->chipset].flags & HasPwrDn) { + RTL_W8 (Config1, 0x03); + RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + } DPRINTK ("EXIT\n"); return 0; @@ -2074,7 +2183,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 +2216,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 +2240,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 +2253,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 +2287,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 +2296,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,11 +2304,14 @@ 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; + if (!netif_running (dev)) + return; + netif_device_detach (dev); spin_lock_irqsave (&tp->lock, flags); @@ -2207,8 +2330,10 @@ static void rtl8139_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); + if (!netif_running (dev)) + return; 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 Sun Mar 25 18:24:31 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,14 @@ 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_mbool ' Use PIO instead of MMIO' CONFIG_8139TOO_PIO $CONFIG_8139TOO + dep_mbool ' Support for automatic channel equalization (EXPERIMENTAL)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO $CONFIG_EXPERIMENTAL + dep_mbool ' Support for older RTL-8129/8130 boards' CONFIG_8139TOO_8129 $CONFIG_8139TOO 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 +196,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 +266,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 Mon Mar 26 15:39:56 2001 @@ -15,8 +15,9 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o ppp_async.o \ - ppp_generic.o slhc.o pppox.o auto_irq.o +export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o \ + ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \ + net_init.o ifeq ($(CONFIG_TULIP),y) obj-y += tulip/tulip.o @@ -49,6 +50,7 @@ obj-$(CONFIG_SUNQE) += sunqe.o obj-$(CONFIG_SUNBMAC) += sunbmac.o obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o +obj-$(CONFIG_SUNGEM) += sungem.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o @@ -163,7 +165,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/aironet4500_card.c linux/drivers/net/aironet4500_card.c --- v2.4.2/linux/drivers/net/aironet4500_card.c Wed Feb 21 18:20:25 2001 +++ linux/drivers/net/aironet4500_card.c Sun Mar 25 18:24:31 2001 @@ -370,7 +370,15 @@ request_region(isa_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"); if (!dev) { - dev = init_etherdev(dev, 0 ); + dev = init_etherdev(NULL, 0); + if (!dev) { + release_region(isa_ioaddr, AIRONET4X00_IO_SIZE); + isapnp_cfg_begin(logdev->PNP_BUS->PNP_BUS_NUMBER, + logdev->PNP_DEV_NUMBER); + isapnp_deactivate(logdev->PNP_DEV_NUMBER); + isapnp_cfg_end(); + return -ENOMEM; + } } dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL ); memset(dev->priv,0,sizeof(struct awc_private)); @@ -524,7 +532,7 @@ printk(KERN_WARNING " Use aironet4500_pnp if any problems(i.e. card malfunctioning). \n"); printk(KERN_WARNING " Note that this isa probe is not friendly... must give exact parameters \n"); - while (irq[card] !=0){ + while (irq[card] != 0){ isa_ioaddr = io[card]; isa_irq_line = irq[card]; @@ -532,7 +540,11 @@ request_region(isa_ioaddr, AIRONET4X00_IO_SIZE, "aironet4x00 ioaddr"); if (!dev) { - dev = init_etherdev(dev, 0 ); + dev = init_etherdev(NULL, 0); + if (!dev) { + release_region(isa_ioaddr, AIRONET4X00_IO_SIZE); + return (card == 0) ? -ENOMEM : 0; + } } dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL ); memset(dev->priv,0,sizeof(struct awc_private)); 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 Tue Mar 20 12:05:00 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. */ @@ -752,8 +752,8 @@ { int pkt_len = 0; int rsp_type = 0; - struct sk_buff *skb; - struct cops_local *lp = (struct cops_local *)dev->priv; + struct sk_buff *skb = NULL; + struct cops_local *lp = dev->priv; int ioaddr = dev->base_addr; int boguscount = 0; unsigned long flags; @@ -771,6 +771,7 @@ /* Wait for DMA to turn around. */ while(++boguscount<1000000) { + barrier(); if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY) break; } @@ -801,6 +802,7 @@ lp->stats.rx_dropped++; while(pkt_len--) /* Discard packet */ inb(ioaddr); + restore_flags(flags); return; } skb->dev = dev; @@ -820,7 +822,7 @@ printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", dev->name, pkt_len); lp->stats.tx_errors++; - kfree_skb(skb); + dev_kfree_skb_any(skb); return; } @@ -828,7 +830,7 @@ if(rsp_type == LAP_INIT_RSP) { /* Nodeid taken from received packet. */ lp->node_acquire = skb->data[0]; - kfree_skb(skb); + dev_kfree_skb_any(skb); return; } @@ -837,7 +839,7 @@ { printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type); lp->stats.tx_errors++; - kfree_skb(skb); + dev_kfree_skb_any(skb); return; } 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 Tue Mar 20 12:05:00 2001 @@ -554,6 +554,7 @@ ib = (struct lance_init_block *) (dev->mem_start); #ifdef TEST_HITS + { int i; printk("["); @@ -566,8 +567,10 @@ ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1"); } printk("]"); + } #endif + for (rd = &ib->brx_ring[lp->rx_new]; !((bits = rd->rmd1_bits) & LE_R1_OWN); rd = &ib->brx_ring[lp->rx_new]) { @@ -608,9 +611,11 @@ skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align */ skb_put(skb, len); /* make room */ + cp_from_buf(skb->data, (char *) lp->rx_buf_ptr_cpu[lp->rx_new], len); + skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; @@ -656,7 +661,7 @@ if (status & LE_T3_CLOS) { lp->stats.tx_carrier_errors++; - printk("%s: Carrier Lost", dev->name); + printk("%s: Carrier Lost\n", dev->name); /* Stop the lance */ writereg(&ll->rap, LE_CSR0); writereg(&ll->rdp, LE_C0_STOP); @@ -741,7 +746,7 @@ if (csr0 & LE_C0_MERR) { volatile unsigned long int_stat = *(unsigned long *) (system_base + IOCTL + SIR); - printk("%s: Memory error, status %04x", dev->name, csr0); + printk("%s: Memory error, status %04x\n", dev->name, csr0); if (int_stat & LANCE_DMA_MEMRDERR) { printk("%s: DMA error\n", dev->name); @@ -759,6 +764,7 @@ init_restart_lance(lp); netif_wake_queue(dev); } + writereg(&ll->rdp, LE_C0_INEA); writereg(&ll->rdp, LE_C0_INEA); } @@ -774,11 +780,6 @@ last_dev = dev; - /* Associate IRQ with lance_interrupt */ - if (request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) { - printk("Lance: Can't get irq %d\n", dev->irq); - return -EAGAIN; - } /* Stop the Lance */ writereg(&ll->rap, LE_CSR0); writereg(&ll->rdp, LE_C0_STOP); @@ -798,6 +799,12 @@ netif_start_queue(dev); + /* Associate IRQ with lance_interrupt */ + if (request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) { + printk("Lance: Can't get irq %d\n", dev->irq); + return -EAGAIN; + } + status = init_restart_lance(lp); /* @@ -999,7 +1006,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 +1015,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 +1026,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) { @@ -1035,10 +1043,13 @@ /* * FIXME: ugly hack! */ - dev->mem_start = KSEG1ADDR(0x0020000); + dev->mem_start = KSEG1ADDR(0x00020000); dev->mem_end = dev->mem_start + 0x00020000; dev->irq = ETHER; esar_base = system_base + ESAR; + + /* Workaround crash with booting KN04 2.1k from Disk */ + memset(dev->mem_start, 0, dev->mem_end - dev->mem_start); /* * setup the pointer arrays, this sucks [tm] :-( @@ -1206,13 +1217,13 @@ /* 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 root_lance_dev = NULL; #endif + #ifdef CONFIG_TC int slot = -1; @@ -1244,7 +1255,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 Sun Mar 25 18:24:31 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) @@ -543,7 +553,7 @@ static void __devinit dfx_bus_init(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; u8 val; /* used for I/O read/writes */ DBG_printk("In dfx_bus_init...\n"); @@ -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; } @@ -779,7 +787,7 @@ static int __devinit dfx_driver_init(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; int alloc_size; /* total buffer size needed */ char *top_v, *curr_v; /* virtual addrs into memory block */ u32 top_p, curr_p; /* physical addrs into memory block */ @@ -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) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + int ret; + DFX_board_t *bp = 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; } @@ -1276,7 +1298,7 @@ static int dfx_close(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; DBG_printk("In dfx_close...\n"); @@ -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; } @@ -1611,7 +1634,7 @@ static void dfx_int_common(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *) dev->priv; + DFX_board_t *bp = dev->priv; PI_UINT32 port_status; /* Port Status register */ /* Process xmt interrupts - frequent case, so always call this routine */ @@ -1640,7 +1663,6 @@ if (port_status & PI_PSTATUS_M_TYPE_0_PENDING) dfx_int_type_0_process(bp); /* process Type 0 interrupts */ - return; } @@ -1682,13 +1704,13 @@ static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; DFX_board_t *bp; /* private board structure pointer */ u8 tmp; /* used for disabling/enabling ints */ /* Get board pointer only if device structure is valid */ - bp = (DFX_board_t *) dev->priv; + bp = dev->priv; spin_lock(&bp->lock); @@ -1732,7 +1754,6 @@ } spin_unlock(&bp->lock); - return; } @@ -1781,7 +1802,7 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; /* Fill the bp->stats structure with driver-maintained counters */ @@ -1966,7 +1987,7 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; int i; /* used as index in for loop */ struct dev_mc_list *dmi; /* ptr to multicast addr entry */ @@ -2039,7 +2060,6 @@ { DBG_printk("%s: Adapter filters updated!\n", dev->name); } - return; } @@ -2081,7 +2101,7 @@ static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr) { - DFX_board_t *bp = (DFX_board_t *)dev->priv; + DFX_board_t *bp = dev->priv; struct sockaddr *p_sockaddr = (struct sockaddr *)addr; /* Copy unicast address to driver-maintained structs and update count */ @@ -2540,7 +2560,6 @@ /* Deassert reset */ dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0); - return; } @@ -2631,8 +2650,7 @@ return(DFX_K_HW_TIMEOUT); return(DFX_K_SUCCESS); } - - + /* * Align an sk_buff to a boundary power of 2 * @@ -2662,6 +2680,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 +2688,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 +2702,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,20 +2724,22 @@ * 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 = __dev_alloc_skb(NEW_SKB_SIZE, GFP_BUFFER); + 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. */ - my_skb_align(newskb,128); + my_skb_align(newskb, 128); bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data); /* * p_rcv_buff_va is only used inside the @@ -2733,12 +2757,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 +2858,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 +2883,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 +2891,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 +2906,6 @@ bp->rcv_xmt_reg.index.rcv_prod += 1; bp->rcv_xmt_reg.index.rcv_comp += 1; } - return; } @@ -2953,7 +2976,7 @@ ) { - DFX_board_t *bp = (DFX_board_t *) dev->priv; + DFX_board_t *bp = dev->priv; u8 prod; /* local transmit producer index */ PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */ @@ -3183,6 +3206,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,12 +3328,11 @@ 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) { - DFX_board_t *bp = (DFX_board_t*)dev->priv; + DFX_board_t *bp = dev->priv; unregister_netdev(dev); release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN ); @@ -3272,9 +3342,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 20 12:05:01 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, value) \ + if (dmfe_debug || dbug_now) \ + printk("DBUG: %s %x\n", msg, value) + +#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 */ @@ -1123,7 +1139,7 @@ } /* - Update CR6 vaule + Update CR6 value Firstly stop DM910X , then written value and start */ static void update_cr6(u32 cr6_data, u32 ioaddr) @@ -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/eexpress.c linux/drivers/net/eexpress.c --- v2.4.2/linux/drivers/net/eexpress.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/eexpress.c Tue Mar 20 12:05:01 2001 @@ -592,7 +592,7 @@ status = scb_status(dev); unstick_cu(dev); - printk(KERN_INFO "%s: transmit timed out, %s?", dev->name, + printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name, (SCB_complete(status)?"lost interrupt": "board on fire")); lp->stats.tx_errors++; 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 Sun Mar 25 18:24:31 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,37 +353,27 @@ 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)); + dev = alloc_etherdev(sizeof (*ep)); if (!dev) { 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, "epic100")) 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,69 +411,62 @@ 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); - /* Bring the chip out of low-power mode. */ outl(0x4200, ioaddr + GENCTL); /* Magic?! If we don't set this bit the MII interface won't work. */ outl(0x0008, ioaddr + TEST1); /* Turn on the MII transceiver. */ - outl(0x12, ioaddr + MIICfg); + outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); if (chip_idx == 1) 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)); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x.\n", dev->dev_addr[i]); - if (debug > 2) { - printk(KERN_DEBUG "%s: EEPROM contents\n", dev->name); + printk(KERN_DEBUG "epic100(%s): EEPROM contents\n", + pdev->slot_name); for (i = 0; i < 64; i++) printk(" %4.4x%s", read_eeprom(ioaddr, i), 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 " + printk(KERN_INFO "epic100(%s): MII transceiver #%d control " "%4.4x status %4.4x.\n", - dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status); + pdev->slot_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 "epic100(%s): Autonegotiation advertising %4.4x link " + "partner %4.4x.\n", + pdev->slot_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); + printk(KERN_WARNING "epic100(%s): ***WARNING***: No MII transceiver found!\n", + pdev->slot_name); /* Use the known PHY address of the EPII. */ ep->phys[0] = 3; } @@ -471,7 +478,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 "epic100(%s): Forced full duplex operation requested.\n", + pdev->slot_name); + } dev->if_port = ep->default_port = option; if (ep->default_port) ep->medialock = 1; @@ -486,18 +497,27 @@ dev->watchdog_timeo = TX_TIMEOUT; dev->tx_timeout = &epic_tx_timeout; + i = register_netdev(dev); + if (i) + goto err_out_unmap_tx; + + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x.\n", dev->dev_addr[i]); + 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); return -ENODEV; } @@ -514,7 +534,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,25 +581,38 @@ #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--) { + barrier(); + 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); - for (i = 10000; i > 0; i--) { + outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl); + for (i = 10000; i > 0; i--) { + barrier(); if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0) break; } @@ -589,27 +622,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 @@ -617,7 +644,7 @@ required by the details of which bits are reset and the transceiver wiring on the Ositech CardBus card. */ - outl(0x12, ioaddr + MIICfg); + outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); if (ep->chip_flags & MII_PWRDWN) outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); @@ -639,21 +666,20 @@ 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)); - outl(0x13, ioaddr + MIICfg); + dev->name, mdio_read(dev, ep->phys[0], 1)); } } 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 +689,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 +726,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 +749,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 +778,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 +799,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 +836,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 +844,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 +866,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 +887,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 +902,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 +913,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 +958,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); @@ -933,13 +976,11 @@ after the Tx thread. */ 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 net_device *dev = dev_instance; + 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 +1003,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 +1018,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 +1039,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 +1056,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 +1108,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 +1122,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 +1146,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 +1193,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 +1205,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 +1221,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 +1292,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 +1330,26 @@ static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct epic_private *ep = 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 +1358,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 +1387,44 @@ 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; + if (!netif_running(dev)) + return; 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); + if (!netif_running(dev)) + return; + epic_restart(dev); + /* pci_power_on(pdev); */ } diff -u --recursive --new-file v2.4.2/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.4.2/linux/drivers/net/eql.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/eql.c Tue Mar 20 12:05:01 2001 @@ -197,7 +197,7 @@ static int __init eql_init(struct net_device *dev) { - static unsigned version_printed = 0; + static unsigned version_printed; /* static unsigned num_masters = 0; */ equalizer_t *eql = 0; @@ -721,6 +721,9 @@ static int eql_insert_slave(slave_queue_t *queue, slave_t *slave) { + unsigned long flags; + + save_flags(flags); cli (); if ( ! eql_is_full (queue) ) @@ -736,10 +739,10 @@ slave->next = queue->head->next; queue->head->next = slave; queue->num_slaves++; - sti (); + restore_flags(flags); return 0; } - sti (); + restore_flags(flags); return 1; } @@ -748,7 +751,9 @@ { slave_t *prev; slave_t *curr; + unsigned long flags; + save_flags(flags); cli (); prev = queue->head; @@ -766,10 +771,10 @@ prev->next = curr->next; queue->num_slaves--; curr->dev->flags = curr->dev->flags & ~IFF_SLAVE; - sti(); + restore_flags(flags); return curr; } - sti (); + restore_flags(flags); return 0; /* not found */ } @@ -784,6 +789,9 @@ if (target != 0) { + unsigned long flags; + + save_flags(flags); cli (); prev = queue->head; curr = prev->next; @@ -794,7 +802,7 @@ } prev->next = curr->next; queue->num_slaves--; - sti (); + restore_flags(flags); eql_delete_slave (curr); return 0; } @@ -847,8 +855,10 @@ */ unsigned long best_load = (unsigned long) ULONG_MAX; slave_t *slave = 0; + unsigned long flags; int i; + save_flags(flags); cli (); for (i = 1, slave = eql_first_slave (queue); i <= eql_number_slaves (queue); @@ -895,7 +905,7 @@ } } } /* for */ - sti (); + restore_flags(flags); eql_set_best_slave (queue, best_slave); } /* else */ if (slave_corpse != 0) @@ -948,9 +958,11 @@ slave_t *slave; slave_t *slave_corpse = 0; int i; + unsigned long flags; if ( ! eql_is_empty (eql->queue) ) { + save_flags(flags); cli (); for (i = 1, slave = eql_first_slave (eql->queue); i <= eql_number_slaves (eql->queue); @@ -968,7 +980,7 @@ slave_corpse = slave; } } - sti (); + restore_flags(flags); if (slave_corpse != 0) { printk ("eql: timer found dead slave, burying...\n"); 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/fc/iph5526.c linux/drivers/net/fc/iph5526.c --- v2.4.2/linux/drivers/net/fc/iph5526.c Wed Feb 21 18:20:26 2001 +++ linux/drivers/net/fc/iph5526.c Tue Mar 20 12:05:00 2001 @@ -1074,11 +1074,11 @@ fi->fc_stats.rx_dropped++; fi->g.mfs_buffer_count += no_of_buffers; if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) { - int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES; + int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES; fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count; update_MFSBQ_indx(fi, count); - return; } + return; } if (wrap_around) { int wrap_size = no_of_wrap_buffs * MFS_BUFFER_SIZE; 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 Sun Mar 25 18:24:31 2001 @@ -129,7 +129,6 @@ * Enable mii_ioctl. Added interrupt coalescing parameter adjustment. * 2/19/99 Pete Wyckoff */ -#define HAVE_PRIVATE_IOCTL /* play with 64-bit addrlen; seems to be a teensy bit slower --pw */ /* #define ADDRLEN 64 */ @@ -477,6 +476,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 +503,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 */ @@ -531,9 +531,7 @@ 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 hamachi_open(struct net_device *dev); -#ifdef HAVE_PRIVATE_IOCTL static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif static void hamachi_timer(unsigned long data); static void hamachi_tx_timeout(struct net_device *dev); static void hamachi_init_ring(struct net_device *dev); @@ -554,7 +552,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,21 +560,29 @@ 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); + i = pci_request_regions(pdev, "hamachi"); + if (i) return i; + + irq = pdev->irq; ioaddr = (long) ioremap(ioaddr, 0x400); - if (!ioaddr) + if (!ioaddr) { + pci_release_regions(pdev); return -ENOMEM; + } - dev = init_etherdev(NULL, sizeof(struct hamachi_private)); + dev = alloc_etherdev(sizeof(struct hamachi_private)); if (!dev) { + pci_release_regions(pdev); iounmap((char *)ioaddr); return -ENOMEM; } @@ -587,16 +593,9 @@ dev->hard_header_len += 8; /* for cksum tag */ #endif - printk(KERN_INFO "%s: %s type %x at 0x%lx, ", - dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), - ioaddr); - for (i = 0; i < 6; i++) dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + 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); #if ! defined(final_version) if (hamachi_debug > 4) @@ -605,15 +604,6 @@ read_eeprom(ioaddr, i), i % 16 != 15 ? " " : "\n"); #endif -#if 0 /* Moving this until after the force 32 check and reset. */ - i = readb(ioaddr + PCIClkMeas); - printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " - "%2.2x, LPA %4.4x.\n", - dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, - i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), - readw(ioaddr + ANLinkPartnerAbility)); -#endif - hmp = dev->priv; spin_lock_init(&hmp->lock); @@ -642,12 +632,6 @@ i = readb(ioaddr + PCIClkMeas); } - printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " - "%2.2x, LPA %4.4x.\n", - dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, - i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), - readw(ioaddr + ANLinkPartnerAbility)); - dev->base_addr = ioaddr; dev->irq = irq; @@ -693,17 +677,36 @@ dev->stop = &hamachi_close; dev->get_stats = &hamachi_get_stats; dev->set_multicast_list = &set_rx_mode; -#ifdef HAVE_PRIVATE_IOCTL dev->do_ioctl = &mii_ioctl; -#endif dev->tx_timeout = &hamachi_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) dev->mtu = mtu; + i = register_netdev(dev); + if (i) { + kfree(dev); + iounmap((char *)ioaddr); + pci_release_regions(pdev); + return i; + } + + printk(KERN_INFO "%s: %s type %x at 0x%lx, ", + dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), + ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + i = readb(ioaddr + PCIClkMeas); + printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " + "%2.2x, LPA %4.4x.\n", + dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, + i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), + readw(ioaddr + ANLinkPartnerAbility)); + 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) { @@ -782,7 +785,7 @@ static int hamachi_open(struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; int i; u_int32_t rx_int_var, tx_int_var; @@ -930,7 +933,7 @@ static inline int hamachi_tx(struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; /* Update the dirty pointer until we find an entry that is still owned by the card */ @@ -956,7 +959,7 @@ static void hamachi_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; int next_tick = 10*HZ; @@ -981,7 +984,7 @@ static void hamachi_tx_timeout(struct net_device *dev) { int i; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," @@ -1063,7 +1066,6 @@ /* 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; hmp->stats.tx_errors++; @@ -1072,13 +1074,15 @@ writew(0x0002, dev->base_addr + TxCmd); /* STOP Tx */ writew(0x0001, dev->base_addr + TxCmd); /* START Tx */ writew(0x0001, dev->base_addr + RxCmd); /* START Rx */ + + netif_wake_queue(dev); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void hamachi_init_ring(struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; int i; hmp->tx_full = 0; @@ -1176,7 +1180,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; unsigned entry; u16 status; @@ -1290,7 +1294,7 @@ after the Tx thread. */ static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { - struct net_device *dev = (struct net_device *)dev_instance; + struct net_device *dev = dev_instance; struct hamachi_private *hmp; long ioaddr, boguscnt = max_interrupt_work; @@ -1302,7 +1306,7 @@ #endif ioaddr = dev->base_addr; - hmp = (struct hamachi_private *)dev->priv; + hmp = dev->priv; spin_lock(&hmp->lock); do { @@ -1444,7 +1448,7 @@ for clarity and better register allocation. */ static int hamachi_rx(struct net_device *dev) { - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; int entry = hmp->cur_rx % RX_RING_SIZE; int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx; @@ -1651,7 +1655,7 @@ static void hamachi_error(struct net_device *dev, int intr_status) { long ioaddr = dev->base_addr; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; if (intr_status & (LinkChange|NegotiationChange)) { if (hamachi_debug > 1) @@ -1685,7 +1689,7 @@ static int hamachi_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; int i; netif_stop_queue(dev); @@ -1758,7 +1762,7 @@ static struct net_device_stats *hamachi_get_stats(struct net_device *dev) { long ioaddr = dev->base_addr; - struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + struct hamachi_private *hmp = dev->priv; /* We should lock this segment of code for SMP eventually, although the vulnerability window is very small and statistics are @@ -1812,7 +1816,6 @@ } } -#ifdef HAVE_PRIVATE_IOCTL static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { long ioaddr = dev->base_addr; @@ -1853,7 +1856,6 @@ return -EOPNOTSUPP; } } -#endif /* HAVE_PRIVATE_IOCTL */ static void __exit hamachi_remove_one (struct pci_dev *pdev) @@ -1865,6 +1867,7 @@ unregister_netdev(dev); iounmap((char *)dev->base_addr); kfree(dev); + pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); } } 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 20 12:05:00 2001 @@ -582,7 +582,7 @@ if (skb != NULL) dev_kfree_skb_irq(skb); - scc->rx_buff = NULL; + scc->rx_buff = skb = NULL; } if(status & END_FR && skb != NULL) /* end of frame */ @@ -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/hamradio/soundmodem/gentbl.c linux/drivers/net/hamradio/soundmodem/gentbl.c --- v2.4.2/linux/drivers/net/hamradio/soundmodem/gentbl.c Thu Jun 25 12:25:16 1998 +++ linux/drivers/net/hamradio/soundmodem/gentbl.c Tue Mar 20 12:04:59 2001 @@ -26,6 +26,7 @@ */ #include +#include #include #include 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 Tue Mar 20 12:04:58 2001 @@ -67,11 +67,16 @@ #include #include -/* 32 RX buffers. This is tunable in the range of 16 <= x < 512. */ +/* + * 32 RX buffers. This is tunable in the range of 16 <= x < 512. The + * value must be a power of two. + */ #define RX_BUFFS 64 -/* Private ioctls that de facto are well known and used for examply - by mii-tool. */ +/* + * Private ioctls that de facto are well known and used for examply + * by mii-tool. + */ #define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Read from current PHY */ #define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read any PHY register */ #define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write any PHY register */ @@ -707,8 +712,10 @@ if (ip->rxr == NULL) { /* Allocate and initialize rx ring. 4kb = 512 entries */ - ip->rxr = (unsigned long *) get_free_page(GFP_KERNEL|GFP_ATOMIC); + ip->rxr = (unsigned long *) get_free_page(GFP_ATOMIC); rxr = (unsigned long *) ip->rxr; + if (!rxr) + printk("ioc3_alloc_rings(): get_free_page() failed!\n"); /* Now the rx buffers. The RX ring may be larger but we only allocate 16 buffers for now. Need to tune @@ -738,7 +745,9 @@ if (ip->txr == NULL) { /* Allocate and initialize tx rings. 16kb = 128 bufs. */ - ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL|GFP_ATOMIC, 2); + ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2); + if (!ip->txr) + printk("ioc3_alloc_rings(): get_free_page() failed!\n"); ip->tx_pi = 0; ip->tx_ci = 0; } @@ -862,9 +871,6 @@ ioc3_init(dev); netif_start_queue(dev); - - MOD_INC_USE_COUNT; - return 0; } @@ -880,27 +886,26 @@ free_irq(dev->irq, dev); ioc3_free_rings(ip); - - MOD_DEC_USE_COUNT; - return 0; } -static int ioc3_pci_init(struct pci_dev *pdev) +static int __devinit ioc3_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { u16 mii0, mii_status, mii2, mii3, mii4; - struct net_device *dev = NULL; // XXX + struct net_device *dev = NULL; struct ioc3_private *ip; 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 +921,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 +940,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,34 +974,42 @@ 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 void __devexit eepro100_remove_one (struct pci_dev *pdev) { - static int called = 0; - int cards = 0; - - if (called) - return -ENODEV; - called = 1; + /* Later ... */ +} - if (pci_present()) { - struct pci_dev *pdev = NULL; +static struct pci_device_id ioc3_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ioc3_pci_tbl); - while ((pdev = pci_find_device(PCI_VENDOR_ID_SGI, - PCI_DEVICE_ID_SGI_IOC3, pdev))) { - if (ioc3_pci_init(pdev)) - return -ENOMEM; - cards++; - } - } +static struct pci_driver ioc3_driver = { + name: "ioc3-eth", + id_table: ioc3_pci_tbl, + probe: ioc3_probe, + /* remove: ioc3_remove_one, */ +}; - return cards ? -ENODEV : 0; +static int __init ioc3_init_module(void) +{ + return pci_module_init(&ioc3_driver); } static void __exit ioc3_cleanup_module(void) { - /* Later, when we really support modules. */ + pci_unregister_driver(&ioc3_driver); } static int @@ -1192,10 +1207,8 @@ } } -#ifdef MODULE MODULE_AUTHOR("Ralf Baechle "); MODULE_DESCRIPTION("SGI IOC3 Ethernet driver"); -#endif /* MODULE */ -module_init(ioc3_probe); +module_init(ioc3_init_module); module_exit(ioc3_cleanup_module); diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c --- v2.4.2/linux/drivers/net/irda/irport.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/irda/irport.c Tue Mar 20 12:04:59 2001 @@ -609,7 +609,7 @@ * * Transmits the current frame until FIFO is full, then * waits until the next transmitt interrupt, and continues until the - * frame is transmited. + * frame is transmitted. */ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1008,7 +1008,7 @@ #ifdef MODULE MODULE_PARM(io, "1-4i"); -MODULE_PARM_DESC(io, "Base I/O adresses"); +MODULE_PARM_DESC(io, "Base I/O addresses"); MODULE_PARM(irq, "1-4i"); MODULE_PARM_DESC(irq, "IRQ lines"); diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c --- v2.4.2/linux/drivers/net/irda/irtty.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/irda/irtty.c Tue Mar 20 12:04:59 2001 @@ -824,7 +824,7 @@ /* * Function irtty_raw_read (self, buf, len) * - * Receive incomming data. This function sleeps, so it must only be + * Receive incoming data. This function sleeps, so it must only be * called with a process context. Timeout is currently defined to be * a multiple of 10 ms. */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c --- v2.4.2/linux/drivers/net/irda/nsc-ircc.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/irda/nsc-ircc.c Tue Mar 20 12:04:59 2001 @@ -1263,7 +1263,7 @@ * Function nsc_ircc_pio_xmit (self, iobase) * * Transmit data using PIO. Returns the number of bytes that actually - * got transfered + * got transferred * */ static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c --- v2.4.2/linux/drivers/net/irda/smc-ircc.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/irda/smc-ircc.c Tue Mar 20 12:04:59 2001 @@ -560,7 +560,7 @@ */ /* outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); */ - /* Be ready for incomming frames */ + /* Be ready for incoming frames */ ircc_dma_receive(self, iobase); } else { /* Install SIR transmit handler */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c --- v2.4.2/linux/drivers/net/irda/w83977af_ir.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/irda/w83977af_ir.c Tue Mar 20 12:04:59 2001 @@ -875,7 +875,7 @@ self->stats.rx_fifo_errors++; } else { - /* Check if we have transfered all data to memory */ + /* Check if we have transferred all data to memory */ switch_bank(iobase, SET0); if (inb(iobase+USR) & USR_RDR) { #ifdef CONFIG_USE_INTERNAL_TIMER 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/mace.c linux/drivers/net/mace.c --- v2.4.2/linux/drivers/net/mace.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/mace.c Tue Mar 20 12:05:01 2001 @@ -87,7 +87,7 @@ /* * If we can't get a skbuff when we need it, we use this area for DMA. */ -static unsigned char dummy_buf[RX_BUFLEN+2]; +static unsigned char *dummy_buf; /* Bit-reverse one byte of an ethernet hardware address. */ static inline int @@ -106,7 +106,7 @@ for (mace = find_devices("mace"); mace != NULL; mace = mace->next) mace_probe1(mace); - return 0; + return mace_devs? 0: -ENODEV; } static void __init mace_probe1(struct device_node *mace) @@ -132,6 +132,14 @@ } } + if (dummy_buf == NULL) { + dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL); + if (dummy_buf == NULL) { + printk(KERN_ERR "MACE: couldn't allocate dummy buffer\n"); + return; + } + } + dev = init_etherdev(0, PRIV_BYTES); if (!dev) return; @@ -897,6 +905,10 @@ unregister_netdev(dev); kfree(dev); + } + if (dummy_buf != NULL) { + kfree(dummy_buf); + dummy_buf = NULL; } } 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 Sun Mar 25 18:24:31 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; @@ -316,9 +316,14 @@ if (dev) { dev = init_etherdev(dev, sizeof(struct sonic_local)); + if (!dev) + return -ENOMEM; /* methinks this will always be true but better safe than sorry */ - if (dev->priv == NULL) + if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL); + if (!dev->priv) /* FIXME: kfree dev if necessary */ + return -ENOMEM; + } } else { dev = init_etherdev(NULL, sizeof(struct sonic_local)); } @@ -438,7 +443,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 +572,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/natsemi.c linux/drivers/net/natsemi.c --- v2.4.2/linux/drivers/net/natsemi.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/natsemi.c Sun Mar 25 18:24:31 2001 @@ -1,6 +1,6 @@ -/* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP83810 series. */ +/* natsemi.c: A Linux PCI Ethernet driver for the NatSemi DP8381x series. */ /* - Written/copyright 1999-2000 by Donald Becker. + Written/copyright 1999-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. @@ -31,25 +31,28 @@ - Call netif_start_queue from dev->tx_timeout - wmb() in start_tx() to flush data - Update Tx locking + - Clean up PCI enable (davej) + Version 1.0.4: + - Merge Donald Becker's natsemi.c version 1.07 */ /* These identify the driver base version and may not be removed. */ static const char version1[] = -"natsemi.c:v1.05 8/7/2000 Written by Donald Becker \n"; +"natsemi.c:v1.07 1/9/2001 Written by Donald Becker \n"; static const char version2[] = " http://www.scyld.com/network/natsemi.html\n"; static const char version3[] = -" (unofficial 2.4.x kernel port, version 1.0.3, January 21, 2001 Jeff Garzik, Tjeerd Mulder)\n"; +" (unofficial 2.4.x kernel port, version 1.0.4, February 26, 2001 Jeff Garzik, Tjeerd Mulder)\n"; /* Updated to recommendations in pci-skeleton v2.03. */ /* Automatically extracted configuration info: probe-func: natsemi_probe -config-in: tristate 'National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI +config-in: tristate 'National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI -c-help-name: National Semiconductor DP83810 series PCI Ethernet support +c-help-name: National Semiconductor DP8381x series PCI Ethernet support c-help-symbol: CONFIG_NATSEMI -c-help: This driver is for the National Semiconductor DP83810 series, +c-help: This driver is for the National Semiconductor DP8381x series, c-help: including the 83815 chip. c-help: More specific information and updates are available from c-help: http://www.scyld.com/network/natsemi.html @@ -87,7 +90,7 @@ bonding and packet priority. There are no ill effects from too-large receive rings. */ #define TX_RING_SIZE 16 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used, min 4. */ #define RX_RING_SIZE 32 /* Operational parameters that usually are not changed. */ @@ -127,7 +130,7 @@ #define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("National Semiconductor DP83810 series PCI Ethernet driver"); +MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(mtu, "i"); MODULE_PARM(debug, "i"); @@ -192,14 +195,13 @@ The send packet thread has partial control over the Tx ring and 'dev->tbusy' flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished. Under 2.4, the -"tbusy flag" is now controlled by netif_{start,stop,wake}_queue() and tested -by netif_queue_stopped(). +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. The interrupt handler has exclusive control over the Rx ring and records stats from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. Iff Tx queueing is stopped and Tx -entries were reaped, the Tx queue is started and scheduled. +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. IV. Notes @@ -258,6 +260,7 @@ WOLCmd=0x40, PauseCmd=0x44, RxFilterAddr=0x48, RxFilterData=0x4C, BootRomAddr=0x50, BootRomData=0x54, StatsCtrl=0x5C, StatsData=0x60, RxPktErrs=0x60, RxMissed=0x68, RxCRCErrs=0x64, + PCIPM = 0x44, }; /* Bit in ChipCmd. */ @@ -271,24 +274,20 @@ IntrRxDone=0x0001, IntrRxIntr=0x0002, IntrRxErr=0x0004, IntrRxEarly=0x0008, IntrRxIdle=0x0010, IntrRxOverrun=0x0020, IntrTxDone=0x0040, IntrTxIntr=0x0080, IntrTxErr=0x0100, - IntrTxIdle=0x0200, IntrTxOverrun=0x0400, + IntrTxIdle=0x0200, IntrTxUnderrun=0x0400, StatsMax=0x0800, LinkChange=0x4000, WOLPkt=0x2000, RxResetDone=0x1000000, TxResetDone=0x2000000, IntrPCIErr=0x00f00000, - IntrAbnormalSummary=0xCD20, + IntrNormalSummary=0x0251, IntrAbnormalSummary=0xED20, }; /* Bits in the RxMode register. */ enum rx_mode_bits { - EnableFilter = 0x80000000, - AcceptBroadcast = 0x40000000, - AcceptAllMulticast = 0x20000000, - AcceptAllPhys = 0x10000000, - AcceptMyPhys = 0x08000000, - AcceptMulticast = 0x00200000, - AcceptErr=0x20, /* these 2 are in another register */ - AcceptRunt=0x10,/* and are not used in this driver */ + AcceptErr=0x20, AcceptRunt=0x10, + AcceptBroadcast=0xC0000000, + AcceptMulticast=0x00200000, AcceptAllMulticast=0x20000000, + AcceptAllPhys=0x10000000, AcceptMyPhys=0x08000000, }; /* The Rx and Tx buffer descriptors. */ @@ -334,9 +333,9 @@ u32 cur_rx_mode; u32 rx_filter[16]; /* FIFO and PCI burst thresholds. */ - int tx_config, rx_config; + u32 tx_config, rx_config; /* original contents of ClkRun register */ - int SavedClkRun; + u32 SavedClkRun; /* MII transceiver section. */ u16 advertising; /* NWay media advertisement */ @@ -346,7 +345,6 @@ static int eeprom_read(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 value); static int netdev_open(struct net_device *dev); static void check_duplex(struct net_device *dev); static void netdev_timer(unsigned long data); @@ -368,68 +366,70 @@ { struct net_device *dev; struct netdev_private *np; - int i, option, irq = pdev->irq, chip_idx = ent->driver_data; + int i, option, irq, chip_idx = ent->driver_data; static int find_cnt = -1; static int printed_version; unsigned long ioaddr, iosize; const int pcibar = 1; /* PCI base address register */ + int prev_eedata; + u32 tmp; if ((debug <= 1) && !printed_version++) printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s", version1, version2, version3); + i = pci_enable_device(pdev); + if (i) return i; + + /* natsemi has a non-standard PM control register + * in PCI config space. Some boards apparently need + * to be brought to D0 in this manner. + */ + pci_read_config_dword(pdev, PCIPM, &tmp); + if (tmp & (0x03|0x100)) { + /* D0 state, disable PME assertion */ + u32 newtmp = tmp & ~(0x03|0x100); + pci_write_config_dword(pdev, PCIPM, newtmp); + } + find_cnt++; option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; ioaddr = pci_resource_start(pdev, pcibar); iosize = pci_resource_len(pdev, pcibar); - - if (pci_enable_device(pdev)) - return -EIO; + irq = pdev->irq; + if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER) pci_set_master(pdev); - dev = init_etherdev(NULL, sizeof (struct netdev_private)); + dev = alloc_etherdev(sizeof (struct netdev_private)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); + i = pci_request_regions(pdev, dev->name); + if (i) { + kfree(dev); + return i; + } + { - void *mmio; - if (request_mem_region(ioaddr, iosize, dev->name) == NULL) { - unregister_netdev(dev); - kfree(dev); - return -EBUSY; - } - mmio = ioremap (ioaddr, iosize); + void *mmio = ioremap (ioaddr, iosize); if (!mmio) { - release_mem_region(ioaddr, iosize); - unregister_netdev(dev); + pci_release_regions(pdev); kfree(dev); return -ENOMEM; } ioaddr = (unsigned long) mmio; } - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, natsemi_pci_info[chip_idx].name, ioaddr); - - for (i = 0; i < ETH_ALEN/2; i++) { - /* weird organization */ - unsigned short a; - a = (le16_to_cpu(eeprom_read(ioaddr, i + 6)) >> 15) + - (le16_to_cpu(eeprom_read(ioaddr, i + 7)) << 1); - ((u16 *)dev->dev_addr)[i] = a; + /* Work around the dropped serial bit. */ + prev_eedata = eeprom_read(ioaddr, 6); + for (i = 0; i < 3; i++) { + int eedata = eeprom_read(ioaddr, i + 7); + dev->dev_addr[i*2] = (eedata << 1) + (prev_eedata >> 15); + dev->dev_addr[i*2+1] = eedata >> 7; + prev_eedata = eedata; } - for (i = 0; i < ETH_ALEN-1; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); - -#if ! defined(final_version) /* Dump the EEPROM contents during development. */ - if (debug > 4) - for (i = 0; i < 64; i++) - printk("%4.4x%s", - eeprom_read(ioaddr, i), i % 16 != 15 ? " " : "\n"); -#endif /* Reset the chip to erase previous misconfiguration. */ writel(ChipReset, ioaddr + ChipCmd); @@ -440,7 +440,7 @@ np = dev->priv; np->pci_dev = pdev; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); np->iosize = iosize; spin_lock_init(&np->lock); @@ -474,7 +474,31 @@ if (mtu) dev->mtu = mtu; - np->advertising = readl(ioaddr + 0x90); + i = register_netdev(dev); + if (i) { + pci_release_regions(pdev); + unregister_netdev(dev); + kfree(dev); + pci_set_drvdata(pdev, NULL); + return i; + } + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, natsemi_pci_info[chip_idx].name, ioaddr); + for (i = 0; i < ETH_ALEN-1; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + np->advertising = mdio_read(dev, 1, 4); + if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) { + u32 chip_config = readl(ioaddr + ChipConfig); + printk(KERN_INFO "%s: Transceiver default autonegotiation %s " + "10%s %s duplex.\n", + dev->name, + chip_config & 0x2000 ? "enabled, advertise" : "disabled, force", + chip_config & 0x4000 ? "0" : "", + chip_config & 0x8000 ? "full" : "half"); + } printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n", dev->name, (int)readl(ioaddr + 0x84), np->advertising); @@ -522,12 +546,12 @@ eeprom_delay(ee_addr); } writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); - for (i = 16; i > 0; i--) { + for (i = 0; i < 16; i++) { writel(EE_ChipSelect | EE_ShiftClk, ee_addr); eeprom_delay(ee_addr); - /* data bits are LSB first */ - retval = (retval >> 1) | ((readl(ee_addr) & EE_DataOut) ? 0x8000 : 0); + retval |= (readl(ee_addr) & EE_DataOut) ? 1 << i : 0; writel(EE_ChipSelect, ee_addr); eeprom_delay(ee_addr); } @@ -550,16 +574,10 @@ return 0xffff; } -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - if (phy_id == 1 && location < 32) - writew(value, dev->base_addr + 0x80 + (location<<2)); -} - 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; @@ -586,20 +604,26 @@ /* Initialize other registers. */ /* Configure the PCI bus bursts and FIFO thresholds. */ /* Configure for standard, in-spec Ethernet. */ - np->tx_config = (1<<28) + /* Automatic transmit padding */ - (1<<23) + /* Excessive collision retry */ - (0x0<<20) + /* Max DMA burst = 512 byte */ - (8<<8) + /* fill threshold = 256 byte */ - 2; /* drain threshold = 64 byte */ + + if (readl(ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ + np->tx_config = 0xD0801002; + np->rx_config = 0x10000020; + } else { + np->tx_config = 0x10801002; + np->rx_config = 0x0020; + } writel(np->tx_config, ioaddr + TxConfig); - np->rx_config = (0x0<<20) /* Max DMA burst = 512 byte */ + - (0x8<<1); /* Drain Threshold = 64 byte */ writel(np->rx_config, ioaddr + RxConfig); if (dev->if_port == 0) dev->if_port = np->default_port; - /* Disable PME */ + /* Disable PME: + * The PME bit is initialized from the EEPROM contents. + * PCI cards probably have PME disabled, but motherboard + * implementations may have PME set to enable WakeOnLan. + * With PME set the chip will scan incoming packets but + * nothing will be written to memory. */ np->SavedClkRun = readl(ioaddr + ClkRun); writel(np->SavedClkRun & ~0x100, ioaddr + ClkRun); @@ -608,10 +632,8 @@ check_duplex(dev); set_rx_mode(dev); - /* Enable interrupts by setting the interrupt mask. - * We don't listen for TxDone interrupts and rely on TxIdle. */ - writel(IntrAbnormalSummary | IntrTxIdle | IntrRxIdle | IntrRxDone, - ioaddr + IntrMask); + /* Enable interrupts by setting the interrupt mask. */ + writel(IntrNormalSummary | IntrAbnormalSummary | 0x1f, ioaddr + IntrMask); writel(1, ioaddr + IntrEnable); writel(RxOn | TxOn, ioaddr + ChipCmd); @@ -633,7 +655,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 duplex; @@ -661,7 +683,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 = 60*HZ; @@ -675,7 +697,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," @@ -702,14 +724,14 @@ dev->trans_start = jiffies; np->stats.tx_errors++; - netif_start_queue(dev); + 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->cur_rx = np->cur_tx = 0; @@ -736,7 +758,7 @@ skb->dev = dev; /* Mark as being used by this device. */ np->rx_ring[i].addr = virt_to_le32desc(skb->tail); np->rx_ring[i].cmd_status = - cpu_to_le32(np->rx_buf_sz); + cpu_to_le32(DescIntr | np->rx_buf_sz); } np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -751,7 +773,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; /* Note: Ordering is important here, set the field with the @@ -763,7 +785,7 @@ np->tx_skbuff[entry] = skb; np->tx_ring[entry].addr = virt_to_le32desc(skb->data); - np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len); + np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn|DescIntr | skb->len); np->cur_tx++; /* StrongARM: Explicitly cache flush np->tx_ring and skb->data,skb->len. */ @@ -819,7 +841,7 @@ if (intr_status == 0) break; - if (intr_status & (IntrRxDone | IntrRxErr | IntrRxIdle | IntrRxOverrun)) + if (intr_status & (IntrRxDone | IntrRxIntr)) netdev_rx(dev); spin_lock(&np->lock); @@ -886,7 +908,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; s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); @@ -898,7 +920,6 @@ entry, desc_status); if (--boguscnt < 0) break; - if ((desc_status & (DescMore|DescPktOK|RxTooLong)) != DescPktOK) { if (desc_status & DescMore) { printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned " @@ -984,7 +1005,7 @@ np->rx_ring[entry].addr = virt_to_le32desc(skb->tail); } np->rx_ring[entry].cmd_status = - cpu_to_le32(np->rx_buf_sz); + cpu_to_le32(DescIntr | np->rx_buf_sz); } /* Restart Rx engine if stopped. */ @@ -994,7 +1015,7 @@ static void netdev_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; if (intr_status & LinkChange) { @@ -1006,7 +1027,17 @@ if (intr_status & StatsMax) { get_stats(dev); } - if ((intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|0x83ff)) + if (intr_status & IntrTxUnderrun) { + if ((np->tx_config & 0x3f) < 62) + np->tx_config += 2; + writel(np->tx_config, ioaddr + TxConfig); + } + if (intr_status & WOLPkt) { + int wol_status = readl(ioaddr + WOLCmd); + printk(KERN_NOTICE "%s: Link wake-up event %8.8x", + dev->name, wol_status); + } + if ((intr_status & ~(LinkChange|StatsMax|RxResetDone|TxResetDone|0xA7ff)) && debug) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); @@ -1020,7 +1051,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; /* We should lock this segment of code for SMP eventually, although the vulnerability window is very small and statistics are @@ -1061,8 +1092,8 @@ static void set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; - struct netdev_private *np = (struct netdev_private *)dev->priv; - u16 mc_filter[32]; /* Multicast hash filter */ + struct netdev_private *np = dev->priv; + u8 mc_filter[64]; /* Multicast hash filter */ u32 rx_mode; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ @@ -1082,18 +1113,19 @@ set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, mc_filter); } - for (i = 0; i < 32; i++) { - writew(0x200 + (i<<1), ioaddr + RxFilterAddr); - writew(cpu_to_be16(mc_filter[i]), ioaddr + RxFilterData); - } rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + for (i = 0; i < 64; i += 2) { + writew(0x200 + i, ioaddr + RxFilterAddr); + writew((mc_filter[i+1]<<8) + mc_filter[i], ioaddr + RxFilterData); + } } - writel(rx_mode | EnableFilter, ioaddr + RxFilterAddr); + writel(rx_mode, ioaddr + RxFilterAddr); np->cur_rx_mode = rx_mode; } static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { + struct netdev_private *np = dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { @@ -1106,7 +1138,20 @@ case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!capable(CAP_NET_ADMIN)) return -EPERM; - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + if (data[0] == 1) { + u16 miireg = data[1] & 0x1f; + u16 value = data[2]; + writew(value, dev->base_addr + 0x80 + (miireg << 2)); + switch (miireg) { + case 0: + /* Check for autonegotiation on or reset. */ + np->duplex_lock = (value & 0x9000) ? 0 : 1; + if (np->duplex_lock) + np->full_duplex = (value & 0x0100) ? 1 : 0; + break; + case 4: np->advertising = value; break; + } + } return 0; default: return -EOPNOTSUPP; @@ -1116,7 +1161,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); @@ -1187,14 +1232,13 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; - struct netdev_private *np = (struct netdev_private *)dev->priv; - const int pcibar = 1; /* PCI base address register */ + struct net_device *dev = pci_get_drvdata(pdev); unregister_netdev (dev); - release_mem_region(pci_resource_start(pdev, pcibar), np->iosize); + pci_release_regions (pdev); iounmap ((char *) dev->base_addr); kfree (dev); + pci_set_drvdata(pdev, NULL); } static struct pci_driver natsemi_driver = { 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/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.4.2/linux/drivers/net/ne2k-pci.c Wed Feb 21 18:20:27 2001 +++ linux/drivers/net/ne2k-pci.c Sun Mar 25 18:24:31 2001 @@ -239,7 +239,7 @@ } } - dev = init_etherdev(NULL, 0); + dev = alloc_etherdev(0); if (!dev) { printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n"); goto err_out_free_res; @@ -312,17 +312,11 @@ /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { - printk (KERN_ERR "%s: unable to get memory for dev->priv.\n", dev->name); + printk (KERN_ERR "ne2kpci(%s): unable to get memory for dev->priv.\n", + pdev->slot_name); goto err_out_free_netdev; } - printk("%s: %s found at %#lx, IRQ %d, ", - dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); - for(i = 0; i < 6; i++) { - printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); - dev->dev_addr[i] = SA_prom[i]; - } - ei_status.name = pci_clone_list[chip_idx].name; ei_status.tx_start_page = start_page; ei_status.stop_page = stop_page; @@ -346,13 +340,27 @@ dev->open = &ne2k_pci_open; dev->stop = &ne2k_pci_close; NS8390_init(dev, 0); + + i = register_netdev(dev); + if (i) + goto err_out_free_8390; + + printk("%s: %s found at %#lx, IRQ %d, ", + dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq); + for(i = 0; i < 6; i++) { + printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":"); + dev->dev_addr[i] = SA_prom[i]; + } + return 0; +err_out_free_8390: + kfree(dev->priv); err_out_free_netdev: - unregister_netdev (dev); kfree (dev); err_out_free_res: release_region (ioaddr, NE_IO_EXTENT); + pci_set_drvdata (pdev, NULL); return -ENODEV; } 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 Sun Mar 25 18:24:31 2001 @@ -28,10 +28,12 @@ up. We now share common code and have regularised name allocation setups. Abolished the 16 card limits. 03/19/2000 - jgarzik and Urban Widmark: init_etherdev 32-byte align + 03/21/2001 - jgarzik: alloc_etherdev and friends */ #include +#include #include #include #include @@ -68,6 +70,33 @@ */ +static struct net_device *alloc_netdev(int sizeof_priv, const char *mask, + void (*setup)(struct net_device *)) +{ + struct net_device *dev; + int alloc_size; + + /* ensure 32-byte alignment of the private area */ + alloc_size = sizeof (*dev) + sizeof_priv + 31; + + dev = (struct net_device *) kmalloc (alloc_size, GFP_KERNEL); + if (dev == NULL) + { + printk(KERN_ERR "alloc_dev: Unable to allocate device memory.\n"); + return NULL; + } + + memset(dev, 0, alloc_size); + + if (sizeof_priv) + dev->priv = (void *) (((long)(dev + 1) + 31) & ~31); + + setup(dev); + strcpy(dev->name, mask); + + return dev; +} + static struct net_device *init_alloc_dev(int sizeof_priv) { struct net_device *dev; @@ -142,6 +171,17 @@ return dev; } +static int __register_netdev(struct net_device *dev) +{ + dev_init_buffers(dev); + + if (dev->init && dev->init(dev) != 0) { + unregister_netdev(dev); + return -EIO; + } + return 0; +} + /** * init_etherdev - Register ethernet device * @dev: An ethernet device structure to be filled in, or %NULL if a new @@ -164,6 +204,25 @@ return init_netdev(dev, sizeof_priv, "eth%d", ether_setup); } +/** + * alloc_etherdev - Register ethernet device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with ethernet-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_etherdev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "eth%d", ether_setup); +} + +EXPORT_SYMBOL(init_etherdev); +EXPORT_SYMBOL(alloc_etherdev); static int eth_mac_addr(struct net_device *dev, void *p) { @@ -184,11 +243,48 @@ #ifdef CONFIG_FDDI +/** + * init_fddidev - Register FDDI device + * @dev: A FDDI device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with FDDI-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. + */ + struct net_device *init_fddidev(struct net_device *dev, int sizeof_priv) { return init_netdev(dev, sizeof_priv, "fddi%d", fddi_setup); } +/** + * alloc_fddidev - Register FDDI device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this FDDI device + * + * Fill in the fields of the device structure with FDDI-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_fddidev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup); +} + +EXPORT_SYMBOL(init_fddidev); +EXPORT_SYMBOL(alloc_fddidev); + static int fddi_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN)) @@ -227,19 +323,59 @@ } +/** + * init_hippi_dev - Register HIPPI device + * @dev: A HIPPI device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with HIPPI-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. + */ + struct net_device *init_hippi_dev(struct net_device *dev, int sizeof_priv) { return init_netdev(dev, sizeof_priv, "hip%d", hippi_setup); } +/** + * alloc_hippi_dev - Register HIPPI device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this HIPPI device + * + * Fill in the fields of the device structure with HIPPI-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_hippi_dev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "hip%d", hippi_setup); +} + +int register_hipdev(struct net_device *dev) +{ + return __register_netdev(dev); +} void unregister_hipdev(struct net_device *dev) { - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); + unregister_netdev(dev); } +EXPORT_SYMBOL(init_hippi_dev); +EXPORT_SYMBOL(alloc_hippi_dev); +EXPORT_SYMBOL(register_hipdev); +EXPORT_SYMBOL(unregister_hipdev); static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) { @@ -283,6 +419,7 @@ dev_init_buffers(dev); } +EXPORT_SYMBOL(ether_setup); #ifdef CONFIG_FDDI @@ -312,6 +449,7 @@ return; } +EXPORT_SYMBOL(fddi_setup); #endif /* CONFIG_FDDI */ @@ -349,6 +487,7 @@ dev_init_buffers(dev); } +EXPORT_SYMBOL(hippi_setup); #endif /* CONFIG_HIPPI */ #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) @@ -387,26 +526,10 @@ dev_init_buffers(dev); } +EXPORT_SYMBOL(ltalk_setup); #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; @@ -420,8 +543,8 @@ if (strchr(dev->name, '%')) { - err = -EBUSY; - if(dev_alloc_name(dev, dev->name)<0) + err = dev_alloc_name(dev, dev->name); + if (err < 0) goto out; } @@ -431,17 +554,12 @@ if (dev->name[0]==0 || dev->name[0]==' ') { - err = -EBUSY; - if(dev_alloc_name(dev, "eth%d")<0) + err = dev_alloc_name(dev, "eth%d"); + if (err < 0) goto out; } - - - err = -EIO; - if (register_netdevice(dev)) - goto out; - err = 0; + err = register_netdevice(dev); out: rtnl_unlock(); @@ -455,10 +573,12 @@ rtnl_unlock(); } +EXPORT_SYMBOL(register_netdev); +EXPORT_SYMBOL(unregister_netdev); #ifdef CONFIG_TR -static void tr_configure(struct net_device *dev) +void tr_setup(struct net_device *dev) { /* * Configure and register @@ -479,32 +599,61 @@ dev->flags = IFF_BROADCAST | IFF_MULTICAST ; } +/** + * init_trdev - Register token ring device + * @dev: A token ring device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with token ring-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. + */ + struct net_device *init_trdev(struct net_device *dev, int sizeof_priv) { - return init_netdev(dev, sizeof_priv, "tr%d", tr_configure); + return init_netdev(dev, sizeof_priv, "tr%d", tr_setup); } -void tr_setup(struct net_device *dev) +/** + * alloc_trdev - Register token ring device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this token ring device + * + * Fill in the fields of the device structure with token ring-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_trdev(int sizeof_priv) { + return alloc_netdev(sizeof_priv, "tr%d", tr_setup); } int register_trdev(struct net_device *dev) { - dev_init_buffers(dev); - - if (dev->init && dev->init(dev) != 0) { - unregister_trdev(dev); - return -EIO; - } - return 0; + return __register_netdev(dev); } void unregister_trdev(struct net_device *dev) { - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); + unregister_netdev(dev); } + +EXPORT_SYMBOL(tr_setup); +EXPORT_SYMBOL(init_trdev); +EXPORT_SYMBOL(alloc_trdev); +EXPORT_SYMBOL(register_trdev); +EXPORT_SYMBOL(unregister_trdev); + #endif /* CONFIG_TR */ @@ -526,31 +675,62 @@ /* New-style flags. */ dev->flags = IFF_BROADCAST; dev_init_buffers(dev); - return; } +/** + * init_fcdev - Register fibre channel device + * @dev: A fibre channel device structure to be filled in, or %NULL if a new + * struct should be allocated. + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this ethernet device + * + * Fill in the fields of the device structure with fibre channel-generic values. + * + * If no device structure is passed, a new one is constructed, complete with + * a private data area of size @sizeof_priv. A 32-byte (not bit) + * alignment is enforced for this private data area. + * + * If an empty string area is passed as dev->name, or a new structure is made, + * a new name string is constructed. + */ struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv) { return init_netdev(dev, sizeof_priv, "fc%d", fc_setup); } +/** + * alloc_fcdev - Register fibre channel device + * @sizeof_priv: Size of additional driver-private structure to be allocated + * for this fibre channel device + * + * Fill in the fields of the device structure with fibre channel-generic values. + * + * Constructs a new net device, complete with a private data area of + * size @sizeof_priv. A 32-byte (not bit) alignment is enforced for + * this private data area. + */ + +struct net_device *alloc_fcdev(int sizeof_priv) +{ + return alloc_netdev(sizeof_priv, "fc%d", fc_setup); +} + int register_fcdev(struct net_device *dev) { - dev_init_buffers(dev); - if (dev->init && dev->init(dev) != 0) { - unregister_fcdev(dev); - return -EIO; - } - return 0; + return __register_netdev(dev); } void unregister_fcdev(struct net_device *dev) { - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); + unregister_netdev(dev); } + +EXPORT_SYMBOL(fc_setup); +EXPORT_SYMBOL(init_fcdev); +EXPORT_SYMBOL(alloc_fcdev); +EXPORT_SYMBOL(register_fcdev); +EXPORT_SYMBOL(unregister_fcdev); #endif /* CONFIG_NET_FC */ 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 Sun Mar 25 18:24:31 2001 @@ -504,7 +504,7 @@ static void netdrv_interrupt (int irq, void *dev_instance, struct pt_regs *regs); static int netdrv_close (struct net_device *dev); -static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *netdrv_get_stats (struct net_device *dev); static inline u32 ether_crc (int length, unsigned char *data); static void netdrv_set_rx_mode (struct net_device *dev); @@ -600,7 +600,7 @@ *dev_out = NULL; /* dev zeroed in init_etherdev */ - dev = init_etherdev (NULL, sizeof (*tp)); + dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { printk (KERN_ERR PFX "unable to alloc new ethernet\n"); DPRINTK ("EXIT, returning -ENOMEM\n"); @@ -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, "pci-skeleton"); 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--) @@ -742,22 +710,22 @@ tp->chipset, rtl_chip_info[tp->chipset].name); + i = register_netdev (dev); + if (i) + goto err_out_unmap; + DPRINTK ("EXIT, returning 0\n"); *ioaddr_out = ioaddr; *dev_out = dev; return 0; -err_out_iounmap: - assert (ioaddr > 0); +err_out_unmap: #ifndef USE_IO_OPS - iounmap (ioaddr); -#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); + iounmap(ioaddr); +err_out_free_res: +#endif + pci_release_regions (pdev); err_out: - unregister_netdev (dev); kfree (dev); DPRINTK ("EXIT, returning %d\n", rc); return rc; @@ -810,7 +778,7 @@ dev->stop = netdrv_close; dev->get_stats = netdrv_get_stats; dev->set_multicast_list = netdrv_set_rx_mode; - dev->do_ioctl = mii_ioctl; + dev->do_ioctl = netdrv_ioctl; dev->tx_timeout = netdrv_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; @@ -828,7 +796,7 @@ tp->mmio_addr = ioaddr; tp->lock = SPIN_LOCK_UNLOCKED; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); tp->phys[0] = 32; @@ -849,12 +817,6 @@ /* Put the chip into low-power mode. */ NETDRV_W8_F (Cfg9346, Cfg9346_Unlock); - tmp = NETDRV_R8 (Config1) & Config1Clear; - tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ - NETDRV_W8_F (Config1, tmp); - - NETDRV_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ - /* The lower four bits are the media type. */ option = (board_idx > 7) ? 0 : media[board_idx]; if (option > 0) { @@ -879,14 +841,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 +857,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 +868,7 @@ kfree (dev); - pdev->driver_data = NULL; + pci_set_drvdata (pdev, NULL); pci_power_off (pdev, -1); @@ -1029,7 +988,7 @@ static int mdio_read (struct net_device *dev, int phy_id, int location) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; @@ -1072,7 +1031,7 @@ static void mdio_write (struct net_device *dev, int phy_id, int location, int value) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *mdio_addr = tp->mmio_addr + Config4; int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; @@ -1115,7 +1074,7 @@ static int netdrv_open (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; int retval; #ifdef NETDRV_DEBUG void *ioaddr = tp->mmio_addr; @@ -1176,7 +1135,7 @@ /* Start the hardware at open or resume. */ static void netdrv_hw_start (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 i; u8 tmp; @@ -1213,27 +1172,6 @@ tp->cur_rx = 0; - if (tp->chipset >= CH_8139A) { - tmp = NETDRV_R8 (Config1) & Config1Clear; - tmp |= Cfg1_Driver_Load; - tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ - NETDRV_W8_F (Config1, tmp); - } else { - u8 foo = NETDRV_R8 (Config1) & Config1Clear; - NETDRV_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20)); - } - - if (tp->chipset >= CH_8139B) { - tmp = NETDRV_R8 (Config4) & ~(1<<2); - /* chip will clear Rx FIFO overflow automatically */ - tmp |= (1<<7); - NETDRV_W8 (Config4, tmp); - - /* disable magic packet scanning, which is enabled - * when PM is enabled above (Config1) */ - NETDRV_W8 (Config3, NETDRV_R8 (Config3) & ~(1<<5)); - } - /* Lock Config[01234] and BMCR register writes */ NETDRV_W8_F (Cfg9346, Cfg9346_Lock); udelay (10); @@ -1268,7 +1206,7 @@ /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void netdrv_init_ring (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; int i; DPRINTK ("ENTER\n"); @@ -1287,104 +1225,10 @@ } -#ifndef NETDRV_TUNE_TWISTER -static inline void netdrv_tune_twister (struct net_device *dev, - struct netdrv_private *tp) {} -#else -static void netdrv_tune_twister (struct net_device *dev, - struct netdrv_private *tp) -{ - int linkcase; - - DPRINTK ("ENTER\n"); - - /* This is a complicated state machine to configure the "twister" for - impedance/echos based on the cable length. - All of this is magic and undocumented. - */ - switch (tp->twistie) { - case 1: - if (NETDRV_R16 (CSCR) & CSCR_LinkOKBit) { - /* We have link beat, let us tune the twister. */ - NETDRV_W16 (CSCR, CSCR_LinkDownOffCmd); - tp->twistie = 2; /* Change to state 2. */ - next_tick = HZ / 10; - } else { - /* Just put in some reasonable defaults for when beat returns. */ - NETDRV_W16 (CSCR, CSCR_LinkDownCmd); - NETDRV_W32 (FIFOTMS, 0x20); /* Turn on cable test mode. */ - NETDRV_W32 (PARA78, PARA78_default); - NETDRV_W32 (PARA7c, PARA7c_default); - tp->twistie = 0; /* Bail from future actions. */ - } - break; - case 2: - /* Read how long it took to hear the echo. */ - linkcase = NETDRV_R16 (CSCR) & CSCR_LinkStatusBits; - if (linkcase == 0x7000) - tp->twist_row = 3; - else if (linkcase == 0x3000) - tp->twist_row = 2; - else if (linkcase == 0x1000) - tp->twist_row = 1; - else - tp->twist_row = 0; - tp->twist_col = 0; - tp->twistie = 3; /* Change to state 2. */ - next_tick = HZ / 10; - break; - case 3: - /* Put out four tuning parameters, one per 100msec. */ - if (tp->twist_col == 0) - NETDRV_W16 (FIFOTMS, 0); - NETDRV_W32 (PARA7c, param[(int) tp->twist_row] - [(int) tp->twist_col]); - next_tick = HZ / 10; - if (++tp->twist_col >= 4) { - /* For short cables we are done. - For long cables (row == 3) check for mistune. */ - tp->twistie = - (tp->twist_row == 3) ? 4 : 0; - } - break; - case 4: - /* Special case for long cables: check for mistune. */ - if ((NETDRV_R16 (CSCR) & - CSCR_LinkStatusBits) == 0x7000) { - tp->twistie = 0; - break; - } else { - NETDRV_W32 (PARA7c, 0xfb38de03); - tp->twistie = 5; - next_tick = HZ / 10; - } - break; - case 5: - /* Retune for shorter cable (column 2). */ - NETDRV_W32 (FIFOTMS, 0x20); - NETDRV_W32 (PARA78, PARA78_default); - NETDRV_W32 (PARA7c, PARA7c_default); - NETDRV_W32 (FIFOTMS, 0x00); - tp->twist_row = 2; - tp->twist_col = 0; - tp->twistie = 3; - next_tick = HZ / 10; - break; - - default: - /* do nothing */ - break; - } - - DPRINTK ("EXIT\n"); -} -#endif /* NETDRV_TUNE_TWISTER */ - - static void netdrv_timer (unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int next_tick = 60 * HZ; int mii_reg5; @@ -1407,8 +1251,6 @@ } } - netdrv_tune_twister (dev, tp); - DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n", dev->name, NETDRV_R16 (NWayLPAR)); DPRINTK ("%s: Other registers are IntMask %4.4x IntStatus %4.4x" @@ -1451,7 +1293,7 @@ static void netdrv_tx_timeout (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int i; u8 tmp8; @@ -1498,7 +1340,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int entry; @@ -1713,18 +1555,6 @@ } #endif - /* E. Gill */ - /* Note from BSD driver: - * Here's a totally undocumented fact for you. When the - * RealTek chip is in the process of copying a packet into - * RAM for you, the length will be 0xfff0. If you spot a - * packet header with this value, you need to stop. The - * datasheet makes absolutely no mention of this and - * RealTek should be shot for this. - */ - if (rx_size == 0xfff0) - break; - /* If Rx err or invalid rx_size/rx_status received * (which happens if we get lost in the ring), * Rx process gets reset, so we abort any further @@ -1839,7 +1669,7 @@ struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ @@ -1853,31 +1683,8 @@ if (status == 0xFFFF) break; - /* Acknowledge all of the current interrupt sources ASAP, but - an first get an additional status bit from CSCR. */ - if (status & RxUnderrun) - link_changed = NETDRV_R16 (CSCR) & CSCR_LinkChangeBit; - - /* E. Gill */ - /* In case of an RxFIFOOver we must also clear the RxOverflow - bit to avoid dropping frames for ever. Believe me, I got a - lot of troubles copying huge data (approximately 2 RxFIFOOver - errors per 1GB data transfer). - The following is written in the 'p-guide.pdf' file (RTL8139(A/B) - Programming guide V0.1, from 1999/1/15) on page 9 from REALTEC. - ----------------------------------------------------------- - 2. RxFIFOOvw handling: - When RxFIFOOvw occurs, all incoming packets are discarded. - Clear ISR(RxFIFOOvw) doesn't dismiss RxFIFOOvw event. To - dismiss RxFIFOOvw event, the ISR(RxBufOvw) must be written - with a '1'. - ----------------------------------------------------------- - Unfortunately I was not able to find any reason for the - 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 */ - NETDRV_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status); + /* Acknowledge all of the current interrupt sources ASAP */ + NETDRV_W16_F (IntrStatus, status); DPRINTK ("%s: interrupt status=%#4.4x new intstat=%#4.4x.\n", dev->name, status, @@ -1922,7 +1729,7 @@ static int netdrv_close (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; @@ -1964,16 +1771,16 @@ /* Green! Put the chip in low-power mode. */ NETDRV_W8 (Cfg9346, Cfg9346_Unlock); NETDRV_W8 (Config1, 0x03); - NETDRV_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ + NETDRV_W8 (Cfg9346, Cfg9346_Lock); DPRINTK ("EXIT\n"); return 0; } -static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; u16 *data = (u16 *) & rq->ifr_data; unsigned long flags; int rc = 0; @@ -2014,7 +1821,7 @@ static struct net_device_stats *netdrv_get_stats (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; DPRINTK ("ENTER\n"); @@ -2062,7 +1869,7 @@ static void netdrv_set_rx_mode (struct net_device *dev) { - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; @@ -2117,11 +1924,13 @@ static void netdrv_suspend (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; - struct netdrv_private *tp = (struct netdrv_private *) dev->priv; + struct net_device *dev = pci_get_drvdata (pdev); + struct netdrv_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; + if (!netif_running(dev)) + return; netif_device_detach (dev); spin_lock_irqsave (&tp->lock, flags); @@ -2142,8 +1951,10 @@ static void netdrv_resume (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata (pdev); + if (!netif_running(dev)) + return; pci_power_on (pdev); netif_device_attach (dev); netdrv_hw_start (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/Config.in linux/drivers/net/pcmcia/Config.in --- v2.4.2/linux/drivers/net/pcmcia/Config.in Sat Nov 11 18:56:58 2000 +++ linux/drivers/net/pcmcia/Config.in Sun Mar 25 18:24:31 2001 @@ -26,6 +26,7 @@ bool ' Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA + dep_tristate ' Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile --- v2.4.2/linux/drivers/net/pcmcia/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/net/pcmcia/Makefile Sun Mar 25 18:24:31 2001 @@ -12,7 +12,7 @@ obj- := # Things that need to export symbols -export-objs := ray_cs.o +export-objs := ray_cs.o hermes.o # 16-bit client drivers obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o @@ -25,6 +25,7 @@ obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o # 16-bit wireless client drivers +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o hermes.o obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c --- v2.4.2/linux/drivers/net/pcmcia/aironet4500_cs.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/aironet4500_cs.c Tue Mar 20 12:05:00 2001 @@ -177,8 +177,14 @@ /* Create the PC card device object. */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + if (!link) + return NULL; link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL); + if (!link->dev) { + kfree(link); + return NULL; + } + memset(link, 0, sizeof(struct dev_link_t)); memset(link->dev, 0, sizeof(struct dev_node_t)); link->release.function = &awc_release; @@ -199,7 +205,6 @@ /* Create the network device object. */ dev = kmalloc(sizeof(struct net_device ), GFP_KERNEL); - memset(dev,0,sizeof(struct net_device)); // dev = init_etherdev(0, sizeof(struct awc_private) ); if (!dev ) { printk(KERN_CRIT "out of mem on dev alloc \n"); @@ -207,6 +212,7 @@ kfree(link); return NULL; }; + memset(dev,0,sizeof(struct net_device)); dev->priv = kmalloc(sizeof(struct awc_private), GFP_KERNEL); if (!dev->priv ) {printk(KERN_CRIT "out of mem on dev priv alloc \n"); return NULL;}; memset(dev->priv,0,sizeof(struct awc_private)); 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/hermes.c linux/drivers/net/pcmcia/hermes.c --- v2.4.2/linux/drivers/net/pcmcia/hermes.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/hermes.c Sun Mar 25 18:24:31 2001 @@ -0,0 +1,502 @@ +/* hermes.c + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia + * + * This file distributed under the GPL, version 2. + */ + +static const char *version = "hermes.c: 12 Dec 2000 David Gibson "; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hermes.h" + +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */ +#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */ +#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */ +#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ +#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */ +#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */ + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +/* + * Debugging helpers + */ + +#undef HERMES_DEBUG +#ifdef HERMES_DEBUG + +#include + +#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \ + printk(#stuff);} while (0) + +#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff) + +#else /* ! HERMES_DEBUG */ + +#define DEBUG(lvl, stuff...) do { } while (0) + +#endif /* ! HERMES_DEBUG */ + +/* + * Prototypes + */ + +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0); + +/* + * Internal inline functions + */ + +/* + * Internal functions + */ + +/* Issue a command to the chip. Waiting for it to complete is the caller's + problem. + + Returns -EBUSY if the command register is busy, 0 on success. + + Callable from any context. +*/ +static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0) +{ + uint16_t reg; +/* unsigned long k = CMD_BUSY_TIMEOUT; */ + + /* First check that the command register is not busy */ + reg = hermes_read_regn(hw, CMD); + if (reg & HERMES_CMD_BUSY) { + return -EBUSY; + } + + hermes_write_regn(hw, PARAM2, 0); + hermes_write_regn(hw, PARAM1, 0); + hermes_write_regn(hw, PARAM0, param0); + hermes_write_regn(hw, CMD, cmd); + + return 0; +} + +/* + * Function definitions + */ + +void hermes_struct_init(hermes_t *hw, ushort io) +{ + hw->iobase = io; + hw->inten = 0x0; +} + +int hermes_reset(hermes_t *hw) +{ + uint16_t status, reg; + int err = 0; + int k; + + /* We don't want to be interrupted while resetting the chipset */ + hw->inten = 0x0; + hermes_write_regn(hw, INTEN, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + /* Because we hope we can reset the card even if it gets into + a stupid state, we actually wait to see if the command + register will unbusy itself */ + k = CMD_BUSY_TIMEOUT; + reg = hermes_read_regn(hw, CMD); + while (k && (reg & HERMES_CMD_BUSY)) { + if (reg == 0xffff) /* Special case - the card has probably been removed, + so don't wait for the timeout */ + return -ENODEV; + + k--; + udelay(1); + reg = hermes_read_regn(hw, CMD); + } + + /* No need to explicitly handle the timeout - hermes_issue_cmd() will + probably return -EBUSY */ + + /* We don't use hermes_docmd_wait here, because the reset wipes + the magic constant in SWSUPPORT0 away, and it gets confused */ + err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); + if (err) + return err; + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_INIT_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k); + + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); + + if (! hermes_present(hw)) { + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n", + hw->iobase, reg); + err = -ETIMEDOUT; + goto out; + } + + status = hermes_read_regn(hw, STATUS); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = status & HERMES_STATUS_RESULT; + + out: + return err; +} + +/* Issue a command to the chip, and (busy!) wait for it to + * complete. + * + * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware + * + * Callable from any context, but locking is your problem. */ +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp) +{ + int err; + int k; + uint16_t reg; + + err = hermes_issue_cmd(hw, cmd, parm0); + if (err) { + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n", + hw->iobase); + err = -ENODEV; + } else + printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n", + hw->iobase); + goto out; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = CMD_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_CMD)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n", + hw->iobase); + err = -ENODEV; + goto out; + } + + if (! (reg & HERMES_EV_CMD)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n", + hw->iobase); + err = -ETIMEDOUT; + goto out; + } + + resp->status = hermes_read_regn(hw, STATUS); + resp->resp0 = hermes_read_regn(hw, RESP0); + resp->resp1 = hermes_read_regn(hw, RESP1); + resp->resp2 = hermes_read_regn(hw, RESP2); + + hermes_write_regn(hw, EVACK, HERMES_EV_CMD); + + err = resp->status & HERMES_STATUS_RESULT; + + out: + return err; +} + +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid) +{ + int err = 0; + hermes_response_t resp; + int k; + uint16_t reg; + + if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); + if (err) { + printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", + hw->iobase, err); + return err; + } + + reg = hermes_read_regn(hw, EVSTAT); + k = ALLOC_COMPL_TIMEOUT; + while ( (! (reg & HERMES_EV_ALLOC)) && k) { + k--; + udelay(10); + reg = hermes_read_regn(hw, EVSTAT); + } + + if (! hermes_present(hw)) { + printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", + hw->iobase); + return -ENODEV; + } + + if (! (reg & HERMES_EV_ALLOC)) { + printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", + hw->iobase); + return -ETIMEDOUT; + } + + *fid = hermes_read_regn(hw, ALLOCFID); + hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); + + return 0; +} + +/* Set up a BAP to read a particular chunk of data from card's internal buffer. + * + * Returns: < 0 on internal failure (errno), 0 on success, >0 on error + * from firmware + * + * Callable from any context */ +static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset) +{ + int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0; + int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0; + int k; + int l = BAP_ERROR_RETRY; + uint16_t reg; + + /* Paranoia.. */ + if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) ) + return -EINVAL; + + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + + if (reg & HERMES_OFFSET_BUSY) + return -EBUSY; + + /* Now we actually set up the transfer */ + retry: + hermes_write_reg(hw, sreg, id); + hermes_write_reg(hw, oreg, offset); + + /* Wait for the BAP to be ready */ + k = BAP_BUSY_TIMEOUT; + reg = hermes_read_reg(hw, oreg); + while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) { + k--; + udelay(1); + reg = hermes_read_reg(hw, oreg); + } + + if (reg & HERMES_OFFSET_BUSY) + return -ETIMEDOUT; + + /* For some reason, seeking the BAP seems to randomly fail somewhere + (firmware bug?). We retry a few times before giving up. */ + if (reg & HERMES_OFFSET_ERR) { + if (l--) { + udelay(1); + goto retry; + } else + return -EIO; + } + + return 0; +} + +/* Read a block of data from the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_read_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Write a block of data to the chip's buffer, via the + * BAP. Synchronization/serialization is the caller's problem. len + * must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len % 2) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Actually do the transfer */ + hermes_write_data(hw, dreg, buf, len/2); + + out: + return err; +} + +/* Read a Length-Type-Value record from the card. + * + * If length is NULL, we ignore the length read from the card, and + * read the entire buffer regardless. This is useful because some of + * the configuration records appear to have incorrect lengths in + * practice. + * + * Callable from user or bh context. */ +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf) +{ + int err = 0; + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + uint16_t rlength, rtype; + hermes_response_t resp; + int count; + + if (buflen % 2) + return -EINVAL; + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp); + if (err) + goto out; + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + rlength = hermes_read_reg(hw, dreg); + rtype = hermes_read_reg(hw, dreg); + + if (length) + *length = rlength; + + if (rtype != rid) + printk(KERN_WARNING "hermes_read_ltv(): rid (0x%04x) does " + "not match type (0x%04x)\n", rid, rtype); + if (HERMES_RECLEN_TO_BYTES(rlength) > buflen) + printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. " + "(rid=0x%04x, len=0x%04x)\n", hw->iobase, + HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength); + + /* For now we always read the whole buffer, the + lengths in the records seem to be wrong, frequently */ + count = buflen / 2; + +#if 0 + if (length) + count = (MIN(buflen, rlength) + 1) / 2; + else { + count = buflen / 2; + if (rlength != buflen) + printk(KERN_WARNING "hermes_read_ltv(): Incorrect \ +record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid); + } +#endif + hermes_read_data(hw, dreg, buf, count); + + out: + return err; +} + +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + hermes_response_t resp; + int count; + + DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n", + bap, rid, length, * ((uint16_t *)value)); + + err = hermes_bap_seek(hw, bap, rid, 0); + if (err) + goto out; + + hermes_write_reg(hw, dreg, length); + hermes_write_reg(hw, dreg, rid); + + count = length - 1; + + hermes_write_data(hw, dreg, value, count); + + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, + rid, &resp); + + out: + return err; +} + +EXPORT_SYMBOL(hermes_struct_init); +EXPORT_SYMBOL(hermes_reset); +EXPORT_SYMBOL(hermes_docmd_wait); +EXPORT_SYMBOL(hermes_allocate); + +EXPORT_SYMBOL(hermes_bap_pread); +EXPORT_SYMBOL(hermes_bap_pwrite); +EXPORT_SYMBOL(hermes_read_ltv); +EXPORT_SYMBOL(hermes_write_ltv); + +static int __init init_hermes(void) +{ + printk(KERN_INFO "%s\n", version); + + return 0; +} + +module_init(init_hermes); diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/hermes.h linux/drivers/net/pcmcia/hermes.h --- v2.4.2/linux/drivers/net/pcmcia/hermes.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/hermes.h Sun Mar 25 18:24:31 2001 @@ -0,0 +1,398 @@ +/* hermes.h + * + * Driver core for the "Hermes" wireless MAC controller, as used in + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also + * work on the hfa3841 and hfa3842 MAC controller chips used in the + * Prism I & II chipsets. + * + * This is not a complete driver, just low-level access routines for + * the MAC controller itself. + * + * Based on the prism2 driver from Absolute Value Systems' linux-wlan + * project, the Linux wvlan_cs driver, Lucent's HCF-Light + * (wvlan_hcf.c) library, and the NetBSD wireless driver. + * + * Copyright (C) 2000, David Gibson, Linuxcare Australia + * + * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * + * This file distributed under the GPL, version 2. + */ + +#ifndef _HERMES_H +#define _HERMES_H + +/* Notes on locking: + * + * As a module of low level hardware access routines, there is no + * locking. Users of this module should ensure that they serialize + * access to the hermes_t structure, and to the hardware +*/ + +#include +#include + +/* + * Limits and constants + */ +#define HERMES_ALLOC_LEN_MIN ((uint16_t)4) +#define HERMES_ALLOC_LEN_MAX ((uint16_t)2400) +#define HERMES_LTV_LEN_MAX (34) +#define HERMES_BAP_DATALEN_MAX ((uint16_t)4096) +#define HERMES_BAP_OFFSET_MAX ((uint16_t)4096) +#define HERMES_PORTID_MAX ((uint16_t)7) +#define HERMES_NUMPORTS_MAX ((uint16_t)(HERMES_PORTID_MAX+1)) +#define HERMES_PDR_LEN_MAX ((uint16_t)260) /* in bytes, from EK */ +#define HERMES_PDA_RECS_MAX ((uint16_t)200) /* a guess */ +#define HERMES_PDA_LEN_MAX ((uint16_t)1024) /* in bytes, from EK */ +#define HERMES_SCANRESULT_MAX ((uint16_t)35) +#define HERMES_CHINFORESULT_MAX ((uint16_t)8) +#define HERMES_FRAME_LEN_MAX (2304) +#define HERMES_MAX_MULTICAST (16) +#define HERMES_MAGIC (0x7d1f) + +/* + * Hermes register offsets + */ +#define HERMES_CMD (0x00) +#define HERMES_PARAM0 (0x02) +#define HERMES_PARAM1 (0x04) +#define HERMES_PARAM2 (0x06) +#define HERMES_STATUS (0x08) +#define HERMES_RESP0 (0x0A) +#define HERMES_RESP1 (0x0C) +#define HERMES_RESP2 (0x0E) +#define HERMES_INFOFID (0x10) +#define HERMES_RXFID (0x20) +#define HERMES_ALLOCFID (0x22) +#define HERMES_TXCOMPLFID (0x24) +#define HERMES_SELECT0 (0x18) +#define HERMES_OFFSET0 (0x1C) +#define HERMES_DATA0 (0x36) +#define HERMES_SELECT1 (0x1A) +#define HERMES_OFFSET1 (0x1E) +#define HERMES_DATA1 (0x38) +#define HERMES_EVSTAT (0x30) +#define HERMES_INTEN (0x32) +#define HERMES_EVACK (0x34) +#define HERMES_CONTROL (0x14) +#define HERMES_SWSUPPORT0 (0x28) +#define HERMES_SWSUPPORT1 (0x2A) +#define HERMES_SWSUPPORT2 (0x2C) +#define HERMES_AUXPAGE (0x3A) +#define HERMES_AUXOFFSET (0x3C) +#define HERMES_AUXDATA (0x3E) + +/* + * CMD register bitmasks + */ +#define HERMES_CMD_BUSY ((uint16_t)0x8000) +#define HERMES_CMD_AINFO ((uint16_t)0x7f00) +#define HERMES_CMD_MACPORT ((uint16_t)0x0700) +#define HERMES_CMD_RECL ((uint16_t)0x0100) +#define HERMES_CMD_WRITE ((uint16_t)0x0100) +#define HERMES_CMD_PROGMODE ((uint16_t)0x0300) +#define HERMES_CMD_CMDCODE ((uint16_t)0x003f) + +/* + * STATUS register bitmasks + */ +#define HERMES_STATUS_RESULT ((uint16_t)0x7f00) +#define HERMES_STATUS_CMDCODE ((uint16_t)0x003f) + +/* + * OFFSET refister bitmasks + */ +#define HERMES_OFFSET_BUSY ((uint16_t)0x8000) +#define HERMES_OFFSET_ERR ((uint16_t)0x4000) +#define HERMES_OFFSET_DATAOFF ((uint16_t)0x0ffe) + +/* + * Event register bitmasks (INTEN, EVSTAT, EVACK) + */ +#define HERMES_EV_TICK ((uint16_t)0x8000) +#define HERMES_EV_WTERR ((uint16_t)0x4000) +#define HERMES_EV_INFDROP ((uint16_t)0x2000) +#define HERMES_EV_INFO ((uint16_t)0x0080) +#define HERMES_EV_DTIM ((uint16_t)0x0020) +#define HERMES_EV_CMD ((uint16_t)0x0010) +#define HERMES_EV_ALLOC ((uint16_t)0x0008) +#define HERMES_EV_TXEXC ((uint16_t)0x0004) +#define HERMES_EV_TX ((uint16_t)0x0002) +#define HERMES_EV_RX ((uint16_t)0x0001) + +/* + * Command codes + */ +/*--- Controller Commands --------------------------*/ +#define HERMES_CMD_INIT ((uint16_t)0x00) +#define HERMES_CMD_ENABLE ((uint16_t)0x01) +#define HERMES_CMD_DISABLE ((uint16_t)0x02) +#define HERMES_CMD_DIAG ((uint16_t)0x03) + +/*--- Buffer Mgmt Commands --------------------------*/ +#define HERMES_CMD_ALLOC ((uint16_t)0x0A) +#define HERMES_CMD_TX ((uint16_t)0x0B) +#define HERMES_CMD_CLRPRST ((uint16_t)0x12) + +/*--- Regulate Commands --------------------------*/ +#define HERMES_CMD_NOTIFY ((uint16_t)0x10) +#define HERMES_CMD_INQ ((uint16_t)0x11) + +/*--- Configure Commands --------------------------*/ +#define HERMES_CMD_ACCESS ((uint16_t)0x21) +#define HERMES_CMD_DOWNLD ((uint16_t)0x22) + +/*--- Debugging Commands -----------------------------*/ +#define HERMES_CMD_MONITOR ((uint16_t)(0x38)) +#define HERMES_MONITOR_ENABLE ((uint16_t)(0x0b)) +#define HERMES_MONITOR_DISABLE ((uint16_t)(0x0f)) + +/* + * Configuration RIDs + */ + +#define HERMES_RID_CNF_PORTTYPE ((uint16_t)0xfc00) +#define HERMES_RID_CNF_MACADDR ((uint16_t)0xfc01) +#define HERMES_RID_CNF_DESIRED_SSID ((uint16_t)0xfc02) +#define HERMES_RID_CNF_CHANNEL ((uint16_t)0xfc03) +#define HERMES_RID_CNF_OWN_SSID ((uint16_t)0xfc04) +#define HERMES_RID_CNF_SYSTEM_SCALE ((uint16_t)0xfc06) +#define HERMES_RID_CNF_MAX_DATA_LEN ((uint16_t)0xfc07) +#define HERMES_RID_CNF_PM_ENABLE ((uint16_t)0xfc09) +#define HERMES_RID_CNF_PM_MCAST_RX ((uint16_t)0xfc0b) +#define HERMES_RID_CNF_PM_PERIOD ((uint16_t)0xfc0c) +#define HERMES_RID_CNF_PM_HOLDOVER ((uint16_t)0xfc0d) +#define HERMES_RID_CNF_NICKNAME ((uint16_t)0xfc0e) +#define HERMES_RID_CNF_WEP_ON ((uint16_t)0xfc20) +#define HERMES_RID_CNF_MWO_ROBUST ((uint16_t)0xfc25) +#define HERMES_RID_CNF_PRISM2_WEP_ON ((uint16_t)0xfc28) +#define HERMES_RID_CNF_MULTICAST_LIST ((uint16_t)0xfc80) +#define HERMES_RID_CNF_CREATEIBSS ((uint16_t)0xfc81) +#define HERMES_RID_CNF_FRAG_THRESH ((uint16_t)0xfc82) +#define HERMES_RID_CNF_RTS_THRESH ((uint16_t)0xfc83) +#define HERMES_RID_CNF_TX_RATE_CTRL ((uint16_t)0xfc84) +#define HERMES_RID_CNF_PROMISCUOUS ((uint16_t)0xfc85) +#define HERMES_RID_CNF_KEYS ((uint16_t)0xfcb0) +#define HERMES_RID_CNF_TX_KEY ((uint16_t)0xfcb1) +#define HERMES_RID_CNF_TICKTIME ((uint16_t)0xfce0) + +#define HERMES_RID_CNF_PRISM2_TX_KEY ((uint16_t)0xfc23) +#define HERMES_RID_CNF_PRISM2_KEY0 ((uint16_t)0xfc24) +#define HERMES_RID_CNF_PRISM2_KEY1 ((uint16_t)0xfc25) +#define HERMES_RID_CNF_PRISM2_KEY2 ((uint16_t)0xfc26) +#define HERMES_RID_CNF_PRISM2_KEY3 ((uint16_t)0xfc27) +#define HERMES_RID_CNF_SYMBOL_AUTH_TYPE ((uint16_t)0xfc2A) +/* This one is read only */ +#define HERMES_RID_CNF_SYMBOL_KEY_LENGTH ((uint16_t)0xfc2B) +#define HERMES_RID_CNF_SYMBOL_BASIC_RATES ((uint16_t)0xfc8A) + +/* + * Information RIDs + */ +#define HERMES_RID_CHANNEL_LIST ((uint16_t)0xfd10) +#define HERMES_RID_STAIDENTITY ((uint16_t)0xfd20) +#define HERMES_RID_CURRENT_SSID ((uint16_t)0xfd41) +#define HERMES_RID_CURRENT_BSSID ((uint16_t)0xfd42) +#define HERMES_RID_COMMSQUALITY ((uint16_t)0xfd43) +#define HERMES_RID_CURRENT_TX_RATE ((uint16_t)0xfd44) +#define HERMES_RID_WEP_AVAIL ((uint16_t)0xfd4f) +#define HERMES_RID_CURRENT_CHANNEL ((uint16_t)0xfdc1) +#define HERMES_RID_DATARATES ((uint16_t)0xfdc6) + +/* + * Frame structures and constants + */ + +typedef struct hermes_frame_desc { + /* Hermes - i.e. little-endian byte-order */ + uint16_t status; /* 0x0 */ + uint16_t res1, res2; /* 0x2, 0x4 */ + uint16_t q_info; /* 0x6 */ + uint16_t res3, res4; /* 0x8, 0xA */ + uint16_t tx_ctl; /* 0xC */ +} __attribute__ ((packed)) hermes_frame_desc_t; + +#define HERMES_RXSTAT_ERR ((uint16_t)0x0003) +#define HERMES_RXSTAT_MACPORT ((uint16_t)0x0700) +#define HERMES_RXSTAT_MSGTYPE ((uint16_t)0xE000) + +#define HERMES_RXSTAT_BADCRC ((uint16_t)0x0001) +#define HERMES_RXSTAT_UNDECRYPTABLE ((uint16_t)0x0002) + +/* RFC-1042 encoded frame */ +#define HERMES_RXSTAT_1042 ((uint16_t)0x2000) +/* Bridge-tunnel encoded frame */ +#define HERMES_RXSTAT_TUNNEL ((uint16_t)0x4000) +/* Wavelan-II Management Protocol frame */ +#define HERMES_RXSTAT_WMP ((uint16_t)0x6000) + +#ifdef __KERNEL__ + +/* Basic control structure */ +typedef struct hermes { + uint iobase; + + uint16_t inten; /* Which interrupts should be enabled? */ +} hermes_t; + +typedef struct hermes_response { + uint16_t status, resp0, resp1, resp2; +} hermes_response_t; + +/* Firmware information structure */ +typedef struct hermes_identity { + uint16_t id, vendor, major, minor; +} __attribute__ ((packed)) hermes_identity_t; + +/* "ID" structure - used for ESSID and station nickname */ +typedef struct hermes_id { + uint16_t len; + uint16_t val[16]; +} __attribute__ ((packed)) hermes_id_t; + +typedef struct hermes_commsqual { + uint16_t qual, signal, noise; +} __attribute__ ((packed)) hermes_commsqual_t; + +typedef struct hermes_multicast { + uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN]; +} __attribute__ ((packed)) hermes_multicast_t; + +/* Register access convenience macros */ +#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off))) +#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off))) + +#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name)) +#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count))) +#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count))) + +/* Function prototypes */ +void hermes_struct_init(hermes_t *hw, ushort io); +int hermes_reset(hermes_t *hw); +int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp); +int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid); + + +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len, + uint16_t id, uint16_t offset); +int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen, + uint16_t *length, void *buf); +int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, + uint16_t length, const void *value); + +/* Inline functions */ + +static inline int hermes_present(hermes_t *hw) +{ + return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC; +} + +static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events) +{ + hw->inten |= events; + hermes_write_regn(hw, INTEN, hw->inten); +} + +static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events) +{ + hw->inten = events; + hermes_write_regn(hw, INTEN, events); +} + +static inline int hermes_enable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +static inline int hermes_disable_port(hermes_t *hw, int port) +{ + hermes_response_t resp; + + return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), + 0, &resp); +} + +#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 ) +#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) + +#define HERMES_READ_RECORD(hw, bap, rid, buf) \ + (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) +#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ + (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf))) +#define HERMES_WRITE_RECORD_LEN(hw, bap, rid, buf, len) \ + (hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(len),(buf))) + +static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word) +{ + uint16_t rec; + int err; + + err = HERMES_READ_RECORD(hw, bap, rid, &rec); + *word = le16_to_cpu(rec); + return err; +} + +static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word) +{ + uint16_t rec = cpu_to_le16(word); + return HERMES_WRITE_RECORD(hw, bap, rid, &rec); +} + +static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->id); + le16_to_cpus(&buf->vendor); + le16_to_cpus(&buf->major); + le16_to_cpus(&buf->minor); + + return 0; +} + +static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf) +{ + int err; + + err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf); + if (err) + return err; + + le16_to_cpus(&buf->qual); + le16_to_cpus(&buf->signal); + le16_to_cpus(&buf->noise); + + return 0; +} + +#else /* ! __KERNEL__ */ + +/* These are provided for the benefit of userspace drivers and testing programs + which use ioperm() or iopl() */ + +#define hermes_read_reg(base, off) (inw((base) + (off))) +#define hermes_write_reg(base, off, val) (outw((val), (base) + (off))) + +#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name)) +#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val))) + +/* Note that for the next two, the count is in 16-bit words, not bytes */ +#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count))) +#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count))) + +#endif /* ! __KERNEL__ */ + +#endif /* _HERMES_H */ 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/orinoco_cs.c linux/drivers/net/pcmcia/orinoco_cs.c --- v2.4.2/linux/drivers/net/pcmcia/orinoco_cs.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/pcmcia/orinoco_cs.c Sun Mar 25 18:24:31 2001 @@ -0,0 +1,4018 @@ +/* orinoco_cs.c 0.03 - (formerly known as dldwd_cs.c) + * + * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such + * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others). + * It should also be usable on various Prism II based cards such as the + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol + * cards such as the 3Com AirConnect and Ericsson WLAN. + * + * Copyright (C) 2000 David Gibson, Linuxcare Australia + * With some help from : + * Copyright (C) 2001 Jean Tourrilhes, HP Labs + * + * Based on dummy_cs.c 1.27 2000/06/12 21:27:25 + * + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus + * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + * + * 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. + */ + +/* Notes on locking: + * + * The basic principle of operation is that everything except the + * interrupt handler is serialized through a single spinlock in the + * dldwd_priv_t structure, using dldwd_lock() and + * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()). + * + * The kernel's IRQ handling stuff ensures that the interrupt handler + * does not re-enter itself. The interrupt handler is written such + * that everything it does is safe without a lock: chiefly this means + * that the Rx path uses one of the Hermes chipset's BAPs while + * everything else uses the other. + * + * For the moment access to the device statistics from the interrupt + * handler is unsafe - we just put up with any resulting errors in the + * statisics. FIXME: This should probably be changed to store the + * stats in atomic types. + * + * EXCEPT that we don't want the irq handler running when we actually + * reset or shut down the card, because strange things might happen + * (probably the worst would be one packet of garbage, but you can't + * be too careful). For this we use __dldwd_stop_irqs() which will set + * a flag to disable the interrupt handler, and wait for any + * outstanding instances of the handler to complete. THIS WILL LOSE + * INTERRUPTS! so it shouldn't be used except for resets, when we + * don't care about that.*/ + +/* + * Tentative changelog... + * + * v0.01 -> v0.02 - 21/3/2001 - Jean II + * o Allow to use regular ethX device name instead of dldwdX + * o Warning on IBSS with ESSID=any for firmware 6.06 + * o Put proper range.throughput values (optimistic) + * o IWSPY support (IOCTL and stat gather in Rx path) + * o Allow setting frequency in Ad-Hoc mode + * o Disable WEP setting if !has_wep to work on old firmware + * o Fix txpower range + * o Start adding support for Samsung/Compaq firmware + * + * v0.02 -> v0.03 - 23/3/2001 - Jean II + * o Start adding Symbol support - need to check all that + * o Fix Prism2/Symbol WEP to accept 128 bits keys + * o Add Symbol WEP (add authentication type) + * o Add Prism2/Symbol rate + * o Add PM timeout (holdover duration) + * o Enable "iwconfig eth0 key off" and friends (toggle flags) + * o Enable "iwconfig eth0 power unicast/all" (toggle flags) + * o Try with an intel card. It report firmware 1.01, behave like + * an antiquated firmware, however on windows it says 2.00. Yuck ! + * o Workaround firmware bug in allocate buffer (Intel 1.01) + * o Finish external renaming to orinoco... + * o Testing with various Wavelan firmwares + * + * TODO - Jean II + * o inline functions (lot's of candidate, need to reorder code) + * o Separate Pcmcia specific code to help Airport/Mini PCI driver + * o Test PrismII/Symbol cards & firmware versions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "hermes.h" + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +static char *version = "orinoco_cs.c 0.03 (David Gibson )"; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#define DEBUGMORE(n, args...) do { if (pc_debug>(n)) printk(args); } while (0) +#else +#define DEBUG(n, args...) do { } while (0) +#define DEBUGMORE(n, args...) do { } while (0) +#endif + +#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname); +#define TRACE_EXIT(devname) DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname); + +#define MAX(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + +#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) ) + + +#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) +#error "orinoco_cs requires Wireless extensions v10 or later." +#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */ +#define WIRELESS_SPY // enable iwspy support + +/*====================================================================*/ + +/* 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 uint irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; +/* Control device name allocation. 0 -> dldwdX ; 1 -> ethX */ +static int eth = 1; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(eth, "i"); + +/*====================================================================*/ + +#define DLDWD_MIN_MTU 256 +#define DLDWD_MAX_MTU (HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD) + +#define LTV_BUF_SIZE 128 +#define USER_BAP 0 +#define IRQ_BAP 1 +#define DLDWD_MACPORT 0 +#define IRQ_LOOP_MAX 10 +#define TX_NICBUF_SIZE 2048 +#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Intel firmware */ +#define MAX_KEYS 4 +#define MAX_KEY_SIZE 14 +#define LARGE_KEY_SIZE 13 +#define SMALL_KEY_SIZE 5 +#define MAX_FRAME_SIZE 2304 + +const long channel_frequency[] = { + 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) ) + +/* This tables gives the actual meanings of the bitrate IDs returned by the firmware. + It gives the rate in halfMb/s, negative indicates auto mode */ +const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0}; + +#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0])) +typedef struct dldwd_key { + uint16_t len; + char data[MAX_KEY_SIZE]; +} __attribute__ ((packed)) dldwd_key_t; + +typedef dldwd_key_t dldwd_keys_t[MAX_KEYS]; + +typedef struct dldwd_priv { + dev_link_t link; + dev_node_t node; + int instance; + + spinlock_t lock; + long state; +#define DLDWD_STATE_INIRQ 0 +#define DLDWD_STATE_DOIRQ 1 + + /* Net device stuff */ + struct net_device ndev; + struct net_device_stats stats; + struct iw_statistics wstats; + + + /* Hardware control variables */ + hermes_t hw; + uint16_t txfid; + + /* Capabilities of the hardware/firmware */ + hermes_identity_t firmware_info; + int firmware_type; +#define FIRMWARE_TYPE_LUCENT 1 +#define FIRMWARE_TYPE_PRISM2 2 +#define FIRMWARE_TYPE_SYMBOL 3 + int has_ibss, has_port3, prefer_port3, has_ibss_any; + int has_wep, has_big_wep; + int has_mwo; + int has_pm; + int broken_reset, broken_allocate; + uint16_t channel_mask; + + /* Current configuration */ + uint32_t iw_mode; + int port_type, allow_ibss; + uint16_t wep_on, wep_auth, tx_key; + dldwd_keys_t keys; + char nick[IW_ESSID_MAX_SIZE+1]; + char desired_essid[IW_ESSID_MAX_SIZE+1]; + uint16_t frag_thresh, mwo_robust; + uint16_t channel; + uint16_t ap_density, rts_thresh; + uint16_t tx_rate_ctrl; + uint16_t pm_on, pm_mcast, pm_period, pm_timeout; + + int promiscuous, allmulti, mc_count; + +#ifdef WIRELESS_SPY + int spy_number; + u_char spy_address[IW_MAX_SPY][ETH_ALEN]; + struct iw_quality spy_stat[IW_MAX_SPY]; +#endif + + /* /proc based debugging stuff */ + struct proc_dir_entry *dir_dev; + struct proc_dir_entry *dir_regs; + struct proc_dir_entry *dir_recs; +} dldwd_priv_t; + +struct p80211_hdr { + uint16_t frame_ctl; + uint16_t duration_id; + uint8_t addr1[ETH_ALEN]; + uint8_t addr2[ETH_ALEN]; + uint8_t addr3[ETH_ALEN]; + uint16_t seq_ctl; + uint8_t addr4[ETH_ALEN]; + uint16_t data_len; +} __attribute__ ((packed)); + +/* Frame control field constants */ +#define DLDWD_FCTL_VERS 0x0002 +#define DLDWD_FCTL_FTYPE 0x000c +#define DLDWD_FCTL_STYPE 0x00f0 +#define DLDWD_FCTL_TODS 0x0100 +#define DLDWD_FCTL_FROMDS 0x0200 +#define DLDWD_FCTL_MOREFRAGS 0x0400 +#define DLDWD_FCTL_RETRY 0x0800 +#define DLDWD_FCTL_PM 0x1000 +#define DLDWD_FCTL_MOREDATA 0x2000 +#define DLDWD_FCTL_WEP 0x4000 +#define DLDWD_FCTL_ORDER 0x8000 + +#define DLDWD_FTYPE_MGMT 0x0000 +#define DLDWD_FTYPE_CTL 0x0004 +#define DLDWD_FTYPE_DATA 0x0008 + +struct p8022_hdr { + uint8_t dsap; + uint8_t ssap; + uint8_t ctrl; + uint8_t oui[3]; +} __attribute__ ((packed)); + +struct dldwd_frame_hdr { + hermes_frame_desc_t desc; + struct p80211_hdr p80211; + struct ethhdr p8023; + struct p8022_hdr p8022; + uint16_t ethertype; +} __attribute__ ((packed)); + +#define P8023_OFFSET (sizeof(hermes_frame_desc_t) + \ + sizeof(struct p80211_hdr)) +#define ENCAPS_OVERHEAD (sizeof(struct p8022_hdr) + 2) + +/* + * Function prototypes + */ + +/* PCMCIA gumpf */ + +static void dldwd_config(dev_link_t * link); +static void dldwd_release(u_long arg); +static int dldwd_event(event_t event, int priority, + event_callback_args_t * args); + +static dev_link_t *dldwd_attach(void); +static void dldwd_detach(dev_link_t *); + +/* Hardware control routines */ + +static int __dldwd_hw_reset(dldwd_priv_t *priv); +static void dldwd_shutdown(dldwd_priv_t *dev); +static int dldwd_reset(dldwd_priv_t *dev); +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv); +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]); +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]); +static long dldwd_hw_get_freq(dldwd_priv_t *priv); +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max); + +/* Interrupt handling routines */ +void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs); +static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw); +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw); + +/* struct net_device methods */ +static int dldwd_init(struct net_device *dev); +static int dldwd_open(struct net_device *dev); +static int dldwd_stop(struct net_device *dev); + +static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev); +static void dldwd_tx_timeout(struct net_device *dev); + +static struct net_device_stats *dldwd_get_stats(struct net_device *dev); +static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev); +static void dldwd_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr); + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq); +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq); +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq); +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq); +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq); +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq); +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); +static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +static int dldwd_change_mtu(struct net_device *dev, int new_mtu); +static void __dldwd_set_multicast_list(struct net_device *dev); + +/* /proc debugging stuff */ +static int dldwd_proc_init(void); +static void dldwd_proc_cleanup(void); +static int dldwd_proc_dev_init(dldwd_priv_t *dev); +static void dldwd_proc_dev_cleanup(dldwd_priv_t *dev); + +/* + * Inline functions + */ +static inline void +dldwd_lock(dldwd_priv_t *priv) +{ + spin_lock_bh(&priv->lock); +} + +static inline void +dldwd_unlock(dldwd_priv_t *priv) +{ + spin_unlock_bh(&priv->lock); +} + +static inline int +dldwd_irqs_allowed(dldwd_priv_t *priv) +{ + return test_bit(DLDWD_STATE_DOIRQ, &priv->state); +} + +static inline void +__dldwd_stop_irqs(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + + hermes_set_irqmask(hw, 0); + clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + while (test_bit(DLDWD_STATE_INIRQ, &priv->state)) + ; +} + +static inline void +__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask) +{ + hermes_t *hw = &priv->hw; + + TRACE_ENTER(priv->ndev.name); + + __cli(); + set_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, irqmask); + __sti(); + + TRACE_EXIT(priv->ndev.name); +} + +static inline void +set_port_type(dldwd_priv_t *priv) +{ + switch (priv->iw_mode) { + case IW_MODE_INFRA: + priv->port_type = 1; + priv->allow_ibss = 0; + break; + case IW_MODE_ADHOC: + if (priv->prefer_port3) { + priv->port_type = 3; + priv->allow_ibss = 0; + } else { + priv->port_type = 1; + priv->allow_ibss = 1; + } + break; + default: + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", + priv->ndev.name); + } +} + +static inline void +dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + + dldwd_lock(priv); + __dldwd_set_multicast_list(dev); + dldwd_unlock(priv); +} + +/* + * Hardware control routines + */ + +static int +__dldwd_hw_reset(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err; + + if (! priv->broken_reset) + return hermes_reset(hw); + else { + hw->inten = 0; + hermes_write_regn(hw, INTEN, 0); + err = hermes_disable_port(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + return err; + } +} + +static void +dldwd_shutdown(dldwd_priv_t *priv) +{ +/* hermes_t *hw = &priv->hw; */ + int err = 0; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ + printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err); + + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); +} + +static int +dldwd_reset(dldwd_priv_t *priv) +{ + struct net_device *dev = &priv->ndev; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t idbuf; + int frame_size; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + __dldwd_stop_irqs(priv); + + err = __dldwd_hw_reset(priv); + if (err) + goto out; + + frame_size = TX_NICBUF_SIZE; + /* This stupid bug is present in Intel firmware 1.10, and + * may be fixed in later firmwares - Jean II */ + if(priv->broken_allocate) + frame_size = TX_NICBUF_SIZE_BUG; + err = hermes_allocate(hw, frame_size, &priv->txfid); + if (err) + goto out; + + /* Now set up all the parameters on the card */ + + /* Set up the link mode */ + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type); + if (err) + goto out; + if (priv->has_ibss) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS, + priv->allow_ibss); + if (err) + goto out; + if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) + && (!priv->has_ibss_any)) { + printk(KERN_WARNING "%s: This firmware requires an \ +ESSID in IBSS-Ad-Hoc mode.\n", dev->name); + /* With wvlan_cs, in this case, we would crash. + * hopefully, this driver will behave better... + * Jean II */ + } + } + + /* Set up encryption */ + if (priv->has_wep) { + err = __dldwd_hw_setup_wep(priv); + if (err) + goto out; + } + + /* Set the desired ESSID */ + idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ? + HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID, + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), + &idbuf); + if (err) + goto out; + + /* Set the station name */ + idbuf.len = cpu_to_le16(strlen(priv->nick)); + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), + &idbuf); + if (err) + goto out; + + /* Set the channel/frequency */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel); + if (err) + goto out; + + /* Set AP density */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density); + if (err) + goto out; + + /* Set RTS threshold */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh); + if (err) + goto out; + + /* Set fragmentation threshold or MWO robustness */ + if (priv->has_mwo) + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust); + else + err = hermes_write_wordrec(hw, USER_BAP, + HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh); + if (err) + goto out; + + /* Set bitrate */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, + priv->tx_rate_ctrl); + if (err) + goto out; + + /* Set power management */ + if (priv->has_pm) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, + priv->pm_on); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, + priv->pm_mcast); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + priv->pm_period); + if (err) + goto out; + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + priv->pm_timeout); + if (err) + goto out; + } + + /* Set promiscuity / multicast*/ + priv->promiscuous = 0; + priv->allmulti = 0; + priv->mc_count = 0; + __dldwd_set_multicast_list(dev); + + err = hermes_enable_port(hw, DLDWD_MACPORT); + if (err) + goto out; + + __dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | + HERMES_EV_TX | HERMES_EV_TXEXC | + HERMES_EV_WTERR | HERMES_EV_INFO | + HERMES_EV_INFDROP); + + out: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static int __dldwd_hw_setup_wep(dldwd_priv_t *priv) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */ + if (priv->wep_on) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key); + if (err) + return err; + + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys); + if (err) + return err; + } + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on); + if (err) + return err; + break; + + case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ + if (priv->wep_on) { + char keybuf[LARGE_KEY_SIZE+1]; + int keylen; + int i; + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY, + priv->tx_key); + if (err) + return err; + + keybuf[LARGE_KEY_SIZE] = '\0'; + + /* Write all 4 keys */ + for(i = 0; i < MAX_KEYS; i++) { + keylen = priv->keys[i].len; + keybuf[SMALL_KEY_SIZE] = '\0'; + memcpy(keybuf, priv->keys[i].data, keylen); + err = HERMES_WRITE_RECORD_LEN(hw, USER_BAP, HERMES_RID_CNF_PRISM2_KEY0, &keybuf, keylen); + if (err) + return err; + } + /* Symbol cards : set the authentication : + * 0 -> no encryption, 1 -> open, + * 2 -> shared key, 3 -> shared key 128bit only */ + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_auth); + if (err) + return err; + } + } + + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, priv->wep_on); + if (err) + return err; + break; + + default: + if (priv->wep_on) { + printk(KERN_ERR "%s: WEP enabled, although not supported!\n", + priv->ndev.name); + return -EINVAL; + } + } + + return 0; +} + +static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + + dldwd_lock(priv); + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID, + ETH_ALEN, NULL, buf); + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, + char buf[IW_ESSID_MAX_SIZE+1]) +{ + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t essidbuf; + char *p = (char *)(&essidbuf.val); + int len; + + TRACE_ENTER(priv->ndev.name); + + dldwd_lock(priv); + + if (strlen(priv->desired_essid) > 0) { + /* We read the desired SSID from the hardware rather + than from priv->desired_essid, just in case the + firmware is allowed to change it on us. I'm not + sure about this */ + /* My guess is that the OWN_SSID should always be whatever + * we set to the card, whereas CURRENT_SSID is the one that + * may change... - Jean II */ + uint16_t rid; + + *active = 1; + + rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID : + HERMES_RID_CNF_DESIRED_SSID; + + err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), + NULL, &essidbuf); + if (err) + goto fail_unlock; + } else { + *active = 0; + + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID, + sizeof(essidbuf), NULL, &essidbuf); + if (err) + goto fail_unlock; + } + + len = le16_to_cpu(essidbuf.len); + + memset(buf, 0, sizeof(buf)); + memcpy(buf, p, len); + buf[len] = '\0'; + + fail_unlock: + dldwd_unlock(priv); + + TRACE_EXIT(priv->ndev.name); + + return err; +} + +static long dldwd_hw_get_freq(dldwd_priv_t *priv) +{ + + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t channel; + long freq = 0; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel); + if (err) + goto out; + + if ( (channel < 1) || (channel > NUM_CHANNELS) ) { + struct net_device *dev = &priv->ndev; + + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); + err = -EBUSY; + goto out; + + } + freq = channel_frequency[channel-1] * 100000; + + out: + dldwd_unlock(priv); + + if (err > 0) + err = -EBUSY; + return err ? err : freq; +} + +static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates, + int32_t *rates, int max) +{ + hermes_t *hw = &priv->hw; + hermes_id_t list; + unsigned char *p = (unsigned char *)&list.val; + int err = 0; + int num; + int i; + + dldwd_lock(priv); + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list), + NULL, &list); + dldwd_unlock(priv); + + if (err) + return err; + + num = le16_to_cpu(list.len); + *numrates = num; + num = MIN(num, max); + + for (i = 0; i < num; i++) { + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ + } + + return 0; +} + +#ifndef PCMCIA_DEBUG +static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {} +#else +static void show_rx_frame(struct dldwd_frame_hdr *frame) +{ + printk(KERN_DEBUG "RX descriptor:\n"); + printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); + printk(KERN_DEBUG " res1 = 0x%04x\n", frame->desc.res1); + printk(KERN_DEBUG " res2 = 0x%04x\n", frame->desc.res2); + printk(KERN_DEBUG " q_info = 0x%04x\n", frame->desc.q_info); + printk(KERN_DEBUG " res3 = 0x%04x\n", frame->desc.res3); + printk(KERN_DEBUG " res4 = 0x%04x\n", frame->desc.res4); + printk(KERN_DEBUG " tx_ctl = 0x%04x\n", frame->desc.tx_ctl); + + printk(KERN_DEBUG "IEEE 802.11 header:\n"); + printk(KERN_DEBUG " frame_ctl = 0x%04x\n", + frame->p80211.frame_ctl); + printk(KERN_DEBUG " duration_id = 0x%04x\n", + frame->p80211.duration_id); + printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr1[0], frame->p80211.addr1[1], + frame->p80211.addr1[2], frame->p80211.addr1[3], + frame->p80211.addr1[4], frame->p80211.addr1[5]); + printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr2[0], frame->p80211.addr2[1], + frame->p80211.addr2[2], frame->p80211.addr2[3], + frame->p80211.addr2[4], frame->p80211.addr2[5]); + printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr3[0], frame->p80211.addr3[1], + frame->p80211.addr3[2], frame->p80211.addr3[3], + frame->p80211.addr3[4], frame->p80211.addr3[5]); + printk(KERN_DEBUG " seq_ctl = 0x%04x\n", + frame->p80211.seq_ctl); + printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p80211.addr4[0], frame->p80211.addr4[1], + frame->p80211.addr4[2], frame->p80211.addr4[3], + frame->p80211.addr4[4], frame->p80211.addr4[5]); + printk(KERN_DEBUG " data_len = 0x%04x\n", + frame->p80211.data_len); + + printk(KERN_DEBUG "IEEE 802.3 header:\n"); + printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_dest[0], frame->p8023.h_dest[1], + frame->p8023.h_dest[2], frame->p8023.h_dest[3], + frame->p8023.h_dest[4], frame->p8023.h_dest[5]); + printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", + frame->p8023.h_source[0], frame->p8023.h_source[1], + frame->p8023.h_source[2], frame->p8023.h_source[3], + frame->p8023.h_source[4], frame->p8023.h_source[5]); + printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); + + printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); + printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); + printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); + printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); + printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", + frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); + printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); +} +#endif + +/* + * Interrupt handler + */ +void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs) +{ + dldwd_priv_t *priv = (dldwd_priv_t *) dev_id; + hermes_t *hw = &priv->hw; + struct net_device *dev = &priv->ndev; + int count = IRQ_LOOP_MAX; + uint16_t evstat, events; + static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */ + + if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state)) + BUG(); + + if (! dldwd_irqs_allowed(priv)) { + clear_bit(DLDWD_STATE_INIRQ, &priv->state); + return; + } + + DEBUG(3, "%s: dldwd_interrupt() irq %d\n", priv->ndev.name, irq); + + while (1) { + if (jiffies != old_time) + timecount = 0; + if ( (++timecount > 50) || (! count--) ) { + printk(KERN_CRIT "%s: IRQ handler is looping too \ +much! Shutting down.\n", + dev->name); + /* Perform an emergency shutdown */ + clear_bit(DLDWD_STATE_DOIRQ, &priv->state); + hermes_set_irqmask(hw, 0); + break; + } + + evstat = hermes_read_regn(hw, EVSTAT); + DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n", + count, evstat, hw->inten); + + events = evstat & hw->inten; + + if (! events) { + if (netif_queue_stopped(dev)) { + /* There seems to be a firmware bug which + sometimes causes the card to give an + interrupt with no event set, when there + sould be a Tx completed event. */ + DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n", + dev->name, (int)hermes_read_regn(hw, ALLOCFID)); + events = HERMES_EV_TX | HERMES_EV_ALLOC; + } else /* Nothing's happening, we're done */ + break; + } + + /* Check the card hasn't been removed */ + if (! hermes_present(hw)) { + DEBUG(0, "dldwd_interrupt(): card removed\n"); + break; + } + + if (events & HERMES_EV_TICK) + __dldwd_ev_tick(priv, hw); + if (events & HERMES_EV_WTERR) + __dldwd_ev_wterr(priv, hw); + if (events & HERMES_EV_INFDROP) + __dldwd_ev_infdrop(priv, hw); + if (events & HERMES_EV_INFO) + __dldwd_ev_info(priv, hw); + if (events & HERMES_EV_RX) + __dldwd_ev_rx(priv, hw); + if (events & HERMES_EV_TXEXC) + __dldwd_ev_txexc(priv, hw); + if (events & HERMES_EV_TX) + __dldwd_ev_tx(priv, hw); + if (events & HERMES_EV_ALLOC) + __dldwd_ev_alloc(priv, hw); + + hermes_write_regn(hw, EVACK, events); + } + + clear_bit(DLDWD_STATE_INIRQ, &priv->state); +} + +static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw) +{ + printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name); +} + +static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw) +{ + /* This seems to happen a fair bit under load, but ignoring it + seems to work fine...*/ + DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", + priv->ndev.name); +} + +static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw) +{ + printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name); +} + +static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw) +{ + DEBUG(3, "%s: Information frame received.\n", priv->ndev.name); + /* We don't actually do anything about it - we assume the MAC + controller can deal with it */ +} + +static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + struct iw_statistics *wstats = &priv->wstats; + struct sk_buff *skb = NULL; + uint16_t rxfid, status; + int length, data_len, data_off; + char *p; + struct dldwd_frame_hdr hdr; + struct ethhdr *eh; + int err; + + rxfid = hermes_read_regn(hw, RXFID); + DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid); + + /* We read in the entire frame header here. This isn't really + necessary, since we ignore most of it, but it's + conceptually simpler. We can tune this later if + necessary. */ + err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0); + if (err) { + printk(KERN_ERR "%s: error %d reading frame header. " + "Frame dropped.\n", dev->name, err); + stats->rx_errors++; + goto drop; + } + + status = le16_to_cpu(hdr.desc.status); + + if (status & HERMES_RXSTAT_ERR) { + if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) { + stats->rx_crc_errors++; + printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n", + dev->name); + show_rx_frame(&hdr); + } else if ((status & HERMES_RXSTAT_ERR) + == HERMES_RXSTAT_UNDECRYPTABLE) { + wstats->discard.code++; + printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n", + dev->name); + } else { + wstats->discard.misc++; + printk("%s: Unknown Rx error (0x%x). Frame dropped.\n", + dev->name, status & HERMES_RXSTAT_ERR); + } + stats->rx_errors++; + goto drop; + } + + length = le16_to_cpu(hdr.p80211.data_len); + /* Yes, you heard right, that's le16. 802.2 and 802.3 are + big-endian, but 802.11 is little-endian believe it or + not. */ + /* Correct. 802.3 is big-endian byte order and little endian bit + * order, whereas 802.11 is little endian for both byte and bit + * order. That's specified in the 802.11 spec. - Jean II */ + + /* Sanity check */ + if (length > MAX_FRAME_SIZE) { + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", + dev->name, length); + stats->rx_length_errors++; + stats->rx_errors++; + goto drop; + } + + /* We need space for the packet data itself, plus an ethernet + header, plus 2 bytes so we can align the IP header on a + 32bit boundary, plus 1 byte so we can read in odd length + packets from the card, which has an IO granularity of 16 + bits */ + skb = dev_alloc_skb(length+ETH_HLEN+2+1); + if (!skb) { + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", + dev->name); + stats->rx_dropped++; + goto drop; + } + + skb_reserve(skb, 2); /* This way the IP header is aligned */ + + /* Handle decapsulation */ + switch (status & HERMES_RXSTAT_MSGTYPE) { + /* These both indicate a SNAP within 802.2 LLC within + 802.3 within 802.11 frame which we'll need to + de-encapsulate. IEEE and ISO OSI have a lot to + answer for. */ + case HERMES_RXSTAT_1042: + case HERMES_RXSTAT_TUNNEL: + data_len = length - ENCAPS_OVERHEAD; + data_off = sizeof(hdr); + + eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); + + memcpy(eh, &hdr.p8023, sizeof(hdr.p8023)); + eh->h_proto = hdr.ethertype; + + break; + + /* Otherwise, we just throw the whole thing in, and hope + the protocol layer can deal with it as 802.3 */ + default: + data_len = length; + data_off = P8023_OFFSET; + break; + } + + p = skb_put(skb, data_len); + if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len), + rxfid, data_off) != 0) { + printk(KERN_WARNING "%s: Error reading packet data\n", + dev->name); + stats->rx_errors++; + goto drop; + } + + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + /* Process the wireless stats if needed */ + dldwd_stat_gather(dev, skb, &hdr); + + /* Pass the packet to the networking stack */ + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += length; + + return; + + drop: + if (skb) + dev_kfree_skb_irq(skb); + return; +} + +static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + printk(KERN_WARNING "%s: Tx error!\n", dev->name); + + netif_wake_queue(dev); + stats->tx_errors++; +} + +static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw) +{ + struct net_device *dev = &priv->ndev; + struct net_device_stats *stats = &priv->stats; + + DEBUG(3, "%s: Transmit completed\n", dev->name); + + stats->tx_packets++; + netif_wake_queue(dev); +} + +static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw) +{ + uint16_t allocfid; + + allocfid = hermes_read_regn(hw, ALLOCFID); + DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid); + + /* For some reason we don't seem to get transmit completed events properly */ + if (allocfid == priv->txfid) + __dldwd_ev_tx(priv, hw); + +/* hermes_write_regn(hw, ALLOCFID, 0); */ +} + +/* + * struct net_device methods + */ + +static int dldwd_init(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + hermes_id_t nickbuf; + uint16_t reclen; + int len; + char *vendor_str; + uint32_t firmver; + + TRACE_ENTER("dldwd"); + + dldwd_lock(priv); + + err = hermes_reset(hw); + if (err != 0) { + printk(KERN_ERR "%s: failed to reset hardware\n", dev->name); + goto out; + } + + /* Get the firmware version */ + err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info); + if (err) { + printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n", + dev->name, err); + memset(&priv->firmware_info, 0, sizeof(priv->firmware_info)); + } + + firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor; + + /* Determine capabilities from the firmware version */ + + switch (priv->firmware_info.vendor) { + case 0x1: + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout, + * ELSA, Melco, HP, IBM, Dell 1150 cards */ + vendor_str = "Lucent"; + /* Lucent MAC : 00:60:1D:* & 00:02:2D:* */ + + priv->firmware_type = FIRMWARE_TYPE_LUCENT; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = (firmver >= 0x60006); + priv->has_ibss_any = (firmver >= 0x60010); + priv->has_wep = (firmver >= 0x40020); + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell + Gold cards from the others? */ + priv->has_mwo = (firmver >= 0x60000); + priv->has_pm = (firmver >= 0x40020); + /* Tested with Lucent firmware : + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 => Jean II + * Tested CableTron firmware : 4.32 => Anton */ + break; + case 0x2: + vendor_str = "Generic Prism II"; + /* Note : my Intel card report this value, but I can't do + * much with it, so I guess it's broken - Jean II */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = (firmver <= 0x10001); + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: no idea if this is right */ + priv->has_wep = (firmver >= 0x20000); + priv->has_big_wep = 1; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); + /* Tested with Intel firmware : 1.01 => Jean II */ + /* Note : firmware 1.01 is *seriously* broken */ + break; + case 0x3: + vendor_str = "Samsung"; + /* To check - Should cover Samsung & Compaq */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 0; /* FIXME */ + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); /* FIXME */ + break; + case 0x6: + vendor_str = "LinkSys/D-Link"; + /* To check */ + + priv->firmware_type = FIRMWARE_TYPE_PRISM2; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); /* FIXME */ + break; +#if 0 + case 0x???: /* Could someone help here ??? */ + vendor_str = "Symbol"; + /* Symbol , 3Com AirConnect, Ericsson WLAN */ + + priv->firmware_type = FIRMWARE_TYPE_SYMBOL; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 1; + priv->has_ibss = 0; /* FIXME: available in later firmwares */ + priv->has_wep = (firmver >= 0x20000); /* FIXME */ + priv->has_big_wep = 1; /* Probably RID_SYMBOL_KEY_LENGTH */ + priv->has_mwo = 0; + priv->has_pm = (firmver >= 0x20000); + break; +#endif + default: + vendor_str = "UNKNOWN"; + + priv->firmware_type = 0; + priv->broken_reset = 0; + priv->broken_allocate = 0; + priv->has_port3 = 0; + priv->has_ibss = 0; + priv->has_wep = 0; + priv->has_big_wep = 0; + priv->has_mwo = 0; + priv->has_pm = 0; + } + + printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n", + dev->name, priv->firmware_info.id, priv->firmware_info.vendor, + vendor_str, priv->firmware_info.major, priv->firmware_info.minor); + + if ((priv->broken_reset) || (priv->broken_allocate)) + printk(KERN_INFO "%s: Buggy firmware, please upgrade ASAP.\n", dev->name); + if (priv->has_port3) + printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name); + if (priv->has_ibss) + printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n", + dev->name); + if (priv->has_wep) { + printk(KERN_INFO "%s: WEP supported, ", dev->name); + if (priv->has_big_wep) + printk("\"128\"-bit key.\n"); + else + printk("40-bit key."); + } + + /* Get the MAC address */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR, + ETH_ALEN, NULL, dev->dev_addr); + if (err) { + printk(KERN_WARNING "%s: failed to read MAC address!\n", + dev->name); + goto out; + } + + printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", + dev->name, dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], + dev->dev_addr[5]); + + /* Get the station name */ + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME, + sizeof(nickbuf), &reclen, &nickbuf); + if (err) { + printk(KERN_ERR "%s: failed to read station name!n", + dev->name); + goto out; + } + if ( nickbuf.len ) + len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len)); + else + len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen); + memcpy(priv->nick, &nickbuf.val, len); + priv->nick[len] = '\0'; + + printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick); + + /* Get allowed channels */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask); + if (err) { + printk(KERN_ERR "%s: failed to read channel list!\n", + dev->name); + goto out; + } + + /* Get initial AP density */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density); + if (err) { + printk(KERN_ERR "%s: failed to read AP density!\n", dev->name); + goto out; + } + + /* Get initial RTS threshold */ + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name); + goto out; + } + + /* Get initial fragmentation settings */ + if (priv->has_mwo) + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, + &priv->mwo_robust); + else + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, + &priv->frag_thresh); + if (err) { + printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name); + goto out; + } + + /* Set initial bitrate control*/ + priv->tx_rate_ctrl = 3; + + /* Power management setup */ + if (priv->has_pm) { + priv->pm_on = 0; + priv->pm_mcast = 1; + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, + &priv->pm_period); + if (err) { + printk(KERN_ERR "%s: failed to read power management period!\n", + dev->name); + goto out; + } + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, + &priv->pm_timeout); + if (err) { + printk(KERN_ERR "%s: failed to read power management timeout!\n", + dev->name); + goto out; + } + } + + /* Set up the default configuration */ + priv->iw_mode = IW_MODE_INFRA; + /* By default use IEEE/IBSS ad-hoc mode if we have it */ + priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss); + set_port_type(priv); + + priv->promiscuous = 0; + priv->allmulti = 0; + priv->wep_on = 0; + priv->tx_key = 0; + + printk(KERN_INFO "%s: ready\n", dev->name); + + out: + dldwd_unlock(priv); + + TRACE_EXIT("dldwd"); + + return err; +} + +static int dldwd_open(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dev_link_t *link = &priv->link; + int err = 0; + + TRACE_ENTER(dev->name); + + link->open++; + MOD_INC_USE_COUNT; + netif_device_attach(dev); + + err = dldwd_reset(priv); + if (err) + dldwd_stop(dev); + else + netif_start_queue(dev); + + TRACE_EXIT(dev->name); + + return err; +} + +static int dldwd_stop(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + dev_link_t *link = &priv->link; + + TRACE_ENTER(dev->name); + + netif_stop_queue(dev); + + dldwd_shutdown(priv); + + link->open--; + + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + + MOD_DEC_USE_COUNT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static struct net_device_stats *dldwd_get_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + + return &priv->stats; +} + +static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_t *hw = &priv->hw; + struct iw_statistics *wstats = &priv->wstats; + int err = 0; + hermes_commsqual_t cq; + + dldwd_lock(priv); + + if (priv->port_type == 3) { + memset(&wstats->qual, 0, sizeof(wstats->qual)); +#ifdef WIRELESS_SPY + /* If a spy address is defined, we report stats of the + * first spy address - Jean II */ + if (priv->spy_number > 0) { + wstats->qual.qual = priv->spy_stat[0].qual; + wstats->qual.level = priv->spy_stat[0].level; + wstats->qual.noise = priv->spy_stat[0].noise; + wstats->qual.updated = priv->spy_stat[0].updated; + } +#endif /* WIRELESS_SPY */ + } else { + err = hermes_read_commsqual(hw, USER_BAP, &cq); + + DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + + /* Why are we using MIN/MAX ? We don't really care + * if the value goes above max, because we export the + * raw dBm values anyway. The normalisation should be done + * in user space - Jean II */ + wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0); + wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95; + wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95; + wstats->qual.updated = 7; + } + + dldwd_unlock(priv); + + if (err) + return NULL; + + return wstats; +} + +#ifdef WIRELESS_SPY +static inline void dldwd_spy_gather(struct net_device *dev, + u_char *mac, + hermes_commsqual_t *cq) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + int i; + + /* Gather wireless spy statistics: for each packet, compare the + * source address with out list, and if match, get the stats... */ + for (i = 0; i < priv->spy_number; i++) + if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { + priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0); + priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95; + priv->spy_stat[i].updated = 7; + } +} +#endif /* WIRELESS_SPY */ + +static void dldwd_stat_gather(struct net_device *dev, + struct sk_buff *skb, + struct dldwd_frame_hdr *hdr) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + hermes_commsqual_t cq; + + /* Using spy support with lots of Rx packets, like in an + * infrastructure (AP), will really slow down everything, because + * the MAC address must be compared to each entry of the spy list. + * If the user really asks for it (set some address in the + * spy list), we do it, but he will pay the price. + * Note that to get here, you need both WIRELESS_SPY + * compiled in AND some addresses in the list !!! + */ +#ifdef WIRELESS_EXT + /* Note : gcc will optimise the whole section away if + * WIRELESS_SPY is not defined... - Jean II */ + if ( +#ifdef WIRELESS_SPY + (priv->spy_number > 0) || +#endif + 0 ) + { + u_char *stats = (u_char *) &(hdr->desc.q_info); + /* This code may look strange. Everywhere we are using 16 bit + * ints except here. I've verified that these are are the + * correct values. Please check on PPC - Jean II */ + cq.signal = stats[1]; /* High order byte */ + cq.noise = stats[0]; /* Low order byte */ + cq.qual = stats[0] - stats[1]; /* Better than nothing */ + + DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name, + cq.qual, cq.signal, cq.noise); + +#ifdef WIRELESS_SPY + dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq); +#endif + } +#endif /* WIRELESS_EXT */ +} + +struct p8022_hdr encaps_hdr = { + 0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8} +}; + +static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t txfid = priv->txfid; + char *p; + struct ethhdr *eh; + int len, data_len, data_off; + struct dldwd_frame_hdr hdr; + hermes_response_t resp; + + if (! netif_running(dev)) { + printk(KERN_ERR "%s: Tx on stopped device!\n", + dev->name); + return 1; + + } + + if (netif_queue_stopped(dev)) { + printk(KERN_ERR "%s: Tx while transmitter busy!\n", + dev->name); + return 1; + } + + dldwd_lock(priv); + + /* Length of the packet body */ + len = MAX(skb->len - ETH_HLEN, ETH_ZLEN); + + eh = (struct ethhdr *)skb->data; + + /* Build the IEEE 802.11 header */ + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN); + memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN); + hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA; + + /* Encapsulate Ethernet-II frames */ + if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ + data_len = len; + data_off = sizeof(hdr); + p = skb->data + ETH_HLEN; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD); + + /* 802.3 header */ + memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN); + memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN); + hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD); + + /* 802.2 header */ + memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr)); + + hdr.ethertype = eh->h_proto; + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } else { /* IEEE 802.3 frame */ + data_len = len + ETH_HLEN; + data_off = P8023_OFFSET; + p = skb->data; + + /* 802.11 header */ + hdr.p80211.data_len = cpu_to_le16(len); + err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET, + txfid, 0); + if (err) { + printk(KERN_ERR + "%s: Error %d writing packet header to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + } + + /* Round up for odd length packets */ + err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); + if (err) { + printk(KERN_ERR "%s: Error %d writing packet data to BAP\n", + dev->name, err); + stats->tx_errors++; + goto fail; + } + + + /* Finally, we actually initiate the send */ + err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp); + if (err) { + printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err); + stats->tx_errors++; + goto fail; + } + + dev->trans_start = jiffies; + stats->tx_bytes += data_off + data_len; + + netif_stop_queue(dev); + + dldwd_unlock(priv); + + dev_kfree_skb(skb); + + return 0; + fail: + + dldwd_unlock(priv); + return err; +} + +static void dldwd_tx_timeout(struct net_device *dev) +{ + dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv; + struct net_device_stats *stats = &priv->stats; + int err = 0; + + printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name); + + stats->tx_errors++; + + err = dldwd_reset(priv); + if (err) + printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", + dev->name, err); + else { + dev->trans_start = jiffies; + netif_wake_queue(dev); + } +} + +static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int ptype; + struct iw_range range; + int numrates; + int i, k; + + TRACE_ENTER(dev->name); + + err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range)); + if (err) + return err; + + rrq->length = sizeof(range); + + dldwd_lock(priv); + ptype = priv->port_type; + dldwd_unlock(priv); + + memset(&range, 0, sizeof(range)); + + /* Much of this shamelessly taken from wvlan_cs.c. No idea + * what it all means -dgibson */ + range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ + + /* Set available channels/frequencies */ + range.num_channels = NUM_CHANNELS; + k = 0; + for (i = 0; i < NUM_CHANNELS; i++) { + if (priv->channel_mask & (1 << i)) { + range.freq[k].i = i + 1; + range.freq[k].m = channel_frequency[i] * 100000; + range.freq[k].e = 1; + k++; + } + + if (k >= IW_MAX_FREQUENCIES) + break; + } + range.num_frequency = k; + + range.sensitivity = 3; + + if ((ptype == 3) && (priv->spy_number == 0)){ + /* Quality stats meaningless in ad-hoc mode */ + range.max_qual.qual = 0; + range.max_qual.level = 0; + range.max_qual.noise = 0; + } else { + range.max_qual.qual = 0x8b - 0x2f; + range.max_qual.level = 0x2f - 0x95 - 1; + range.max_qual.noise = 0x2f - 0x95 - 1; + } + + err = dldwd_hw_get_bitratelist(priv, &numrates, + range.bitrate, IW_MAX_BITRATES); + if (err) + return err; + range.num_bitrates = numrates; + + /* Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface. May be use for QoS stuff... + * Jean II */ + if(numrates > 2) + range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ + else + range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ + + range.min_rts = 0; + range.max_rts = 2347; + range.min_frag = 256; + range.max_frag = 2346; + + dldwd_lock(priv); + if (priv->has_wep) { + range.max_encoding_tokens = MAX_KEYS; + + range.encoding_size[0] = SMALL_KEY_SIZE; + range.num_encoding_sizes = 1; + + if (priv->has_big_wep) { + range.encoding_size[1] = LARGE_KEY_SIZE; + range.num_encoding_sizes = 2; + } + } else { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } + dldwd_unlock(priv); + + range.min_pmp = 0; + range.max_pmp = 65535000; + range.min_pmt = 0; + range.max_pmt = 65535 * 1000; /* ??? */ + range.pmp_flags = IW_POWER_PERIOD; + range.pmt_flags = IW_POWER_TIMEOUT; + range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R; + + range.num_txpower = 1; + range.txpower[0] = 15; /* 15dBm */ + range.txpower_capa = IW_TXPOW_DBM; + + if (copy_to_user(rrq->pointer, &range, sizeof(range))) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + int setindex = priv->tx_key; + int enable = priv->wep_on; + int auth = priv->wep_auth; + uint16_t xlen = 0; + int err = 0; + char keybuf[MAX_KEY_SIZE]; + + if (erq->pointer) { + /* We actually have a key to set */ + + if (copy_from_user(keybuf, erq->pointer, erq->length)) + return -EFAULT; + } + + dldwd_lock(priv); + + if (erq->pointer) { + if (erq->length > MAX_KEY_SIZE) { + err = -E2BIG; + goto out; + } + + if ( (erq->length > LARGE_KEY_SIZE) + || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE)) ) { + err = -EINVAL; + goto out; + } + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + if (erq->length > SMALL_KEY_SIZE) { + xlen = LARGE_KEY_SIZE; + } else if (erq->length > 0) { + xlen = SMALL_KEY_SIZE; + } else + xlen = 0; + + /* Switch on WEP if off */ + if ((!enable) && (xlen > 0)) { + setindex = index; + enable = 1; + } + } else { + /* Important note : if the user do "iwconfig eth0 enc off", + * we will arrive there with an index of -1. This is valid + * but need to be taken care off... Jean II */ + if ((index < 0) || (index >= MAX_KEYS)) { + if((index != -1) || (erq->flags == 0)) { + err = -EINVAL; + goto out; + } + } else { + /* Set the index : Check that the key is valid */ + if(priv->keys[index].len == 0) { + err = -EINVAL; + goto out; + } + setindex = index; + } + } + + if (erq->flags & IW_ENCODE_DISABLED) + enable = 0; + /* Only for symbol cards (so far) - Jean II */ + if (erq->flags & IW_ENCODE_OPEN) + auth = 1; + if (erq->flags & IW_ENCODE_RESTRICTED) + auth = 2; /* If all key are 128 -> should be 3 ??? */ + /* Agree with master wep setting */ + if (enable == 0) + auth = 0; + else if(auth == 0) + auth = 1; /* Encryption require some authentication */ + + if (erq->pointer) { + priv->keys[index].len = cpu_to_le16(xlen); + memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data)); + memcpy(priv->keys[index].data, keybuf, erq->length); + } + priv->tx_key = setindex; + priv->wep_on = enable; + priv->wep_auth = auth; + + out: + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + int index = (erq->flags & IW_ENCODE_INDEX) - 1; + uint16_t xlen = 0; + char keybuf[MAX_KEY_SIZE]; + + + dldwd_lock(priv); + + if ((index < 0) || (index >= MAX_KEYS)) + index = priv->tx_key; + + erq->flags = 0; + if (! priv->wep_on) + erq->flags |= IW_ENCODE_DISABLED; + erq->flags |= index + 1; + + /* Only for symbol cards - Jean II */ + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) { + switch(priv->wep_auth) { + case 1: + erq->flags |= IW_ENCODE_OPEN; + break; + case 2: + case 3: + erq->flags |= IW_ENCODE_RESTRICTED; + break; + case 0: + default: + break; + } + } + + xlen = le16_to_cpu(priv->keys[index].len); + + erq->length = xlen; + + if (erq->pointer) { + memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE); + } + + dldwd_unlock(priv); + + if (erq->pointer) { + if (copy_to_user(erq->pointer, keybuf, xlen)) + return -EFAULT; + } + + return 0; +} + +static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + + /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it + * anyway... - Jean II */ + + memset(&essidbuf, 0, sizeof(essidbuf)); + + if (erq->flags) { + if (erq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + if (copy_from_user(&essidbuf, erq->pointer, erq->length)) + return -EFAULT; + + essidbuf[erq->length] = '\0'; + } + + dldwd_lock(priv); + + memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq) +{ + dldwd_priv_t *priv = dev->priv; + char essidbuf[IW_ESSID_MAX_SIZE+1]; + int active; + int err = 0; + + TRACE_ENTER(dev->name); + + err = dldwd_hw_get_essid(priv, &active, essidbuf); + if (err) + return err; + + erq->flags = 1; + erq->length = strlen(essidbuf) + 1; + if (erq->pointer) + if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) + return -EFAULT; + + TRACE_EXIT(dev->name); + + return 0; +} + +static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + if (nrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + memset(nickbuf, 0, sizeof(nickbuf)); + + if (copy_from_user(nickbuf, nrq->pointer, nrq->length)) + return -EFAULT; + + nickbuf[nrq->length] = '\0'; + + dldwd_lock(priv); + + memcpy(priv->nick, nickbuf, sizeof(priv->nick)); + + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) +{ + dldwd_priv_t *priv = dev->priv; + char nickbuf[IW_ESSID_MAX_SIZE+1]; + + dldwd_lock(priv); + memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1); + dldwd_unlock(priv); + + nrq->length = strlen(nickbuf)+1; + + if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf))) + return -EFAULT; + + return 0; +} + +static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) +{ + dldwd_priv_t *priv = dev->priv; + int chan = -1; + + /* We can only use this in Ad-Hoc demo mode to set the operating + * frequency, or in IBSS mode to set the frequency where the IBSS + * will be created - Jean II */ + if (priv->iw_mode != IW_MODE_ADHOC) + return -EOPNOTSUPP; + + if ( (frq->e == 0) && (frq->m <= 1000) ) { + /* Setting by channel number */ + chan = frq->m; + } else { + /* Setting by frequency - search the table */ + int mult = 1; + int i; + + for (i = 0; i < (6 - frq->e); i++) + mult *= 10; + + for (i = 0; i < NUM_CHANNELS; i++) + if (frq->m == (channel_frequency[i] * mult)) + chan = i+1; + } + + if ( (chan < 1) || (chan > NUM_CHANNELS) || + ! (priv->channel_mask & (1 << (chan-1)) ) ) + return -EINVAL; + + dldwd_lock(priv); + priv->channel = chan; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + uint16_t val; + int err; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val); + dldwd_unlock(priv); + + if (err) + return err; + + srq->value = val; + srq->fixed = 0; /* auto */ + + return 0; +} + +static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq) +{ + dldwd_priv_t *priv = dev->priv; + int val = srq->value; + + if ((val < 1) || (val > 3)) + return -EINVAL; + + dldwd_lock(priv); + priv->ap_density = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = rrq->value; + + if (rrq->disabled) + val = 2347; + + if ( (val < 0) || (val > 2347) ) + return -EINVAL; + + dldwd_lock(priv); + priv->rts_thresh = val; + dldwd_unlock(priv); + + return 0; +} + +static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + dldwd_lock(priv); + + if (priv->has_mwo) { + if (frq->disabled) + priv->mwo_robust = 0; + else { + if (frq->fixed) + printk(KERN_WARNING "%s: Fixed fragmentation not \ +supported on this firmware. Using MWO robust instead.\n", dev->name); + priv->mwo_robust = 1; + } + } else { + if (frq->disabled) + priv->frag_thresh = 2346; + else { + if ( (frq->value < 256) || (frq->value > 2346) ) + err = -EINVAL; + else + priv->frag_thresh = frq->value & ~0x1; /* must be even */ + } + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + + dldwd_lock(priv); + + if (priv->has_mwo) { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val); + if (err) + val = 0; + + frq->value = val ? 2347 : 0; + frq->disabled = ! val; + frq->fixed = 0; + } else { + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val); + if (err) + val = 0; + + frq->value = val; + frq->disabled = (val >= 2346); + frq->fixed = 1; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + int rate_ctrl = -1; + int fixed, upto; + int brate; + int i; + + dldwd_lock(priv); + + /* Normalise value */ + brate = rrq->value / 500000; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ + if (! rrq->fixed) { + if (brate > 0) + brate = -brate; + else + brate = -22; + } + + for (i = 0; i < NUM_RATES; i++) + if (rate_list[i] == brate) { + rate_ctrl = i; + break; + } + + if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) ) + err = -EINVAL; + else + priv->tx_rate_ctrl = rate_ctrl; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + switch(brate) { + case 0: + fixed = 0x0; + upto = 0x15; + break; + case 2: + fixed = 0x1; + upto = 0x1; + break; + case 4: + fixed = 0x2; + upto = 0x3; + break; + case 11: + fixed = 0x4; + upto = 0x7; + break; + case 22: + fixed = 0x8; + upto = 0x15; + break; + default: + fixed = 0x0; + upto = 0x0; + } + if (rrq->fixed) + rate_ctrl = fixed; + else + rate_ctrl = upto; + if (rate_ctrl == 0) + err = -EINVAL; + else + priv->tx_rate_ctrl = rate_ctrl; + break; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t val; + int brate = 0; + + dldwd_lock(priv); + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val); + if (err) + goto out; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */ + brate = rate_list[val]; + + if (brate < 0) { + rrq->fixed = 0; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + + if (val == 6) + brate = 11; + else + brate = 2*val; + } else + rrq->fixed = 1; + break; + case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */ + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ + /* Check if auto or fixed (crude approximation) */ + if((val & 0x1) && (val > 1)) { + rrq->fixed = 0; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val); + if (err) + goto out; + } else + rrq->fixed = 1; + + if(val >= 8) + brate = 22; + else if(val >= 4) + brate = 11; + else if(val >= 2) + brate = 4; + else + brate = 2; + break; + } + + rrq->value = brate * 500000; + rrq->disabled = 0; + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + int err = 0; + + + dldwd_lock(priv); + + if (prq->disabled) { + priv->pm_on = 0; + } else { + switch (prq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + priv->pm_mcast = 0; + priv->pm_on = 1; + break; + case IW_POWER_ALL_R: + priv->pm_mcast = 1; + priv->pm_on = 1; + break; + case IW_POWER_ON: + /* No flags : but we may have a value - Jean II */ + break; + default: + err = -EINVAL; + } + if (err) + goto out; + + if (prq->flags & IW_POWER_TIMEOUT) { + priv->pm_on = 1; + priv->pm_timeout = prq->value / 1000; + } + if (prq->flags & IW_POWER_PERIOD) { + priv->pm_on = 1; + priv->pm_period = prq->value / 1000; + } + /* It's valid to not have a value if we are just toggling + * the flags... Jean II */ + if(!priv->pm_on) { + err = -EINVAL; + goto out; + } + } + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + uint16_t enable, period, timeout, mcast; + + dldwd_lock(priv); + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout); + if (err) + goto out; + + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast); + if (err) + goto out; + + prq->disabled = !enable; + /* Note : by default, display the period */ + if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + prq->flags = IW_POWER_TIMEOUT; + prq->value = timeout * 1000; + } else { + prq->flags = IW_POWER_PERIOD; + prq->value = period * 1000; + } + if (mcast) + prq->flags |= IW_POWER_ALL_R; + else + prq->flags |= IW_POWER_UNICAST_R; + + out: + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int val = *( (int *) wrq->u.name ); + int err = 0; + + dldwd_lock(priv); + switch (val) { + case 0: /* Try to do IEEE ad-hoc mode */ + if (! priv->has_ibss) { + err = -EINVAL; + break; + } + priv->prefer_port3 = 0; + + break; + + case 1: /* Try to do Lucent proprietary ad-hoc mode */ + if (! priv->has_port3) { + err = -EINVAL; + break; + } + priv->prefer_port3 = 1; + break; + + default: + err = -EINVAL; + } + + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) +{ + dldwd_priv_t *priv = dev->priv; + int *val = (int *)wrq->u.name; + + dldwd_lock(priv); + *val = priv->prefer_port3; + dldwd_unlock(priv); + + return 0; +} + +/* Spy is used for link quality/strength measurements in Ad-Hoc mode + * Jean II */ +static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + int number = srq->length; + int i; + int err = 0; + + /* Check the number of addresses */ + if (number > IW_MAX_SPY) + return -E2BIG; + + /* Get the data in the driver */ + if (srq->pointer) { + if (copy_from_user(address, srq->pointer, + sizeof(struct sockaddr) * number)) + return -EFAULT; + } + + /* Make sure nobody mess with the structure while we do */ + dldwd_lock(priv); + + /* dldwd_lock() doesn't disable interrupts, so make sure the + * interrupt rx path don't get confused while we copy */ + priv->spy_number = 0; + + if (number > 0) { + /* Extract the addresses */ + for (i = 0; i < number; i++) + memcpy(priv->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(priv->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + /* Set number of addresses */ + priv->spy_number = number; + } + + /* Time to show what we have done... */ + DEBUG(0, "%s: New spy list:\n", dev->name); + for (i = 0; i < number; i++) { + DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, i+1, + priv->spy_address[i][0], priv->spy_address[i][1], + priv->spy_address[i][2], priv->spy_address[i][3], + priv->spy_address[i][4], priv->spy_address[i][5]); + } + + /* Now, let the others play */ + dldwd_unlock(priv); + + return err; +} + +static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq) +{ + dldwd_priv_t *priv = dev->priv; + struct sockaddr address[IW_MAX_SPY]; + struct iw_quality spy_stat[IW_MAX_SPY]; + int number; + int i; + + dldwd_lock(priv); + + number = priv->spy_number; + if ((number > 0) && (srq->pointer)) { + /* Create address struct */ + for (i = 0; i < number; i++) { + memcpy(address[i].sa_data, priv->spy_address[i], + ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats */ + /* In theory, we should disable irqs while copying the stats + * because the rx path migh update it in the middle... + * Bah, who care ? - Jean II */ + memcpy(&spy_stat, priv->spy_stat, + sizeof(struct iw_quality) * IW_MAX_SPY); + for (i=0; i < number; i++) + priv->spy_stat[i].updated = 0; + } + + dldwd_unlock(priv); + + /* Push stuff to user space */ + srq->length = number; + if(copy_to_user(srq->pointer, address, + sizeof(struct sockaddr) * number)) + return -EFAULT; + if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number), + &spy_stat, sizeof(struct iw_quality) * number)) + return -EFAULT; + + return 0; +} + +static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + dldwd_priv_t *priv = dev->priv; + struct iwreq *wrq = (struct iwreq *)rq; + int err = 0; + int changed = 0; + + TRACE_ENTER(dev->name); + + switch (cmd) { + case SIOCGIWNAME: + DEBUG(1, "%s: SIOCGIWNAME\n", dev->name); + strcpy(wrq->u.name, "IEEE 802.11-DS"); + break; + + case SIOCGIWAP: + DEBUG(1, "%s: SIOCGIWAP\n", dev->name); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data); + break; + + case SIOCGIWRANGE: + DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name); + err = dldwd_ioctl_getiwrange(dev, &wrq->u.data); + break; + + case SIOCSIWMODE: + DEBUG(1, "%s: SIOCSIWMODE\n", dev->name); + dldwd_lock(priv); + switch (wrq->u.mode) { + case IW_MODE_ADHOC: + if (! (priv->has_ibss || priv->has_port3) ) + err = -EINVAL; + else { + priv->iw_mode = IW_MODE_ADHOC; + changed = 1; + } + break; + + case IW_MODE_INFRA: + priv->iw_mode = IW_MODE_INFRA; + changed = 1; + break; + + default: + err = -EINVAL; + break; + } + set_port_type(priv); + dldwd_unlock(priv); + break; + + case SIOCGIWMODE: + DEBUG(1, "%s: SIOCGIWMODE\n", dev->name); + dldwd_lock(priv); + wrq->u.mode = priv->iw_mode; + dldwd_unlock(priv); + break; + + case SIOCSIWENCODE: + DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding); + if (! err) + changed = 1; + break; + + case SIOCGIWENCODE: + DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name); + if (! priv->has_wep) { + err = -EOPNOTSUPP; + break; + } + + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding); + break; + + case SIOCSIWESSID: + DEBUG(1, "%s: SIOCSIWESSID\n", dev->name); + err = dldwd_ioctl_setessid(dev, &wrq->u.essid); + if (! err) + changed = 1; + break; + + case SIOCGIWESSID: + DEBUG(1, "%s: SIOCGIWESSID\n", dev->name); + err = dldwd_ioctl_getessid(dev, &wrq->u.essid); + break; + + case SIOCSIWNICKN: + DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name); + err = dldwd_ioctl_setnick(dev, &wrq->u.data); + if (! err) + changed = 1; + break; + + case SIOCGIWNICKN: + DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name); + err = dldwd_ioctl_getnick(dev, &wrq->u.data); + break; + + case SIOCGIWFREQ: + DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name); + wrq->u.freq.m = dldwd_hw_get_freq(priv); + wrq->u.freq.e = 1; + break; + + case SIOCSIWFREQ: + DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name); + err = dldwd_ioctl_setfreq(dev, &wrq->u.freq); + if (! err) + changed = 1; + break; + + case SIOCGIWSENS: + DEBUG(1, "%s: SIOCGIWSENS\n", dev->name); + err = dldwd_ioctl_getsens(dev, &wrq->u.sens); + break; + + case SIOCSIWSENS: + DEBUG(1, "%s: SIOCSIWSENS\n", dev->name); + err = dldwd_ioctl_setsens(dev, &wrq->u.sens); + if (! err) + changed = 1; + break; + + case SIOCGIWRTS: + DEBUG(1, "%s: SIOCGIWRTS\n", dev->name); + wrq->u.rts.value = priv->rts_thresh; + wrq->u.rts.disabled = (wrq->u.rts.value == 2347); + wrq->u.rts.fixed = 1; + break; + + case SIOCSIWRTS: + DEBUG(1, "%s: SIOCSIWRTS\n", dev->name); + err = dldwd_ioctl_setrts(dev, &wrq->u.rts); + if (! err) + changed = 1; + break; + + case SIOCSIWFRAG: + DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name); + err = dldwd_ioctl_setfrag(dev, &wrq->u.frag); + if (! err) + changed = 1; + break; + + case SIOCGIWFRAG: + DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name); + err = dldwd_ioctl_getfrag(dev, &wrq->u.frag); + break; + + case SIOCSIWRATE: + DEBUG(1, "%s: SIOCSIWRATE\n", dev->name); + err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate); + if (! err) + changed = 1; + break; + + case SIOCGIWRATE: + DEBUG(1, "%s: SIOCGIWRATE\n", dev->name); + err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate); + break; + + case SIOCSIWPOWER: + DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name); + err = dldwd_ioctl_setpower(dev, &wrq->u.power); + if (! err) + changed = 1; + break; + + case SIOCGIWPOWER: + DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name); + err = dldwd_ioctl_getpower(dev, &wrq->u.power); + break; + + case SIOCGIWTXPOW: + DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name); + /* The card only supports one tx power, so this is easy */ + wrq->u.txpower.value = 15; /* dBm */ + wrq->u.txpower.fixed = 1; + wrq->u.txpower.disabled = 0; + wrq->u.txpower.flags = IW_TXPOW_DBM; + break; + + case SIOCSIWSPY: + DEBUG(1, "%s: SIOCSIWSPY\n", dev->name); + + err = dldwd_ioctl_setspy(dev, &wrq->u.data); + break; + + case SIOCGIWSPY: + DEBUG(1, "%s: SIOCGIWSPY\n", dev->name); + + err = dldwd_ioctl_getspy(dev, &wrq->u.data); + break; + + case SIOCGIWPRIV: + DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name); + if (wrq->u.data.pointer) { + struct iw_priv_args privtab[] = { + { SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" }, + { SIOCDEVPRIVATE + 0x2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_port3" }, + { SIOCDEVPRIVATE + 0x3, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_port3" } + }; + + err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); + if (err) + break; + + wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); + if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab))) + err = -EFAULT; + } + break; + + case SIOCDEVPRIVATE + 0x0: /* force_reset */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); + dldwd_reset(priv); + break; + + case SIOCDEVPRIVATE + 0x2: /* set_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n", + dev->name); + if (! capable(CAP_NET_ADMIN)) { + err = -EPERM; + break; + } + + err = dldwd_ioctl_setport3(dev, wrq); + if (! err) + changed = 1; + break; + + case SIOCDEVPRIVATE + 0x3: /* get_port3 */ + DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n", + dev->name); + err = dldwd_ioctl_getport3(dev, wrq); + break; + + default: + err = -EOPNOTSUPP; + } + + if (! err && changed && netif_running(dev)) { + err = dldwd_reset(priv); + if (err) + dldwd_stop(dev); + } + + TRACE_EXIT(dev->name); + + return err; +} + +static int dldwd_change_mtu(struct net_device *dev, int new_mtu) +{ + TRACE_ENTER(dev->name); + + if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) ) + return -EINVAL; + + dev->mtu = new_mtu; + + TRACE_EXIT(dev->name); + + return 0; +} + +static void __dldwd_set_multicast_list(struct net_device *dev) +{ + dldwd_priv_t *priv = dev->priv; + hermes_t *hw = &priv->hw; + int err = 0; + int promisc, allmulti, mc_count; + + TRACE_ENTER(dev->name); + + DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n", + dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count); + + /* The Hermes doesn't seem to have an allmulti mode, so we go + * into promiscuous mode and let the upper levels deal. */ + if ( (dev->flags & IFF_PROMISC) ) { + promisc = 1; + allmulti = 0; + mc_count = 0; + } else if ( (dev->flags & IFF_ALLMULTI) || + (dev->mc_count > HERMES_MAX_MULTICAST) ) { + promisc = 0; + allmulti = 1; + mc_count = HERMES_MAX_MULTICAST; + } else { + promisc = 0; + allmulti = 0; + mc_count = dev->mc_count; + } + + DEBUG(3, "promisc=%d mc_count=%d\n", + promisc, mc_count); + + if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */ + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS, + promisc); + if (err) { + printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n", + dev->name, err, promisc); + } else + priv->promiscuous = promisc; + } + + if (allmulti) { + /* FIXME: This method of doing allmulticast reception + comes from the NetBSD driver. Haven't actually + tested whether it works or not. */ + hermes_multicast_t mclist; + + memset(&mclist, 0, sizeof(mclist)); + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->allmulti = 1; + + } else if (mc_count || (! mc_count && priv->mc_count) ) { + struct dev_mc_list *p = dev->mc_list; + hermes_multicast_t mclist; + int i; + + for (i = 0; i < mc_count; i++) { + /* First some paranoid checks */ + if (! p) { + printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n", + dev->name); + break; + } + if (p->dmi_addrlen != ETH_ALEN) { + + printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n", + dev->name, p->dmi_addrlen); + break; + } + + memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); + p = p->next; + } + + /* More paranoia */ + if (p) + printk(KERN_ERR "%s: Multicast list longer than mc_count.\n", + dev->name); + + priv->mc_count = i; + + DEBUG(3, "priv->mc_count = %d\n", priv->mc_count); + + err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, + HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), + &mclist); + if (err) + printk(KERN_ERR "%s: Error %d setting multicast list.\n", + dev->name, err); + else + priv->allmulti = 0; + } + + /* Since we can set the promiscuous flag when it wasn't asked + for, make sure the net_device knows about it. */ + if (priv->promiscuous) + dev->flags |= IFF_PROMISC; + else + dev->flags &= ~IFF_PROMISC; + + if (priv->allmulti) + dev->flags |= IFF_ALLMULTI; + else + dev->flags &= ~IFF_ALLMULTI; + + TRACE_EXIT(dev->name); +} + +/* + * procfs stuff + */ + +static struct proc_dir_entry *dir_base = NULL; + +/* + * This function updates the total amount of data printed so far. It then + * determines if the amount of data printed into a buffer has reached the + * offset requested. If it hasn't, then the buffer is shifted over so that + * the next bit of data can be printed over the old bit. If the total + * amount printed so far exceeds the total amount requested, then this + * function returns 1, otherwise 0. + */ +static int + +shift_buffer(char *buffer, int requested_offset, int requested_len, + int *total, int *slop, char **buf) +{ + int printed; + + printed = *buf - buffer; + if (*total + printed <= requested_offset) { + *total += printed; + *buf = buffer; + } + else { + if (*total < requested_offset) { + *slop = requested_offset - *total; + } + *total = requested_offset + printed - *slop; + } + if (*total > requested_offset + requested_len) { + return 1; + } + else { + return 0; + } +} + +/* + * This function calculates the actual start of the requested data + * in the buffer. It also calculates actual length of data returned, + * which could be less that the amount of data requested. + */ +#define PROC_BUFFER_SIZE 4096 +#define PROC_SAFE_SIZE 3072 + +static int +calc_start_len(char *buffer, char **start, int requested_offset, + int requested_len, int total, char *buf) +{ + int return_len, buffer_len; + + buffer_len = buf - buffer; + if (buffer_len >= PROC_BUFFER_SIZE - 1) { + printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); + } + + /* + * There may be bytes before and after the + * chunk that was actually requested. + */ + return_len = total - requested_offset; + if (return_len < 0) { + return_len = 0; + } + *start = buf - return_len; + if (return_len > requested_len) { + return_len = requested_len; + } + return return_len; +} + +static int +dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + dldwd_priv_t *dev = (dldwd_priv_t *)data; + hermes_t *hw = &dev->hw; + char *buf; + int total = 0, slop = 0; + + buf = page; + +#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name)) + + DHERMESREG(CMD); + DHERMESREG(PARAM0); + DHERMESREG(PARAM1); + DHERMESREG(PARAM2); + DHERMESREG(STATUS); + DHERMESREG(RESP0); + DHERMESREG(RESP1); + DHERMESREG(RESP2); + DHERMESREG(INFOFID); + DHERMESREG(RXFID); + DHERMESREG(ALLOCFID); + DHERMESREG(TXCOMPLFID); + DHERMESREG(SELECT0); + DHERMESREG(OFFSET0); + DHERMESREG(SELECT1); + DHERMESREG(OFFSET1); + DHERMESREG(EVSTAT); + DHERMESREG(INTEN); + DHERMESREG(EVACK); + DHERMESREG(CONTROL); + DHERMESREG(SWSUPPORT0); + DHERMESREG(SWSUPPORT1); + DHERMESREG(SWSUPPORT2); + DHERMESREG(AUXPAGE); + DHERMESREG(AUXOFFSET); + DHERMESREG(AUXDATA); +#undef DHERMESREG + + shift_buffer(page, requested_offset, requested_len, &total, + &slop, &buf); + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +struct { + uint16_t rid; + char *name; + int minlen, maxlen; + int displaytype; +#define DISPLAY_WORDS 0 +#define DISPLAY_BYTES 1 +#define DISPLAY_STRING 2 +} record_table[] = { +#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type } + RTCNFENTRY(PORTTYPE, DISPLAY_WORDS), + RTCNFENTRY(MACADDR, DISPLAY_BYTES), + RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING), + RTCNFENTRY(CHANNEL, DISPLAY_WORDS), + RTCNFENTRY(OWN_SSID, DISPLAY_STRING), + RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS), + RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS), + RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS), + RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS), + RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS), + RTCNFENTRY(NICKNAME, DISPLAY_STRING), + RTCNFENTRY(WEP_ON, DISPLAY_WORDS), + RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS), + RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES), + RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS), + RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS), + RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS), + RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS), + RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS), + RTCNFENTRY(KEYS, DISPLAY_BYTES), + RTCNFENTRY(TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(TICKTIME, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS), + RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES), + RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS), +#undef RTCNFENTRY +#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type } + RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS), + RTINFENTRY(STAIDENTITY, DISPLAY_WORDS), + RTINFENTRY(CURRENT_SSID, DISPLAY_STRING), + RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES), + RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS), + RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS), + RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS), + RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS), + RTINFENTRY(DATARATES, DISPLAY_BYTES), +#undef RTINFENTRY +}; +#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) + +static int +dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, + int requested_len, int *eof, void *data) +{ + dldwd_priv_t *dev = (dldwd_priv_t *)data; + hermes_t *hw = &dev->hw; + char *buf; + int total = 0, slop = 0; + int i; + uint16_t length; + int err; + + buf = page; + + /* print out all the config RIDs */ + for (i = 0; i < NUM_RIDS; i++) { + uint16_t rid = record_table[i].rid; + int minlen = record_table[i].minlen; + int maxlen = record_table[i].maxlen; + int len; + uint8_t *val8; + uint16_t *val16; + int j; + + val8 = kmalloc(maxlen + 2, GFP_KERNEL); + if (! val8) + return -ENOMEM; + + err = hermes_read_ltv(hw, USER_BAP, rid, maxlen, + &length, val8); + if (err) { + DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); + continue; + } + val16 = (uint16_t *)val8; + + buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, + rid, length, (length-1)*2); + len = MIN( MAX(minlen, (length-1)*2), maxlen); + + switch (record_table[i].displaytype) { + case DISPLAY_WORDS: + for (j = 0; j < len / 2; j++) { + buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); + } + buf--; + break; + + case DISPLAY_BYTES: + default: + for (j = 0; j < len; j++) { + buf += sprintf(buf, "%02X:", val8[j]); + } + buf--; + break; + + case DISPLAY_STRING: + len = MIN(len, le16_to_cpu(val16[0])+2); + val8[len] = '\0'; + buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); + break; + } + + buf += sprintf(buf, "\n"); + + kfree(val8); + + if (shift_buffer(page, requested_offset, requested_len, + &total, &slop, &buf)) + break; + + if ( (buf - page) > PROC_SAFE_SIZE ) + break; + } + + return calc_start_len(page, start, requested_offset, requested_len, + total, buf); +} + +/* initialise the /proc subsystem for the hermes driver, creating the + * separate entries */ +static int +dldwd_proc_init(void) +{ + int err = 0; + + TRACE_ENTER("dldwd"); + + /* create the directory for it to sit in */ + dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); + if (dir_base == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); + dldwd_proc_cleanup(); + err = -ENOMEM; + } + + TRACE_EXIT("dldwd"); + + return err; +} + +static int +dldwd_proc_dev_init(dldwd_priv_t *dev) +{ + dev->dir_dev = NULL; + /* create the directory for it to sit in */ + dev->dir_dev = create_proc_entry(dev->node.dev_name, S_IFDIR | S_IRUGO | S_IXUGO, + dir_base); + if (dev->dir_dev == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n", dev->node.dev_name); + goto fail; + } + + dev->dir_regs = NULL; + dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO, + dev->dir_dev, dldwd_proc_get_hermes_regs, dev); + if (dev->dir_regs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n", dev->node.dev_name); + goto fail; + } + + dev->dir_recs = NULL; + dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO, + dev->dir_dev, dldwd_proc_get_hermes_recs, dev); + if (dev->dir_recs == NULL) { + printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n", dev->node.dev_name); + goto fail; + } + + return 0; + fail: + dldwd_proc_dev_cleanup(dev); + return -ENOMEM; +} + +static void +dldwd_proc_dev_cleanup(dldwd_priv_t *priv) +{ + if (priv->dir_regs) { + remove_proc_entry("regs", priv->dir_dev); + priv->dir_regs = NULL; + } + if (priv->dir_recs) { + remove_proc_entry("recs", priv->dir_dev); + priv->dir_recs = NULL; + } + if (priv->dir_dev) { + remove_proc_entry(priv->node.dev_name, dir_base); + priv->dir_dev = NULL; + } +} + +static void +dldwd_proc_cleanup(void) +{ + TRACE_ENTER("dldwd"); + + if (dir_base) { + remove_proc_entry("hermes", &proc_root); + dir_base = NULL; + } + + TRACE_EXIT("dldwd"); +} + +/*====================================================================*/ + +/* + * From here on in, it's all PCMCIA junk, taken almost directly from + * dummy_cs.c + */ + +/* + 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 = "orinoco_cs"; + +/* + A linked list of "instances" of the dummy 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; +static int num_instances = 0; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + dldwd_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 *dldwd_attach(void) +{ + dldwd_priv_t *priv; + dev_link_t *link; + struct net_device *ndev; + client_reg_t client_reg; + int ret, i; + + TRACE_ENTER("dldwd"); + + /* Allocate space for private device-specific data */ + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (! priv) { + link = NULL; + goto out; + } + + memset(priv, 0, sizeof(*priv)); + priv->instance = num_instances++; /* FIXME: Racy? */ + spin_lock_init(&priv->lock); + + link = &priv->link; + ndev = &priv->ndev; + link->priv = ndev->priv = priv; + + /* Initialize the dev_link_t structure */ + link->release.function = &dldwd_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. + */ + link->conf.Attributes = 0; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Set up the net_device */ + ether_setup(ndev); + ndev->init = dldwd_init; + ndev->open = dldwd_open; + ndev->stop = dldwd_stop; + ndev->hard_start_xmit = dldwd_xmit; + ndev->tx_timeout = dldwd_tx_timeout; + ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */ + + ndev->get_stats = dldwd_get_stats; + ndev->get_wireless_stats = dldwd_get_wireless_stats; + + ndev->do_ioctl = dldwd_ioctl; + + ndev->change_mtu = dldwd_change_mtu; + ndev->set_multicast_list = dldwd_set_multicast_list; + + netif_stop_queue(ndev); + + /* 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 = &dldwd_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); + dldwd_detach(link); + link = NULL; + goto out; + } + + out: + TRACE_EXIT("dldwd"); + return link; +} /* dldwd_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 dldwd_detach(dev_link_t * link) +{ + dev_link_t **linkp; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER("dldwd"); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + goto out; + + /* + 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 "orinoco_cs: detach postponed, '%s' " + "still locked\n", link->dev->dev_name); +#endif + link->state |= DEV_STALE_LINK; + goto out; + } + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, and free it */ + *linkp = link->next; + DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev); + if (link->dev) { + DEBUG(0, "orinoco_cs: About to unregister net device %p\n", + &priv->ndev); + unregister_netdev(&priv->ndev); + } + kfree(priv); + + num_instances--; /* FIXME: Racy? */ + + out: + TRACE_EXIT("dldwd"); +} /* dldwd_detach */ + +/*====================================================================== + dldwd_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 dldwd_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + dldwd_priv_t *priv = link->priv; + hermes_t *hw = &priv->hw; + struct net_device *ndev = &priv->ndev; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + u_char buf[64]; + config_info_t conf; + cisinfo_t info; + + TRACE_ENTER("dldwd"); + + CS_CHECK(ValidateCIS, handle, &info); + + /* + 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; + + DEBUG(0, "dldwd_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", + link->conf.ConfigBase, link->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); + + DEBUG(0, "dldwd_config: index = 0x%x, flags = 0x%x\n", + cfg->index, cfg->flags); + + 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 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + cfg->vcc.param[CISTPL_POWER_VNOM] / + 10000) goto next_entry; + } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { + if (conf.Vcc != + dflt.vcc.param[CISTPL_POWER_VNOM] / + 10000) goto next_entry; + } + + if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; + else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; + + DEBUG(0, "dldwd_config: We seem to have configured Vcc and Vpp\n"); + + /* 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; + 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); + } + + + /* If we got this far, we're cool! */ + + break; + + next_entry: + 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) { + int i; + + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + 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 = dldwd_interrupt; + link->irq.Instance = priv; + + CS_CHECK(RequestIRQ, link->handle, &link->irq); + } + + /* We initialize the hermes structure before completing PCMCIA + configuration just in case the interrupt handler gets + called. */ + hermes_struct_init(hw, link->io.BasePort1); + + /* + 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); + + ndev->base_addr = link->io.BasePort1; + ndev->irq = link->irq.AssignedIRQ; + + /* Instance name : by default, use hermesX, on demand use the + * regular ethX (less risky) - Jean II */ + if(!eth) + sprintf(ndev->name, "hermes%d", priv->instance); + else + ndev->name[0] = '\0'; + /* Tell the stack we exist */ + if (register_netdev(ndev) != 0) { + printk(KERN_ERR "orinoco_cs: register_netdev() failed\n"); + goto failed; + } + strcpy(priv->node.dev_name, ndev->name); + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + priv->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); + printk("\n"); + + /* And give us the proc nodes for debugging */ + if (dldwd_proc_dev_init(priv) != 0) { + printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", + priv->node.dev_name); + goto failed; + } + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + priv->node.major = priv->node.minor = 0; + link->dev = &priv->node; + link->state &= ~DEV_CONFIG_PENDING; + + TRACE_EXIT("dldwd"); + + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + failed: + dldwd_release((u_long) link); + + TRACE_EXIT("dldwd"); +} /* dldwd_config */ + +/*====================================================================== + After a card is removed, dldwd_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 dldwd_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + dldwd_priv_t *priv = link->priv; + + TRACE_ENTER(link->dev->dev_name); + + /* + 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(0, "orinoco_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* + In a normal driver, additional code may be needed to release + other kernel data structures associated with this device. + */ + + dldwd_proc_dev_cleanup(priv); + + /* Don't bother checking to see if these succeed or not */ + 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; + + TRACE_EXIT(link->dev->dev_name); +} /* dldwd_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 dldwd_event(event_t event, int priority, + event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + dldwd_priv_t *priv = (dldwd_priv_t *)link->priv; + struct net_device *dev = &priv->ndev; + + TRACE_ENTER("dldwd"); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + dldwd_shutdown(priv); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_stop_queue(dev); + netif_device_detach(dev); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dldwd_config(link); + break; + case CS_EVENT_PM_SUSPEND: + + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + dldwd_shutdown(priv); + /* Mark the device as stopped, to block IO until later */ + + if (link->state & DEV_CONFIG) { + if (link->open) { + netif_stop_queue(dev); + netif_device_detach(dev); + } + 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); + + if (link->open) { + if (dldwd_reset(priv) == 0) { + netif_device_attach(dev); + netif_start_queue(dev); + } else { + printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n", + dev->name); + dldwd_stop(dev); + } + } + } + /* + In a normal driver, additional code may go here to restore + the device state and restart IO. + */ + break; + } + + TRACE_EXIT("dldwd"); + + return 0; +} /* dldwd_event */ + +static int __init init_dldwd_cs(void) +{ + servinfo_t serv; + int err; + + TRACE_ENTER("dldwd"); + + printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n"); + + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "orinoco_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &dldwd_attach, &dldwd_detach); + + + err = dldwd_proc_init(); + + TRACE_EXIT("dldwd"); + return err; +} + +static void __exit exit_dldwd_cs(void) +{ + TRACE_ENTER("dldwd"); + + dldwd_proc_cleanup(); + + unregister_pccard_driver(&dev_info); + + if (dev_list) + DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); + while (dev_list != NULL) { + del_timer(&dev_list->release); + if (dev_list->state & DEV_CONFIG) + dldwd_release((u_long) dev_list); + dldwd_detach(dev_list); + } + + TRACE_EXIT("dldwd"); +} + +module_init(init_dldwd_cs); +module_exit(exit_dldwd_cs); 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 Tue Mar 20 12:05:00 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 */ @@ -1398,7 +1404,7 @@ printk("2430.5"); break; default: - printk("???"); + printk("unknown"); } } @@ -1713,7 +1719,7 @@ memcmp(dac, dac_verify, 2 * 2)) { #ifdef DEBUG_IOCTL_ERROR - printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n"); + printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n"); #endif return -EOPNOTSUPP; } @@ -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; @@ -1962,7 +1968,7 @@ case SIOCGIWFREQ: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody ??? - especially old cards...) */ + * (does it work for everybody XXX - especially old cards...) */ if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { @@ -2524,11 +2530,12 @@ printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); #endif + if (lp == NULL) /* XXX will this ever occur? */ + return NULL; + /* Disable interrupts & save flags */ spin_lock_irqsave (&lp->lock, flags); - if(lp == (net_local *) NULL) - return (iw_stats *) NULL; wstats = &lp->wstats; /* Get data from the mmc */ @@ -2727,8 +2734,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 +2957,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 +2982,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); @@ -3144,7 +3152,7 @@ */ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) - * (does it work for everybody ??? - especially old cards...) */ + * (does it work for everybody XXX - especially old cards...) */ /* Note : WFREQSEL verify that it is able to read from EEprom * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID * is 0xA (Xilinx version) or 0xB (Ariadne version). @@ -3332,7 +3340,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 +3604,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 +3622,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)) { @@ -3822,7 +3830,7 @@ return FALSE; } - /* ???? Could you explain me this, Dave ? */ + /* XXX Could you explain me this, Dave ? */ link->dev = &((net_local *) dev->priv)->node; #ifdef DEBUG_CONFIG_TRACE @@ -3918,7 +3926,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 +4293,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 +4432,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 +4479,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 +4549,12 @@ #endif return link; + +fail_alloc_dev_priv: + kfree(dev); +fail_alloc_dev: + kfree(link); + return NULL; } /*------------------------------------------------------------------*/ @@ -4683,7 +4707,7 @@ * obliged to close nicely the wavelan here. David, could you * close the device before suspending them ? And, by the way, * could you, on resume, add a "route add -net ..." after the - * ifconfig up ??? Thanks... */ + * ifconfig up XXX Thanks... */ /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); @@ -4711,7 +4735,7 @@ if(link->state & DEV_CONFIG) { CardServices(RequestConfiguration, link->handle, &link->conf); - if(link->open) /* If RESET -> True, If RESUME -> False ??? */ + if(link->open) /* If RESET -> True, If RESUME -> False XXX */ { wv_hw_reset(dev); netif_device_attach(dev); 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/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c --- v2.4.2/linux/drivers/net/pcmcia/xircom_tulip_cb.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcmcia/xircom_tulip_cb.c Sun Mar 25 18:24:31 2001 @@ -503,10 +503,11 @@ } static struct net_device *tulip_probe1(struct pci_dev *pdev, - struct net_device *dev, long ioaddr, int irq, + long ioaddr, int irq, int chip_idx, int board_idx) { static int did_version; /* Already printed version info. */ + struct net_device *dev; struct tulip_private *tp; /* See note below on the multiport cards. */ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; @@ -519,7 +520,9 @@ if (tulip_debug > 0 && did_version++ == 0) printk(KERN_INFO "%s", version); - dev = init_etherdev(dev, 0); + dev = alloc_etherdev(0); + if (!dev) + return NULL; pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev); /* Bring the 21143 out of sleep mode. @@ -527,23 +530,11 @@ if (tulip_tbl[chip_idx].flags & HAS_ACPI) pci_write_config_dword(pdev, 0x40, 0x00000000); - printk(KERN_INFO "%s: %s rev %d at %#3lx,", - dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); - /* Stop the chip's Tx and Rx processes. */ outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, chip_idx); /* Clear the missed-packet counter. */ (volatile int)inl(ioaddr + CSR8); - if (chip_idx == DC21041) { - if (inl(ioaddr + CSR9) & 0x8000) { - printk(" 21040 compatible mode,"); - chip_idx = DC21040; - } else { - printk(" 21041 mode,"); - } - } - /* The station address ROM is read byte serially. The register must be polled, waiting for the value to be read bit serially from the EEPROM. @@ -661,14 +652,10 @@ #endif } - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); - printk(", IRQ %d.\n", irq); last_irq = irq; /* We do a request_region() only to register /proc/ioports info. */ - /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ - request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name); + request_region(ioaddr, tulip_tbl[chip_idx].io_size, "xircom_tulip_cb"); dev->base_addr = ioaddr; dev->irq = irq; @@ -693,17 +680,6 @@ else if (chip_idx == AX88140) tp->csr0 |= 0x2000; -#ifdef TULIP_FULL_DUPLEX - tp->full_duplex = 1; - tp->full_duplex_lock = 1; -#endif -#ifdef TULIP_DEFAULT_MEDIA - tp->default_port = TULIP_DEFAULT_MEDIA; -#endif -#ifdef TULIP_NO_MEDIA_SWITCH - tp->medialock = 1; -#endif - /* The lower four bits are the media type. */ if (board_idx >= 0 && board_idx < MAX_UNITS) { tp->default_port = options[board_idx] & 15; @@ -759,14 +735,14 @@ int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; tp->phys[phy_idx] = phy; tp->advertising[phy_idx++] = reg4; - printk(KERN_INFO "%s: MII transceiver #%d " + printk(KERN_INFO "xircom(%s): MII transceiver #%d " "config %4.4x status %4.4x advertising %4.4x.\n", - dev->name, phy, mii_reg0, mii_status, mii_advert); + pdev->slot_name, phy, mii_reg0, mii_status, mii_advert); /* Fixup for DLink with miswired PHY. */ if (mii_advert != reg4) { - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," + printk(KERN_DEBUG "xircom(%s): Advertising %4.4x on PHY %d," " previously advertising %4.4x.\n", - dev->name, reg4, phy, mii_advert); + pdev->slot_name, reg4, phy, mii_advert); mdio_write(dev, phy, 4, reg4); } /* Enable autonegotiation: some boards default to off. */ @@ -777,8 +753,8 @@ } tp->mii_cnt = phy_idx; if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { - printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", - dev->name); + printk(KERN_INFO "xircom(%s): ***WARNING***: No MII transceiver found!\n", + pdev->slot_name); tp->phys[0] = 1; } } @@ -799,37 +775,10 @@ /* Reset the xcvr interface and turn on heartbeat. */ switch (chip_idx) { - case DC21041: - outl(0x00000000, ioaddr + CSR13); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ - outl_CSR6(inl(ioaddr + CSR6) | 0x0200, ioaddr, chip_idx); - outl(0x0000EF05, ioaddr + CSR13); - break; - case DC21040: - outl(0x00000000, ioaddr + CSR13); - outl(0x00000004, ioaddr + CSR13); - break; case DC21140: default: if (tp->mtable) outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); break; - case DC21142: - case PNIC2: - if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) { - outl_CSR6(0x82020000, ioaddr, chip_idx); - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl_CSR6(0x820E0000, ioaddr, chip_idx); - } else { - outl_CSR6(0x82420200, ioaddr, chip_idx); - outl(0x0001, ioaddr + CSR13); - outl(0x0003FFFF, ioaddr + CSR14); - outl(0x0008, ioaddr + CSR15); - outl(0x0001, ioaddr + CSR13); - outl(0x1301, ioaddr + CSR12); /* Start NWay. */ - } - break; case X3201_3: outl(0x0008, ioaddr + CSR15); udelay(5); /* The delays are Xircom recommended to give the @@ -842,29 +791,24 @@ udelay(5); outl_CSR6(0x32000200, ioaddr, chip_idx); break; - case LC82C168: - if ( ! tp->mii_cnt) { - outl_CSR6(0x00420000, ioaddr, chip_idx); - outl(0x30, ioaddr + CSR12); - outl(0x0001F078, ioaddr + 0xB8); - outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ - } - break; - case MX98713: case COMPEX9881: - outl_CSR6(0x00000000, ioaddr, chip_idx); - outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ - outl(0x00000001, ioaddr + CSR13); - break; - case MX98715: case MX98725: - outl_CSR6(0x01a80000, ioaddr, chip_idx); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00001000, ioaddr + CSR12); - break; - case COMET: - /* No initialization necessary. */ - break; } + if (register_netdev(dev)) { + request_region(ioaddr, tulip_tbl[chip_idx].io_size, "xircom_tulip_cb"); + if (tp->mtable) + kfree(tp->mtable); + kfree(dev->priv); + kfree(dev); + return NULL; + } + + printk(KERN_INFO "%s: %s rev %d at %#3lx,", + dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); + for (i = 0; i < 6; i++) + printk("%c%2.2X", i ? ':' : ' ', + last_phys_addr[i] = dev->dev_addr[i]); + printk(", IRQ %d.\n", irq); + return dev; } @@ -1347,11 +1291,11 @@ } /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = 0x08000000 | 192; + tp->tx_ring[tp->cur_tx].length = 0x08000000 | 192; /* Lie about the address of our setup frame to make the */ /* chip happy */ - tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame); - tp->tx_ring[0].status = DescOwned; + tp->tx_ring[tp->cur_tx].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[tp->cur_tx].status = DescOwned; tp->cur_tx++; } @@ -2388,7 +2332,7 @@ #ifdef CARDBUS if (tp->chip_id == X3201_3) tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ); -#endif CARDBUS +#endif /* CARDBUS */ } tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]); } @@ -3081,8 +3025,7 @@ if (pci_enable_device (pdev)) return -ENODEV; pci_set_master (pdev); - dev = tulip_probe1(pdev, NULL, - pci_resource_start (pdev, 0), pdev->irq, + dev = tulip_probe1(pdev, pci_resource_start (pdev, 0), pdev->irq, id->driver_data, board_idx++); if (dev) { pdev->driver_data = dev; diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c --- v2.4.2/linux/drivers/net/pcnet32.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/pcnet32.c Sun Mar 25 18:24:31 2001 @@ -12,6 +12,14 @@ * * This driver is for PCnet32 and PCnetPCI based ethercards */ +/************************************************************************** + * 23 Oct, 2000. + * Fixed a few bugs, related to running the controller in 32bit mode. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + *************************************************************************/ static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n"; @@ -421,7 +429,7 @@ static int pcnet32_dwio_check (unsigned long addr) { outl (88, addr+PCNET32_DWIO_RAP); - return (inl (addr+PCNET32_DWIO_RAP) == 88); + return ((inl (addr+PCNET32_DWIO_RAP) & 0xffff) == 88); } static struct pcnet32_access pcnet32_dwio = { @@ -482,6 +490,12 @@ printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device); + if ((err = pci_enable_device(pdev)) < 0) { + printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err); + return err; + } + pci_set_master(pdev); + ioaddr = pci_resource_start (pdev, 0); printk(KERN_INFO " ioaddr=%#08lx resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0)); if (!ioaddr) { @@ -494,13 +508,6 @@ return -ENODEV; } - if ((err = pci_enable_device(pdev)) < 0) { - printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err); - return err; - } - - pci_set_master(pdev); - return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev); } @@ -528,11 +535,13 @@ pcnet32_dwio_reset(ioaddr); pcnet32_wio_reset(ioaddr); - if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) { - a = &pcnet32_wio; + /* Important to do the check for dwio mode first. */ + if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { + a = &pcnet32_dwio; } else { - if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { - a = &pcnet32_dwio; + if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && + pcnet32_wio_check(ioaddr)) { + a = &pcnet32_wio; } else return -ENODEV; } @@ -624,10 +633,35 @@ printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr); - /* There is a 16 byte station address PROM at the base address. - The first six bytes are the station address. */ + /* In most chips, after a chip reset, the ethernet address is read from the + * station address PROM at the base address and programmed into the + * "Physical Address Registers" CSR12-14. + * As a precautionary measure, we read the PROM values and complain if + * they disagree with the CSRs. Either way, we use the CSR values, and + * double check that they are valid. + */ + for (i = 0; i < 3; i++) { + unsigned int val; + val = a->read_csr(ioaddr, i+12) & 0x0ffff; + /* There may be endianness issues here. */ + dev->dev_addr[2*i] = val & 0x0ff; + dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff; + } + { + u8 promaddr[6]; + for (i = 0; i < 6; i++) { + promaddr[i] = inb(ioaddr + i); + } + if( memcmp( promaddr, dev->dev_addr, 6) ) + printk(" warning: PROM address does not match CSR address"); + } + /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ + if( !is_valid_ether_addr(dev->dev_addr) ) + for (i = 0; i < 6; i++) + dev->dev_addr[i]=0; + for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + printk(" %2.2x", dev->dev_addr[i] ); if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */ i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ @@ -656,7 +690,7 @@ request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname); /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ - if ((lp = (struct pcnet32_private *)pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) + if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) return -ENOMEM; memset(lp, 0, sizeof(*lp)); @@ -764,7 +798,7 @@ static int pcnet32_open(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 val; int i; @@ -775,6 +809,10 @@ return -EAGAIN; } + /* Check for a valid station address */ + if( !is_valid_ether_addr(dev->dev_addr) ) + return -EINVAL; + /* Reset the PCNET32 */ lp->a.reset (ioaddr); @@ -818,6 +856,12 @@ if (lp->options & PORT_100) val |= 0x08; lp->a.write_bcr (ioaddr, 32, val); + } else { + if (lp->options & PORT_ASEL) { /* enable auto negotiate, setup, disable fd */ + val = lp->a.read_bcr(ioaddr, 32) & ~0x98; + val |= 0x20; + lp->a.write_bcr(ioaddr, 32, val); + } } #ifdef DO_DXSUFLO @@ -885,7 +929,7 @@ static void pcnet32_purge_tx_ring(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; int i; for (i = 0; i < TX_RING_SIZE; i++) { @@ -903,7 +947,7 @@ static int pcnet32_init_ring(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; int i; lp->tx_full = 0; @@ -944,7 +988,7 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; int i; @@ -966,7 +1010,7 @@ static void pcnet32_tx_timeout (struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -999,7 +1043,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned int ioaddr = dev->base_addr; u16 status; int entry; @@ -1067,7 +1111,7 @@ static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - struct net_device *dev = (struct net_device *)dev_id; + struct net_device *dev = dev_id; struct pcnet32_private *lp; unsigned long ioaddr; u16 csr0,rap; @@ -1080,7 +1124,7 @@ } ioaddr = dev->base_addr; - lp = (struct pcnet32_private *)dev->priv; + lp = dev->priv; spin_lock(&lp->lock); @@ -1213,7 +1257,7 @@ static int pcnet32_rx(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; int entry = lp->cur_rx & RX_RING_MOD_MASK; /* If we own the next entry, it's a new packet. Send it up. */ @@ -1307,7 +1351,7 @@ pcnet32_close(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; int i; netif_stop_queue(dev); @@ -1357,7 +1401,7 @@ static struct net_device_stats * pcnet32_get_stats(struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 saved_addr; unsigned long flags; @@ -1374,7 +1418,7 @@ /* taken from the sunlance driver, which it took from the depca driver */ static void pcnet32_load_multicast (struct net_device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *) dev->priv; + struct pcnet32_private *lp = dev->priv; volatile struct pcnet32_init_block *ib = &lp->init_block; volatile u16 *mcast_table = (u16 *)&ib->filter; struct dev_mc_list *dmi=dev->mc_list; @@ -1427,7 +1471,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; if (dev->flags&IFF_PROMISC) { /* Log any net taps. */ @@ -1447,7 +1491,7 @@ static int pcnet32_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + struct pcnet32_private *lp = dev->priv; u16 *data = (u16 *)&rq->ifr_data; int phyaddr = lp->a.read_bcr (ioaddr, 33); @@ -1536,7 +1580,7 @@ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ while (pcnet32_dev) { - struct pcnet32_private *lp = (struct pcnet32_private *) pcnet32_dev->priv; + struct pcnet32_private *lp = pcnet32_dev->priv; next_dev = lp->next; unregister_netdev(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); 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 Sun Mar 25 18:24:31 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; } @@ -270,7 +276,7 @@ RCopen(struct net_device *dev) { int post_buffers = MAX_NMBR_RCV_BUFFERS; - PDPA pDpa = (PDPA) dev->priv; + PDPA pDpa = dev->priv; int count = 0; int requested = 0; int error; @@ -278,8 +284,8 @@ dprintk("(rcpci45 driver:) RCopen\n"); /* Request a shared interrupt line. */ - if ( (error=request_irq(dev->irq, (void *)RCinterrupt, - SA_INTERRUPT|SA_SHIRQ, "RedCreek VPN Adapter", dev)) ) { + error=request_irq(dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev); + if (error) { printk(KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", dev->name, dev->irq ); goto err_out; } @@ -361,7 +367,7 @@ RC_xmit_packet(struct sk_buff *skb, struct net_device *dev) { - PDPA pDpa = (PDPA) dev->priv; + PDPA pDpa = dev->priv; singleTCB tcb; psingleTCB ptcb = &tcb; RC_RETURN status = 0; @@ -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; @@ -662,9 +668,9 @@ { PDPA pDpa; - struct net_device *dev = (struct net_device *)(dev_id); + struct net_device *dev = dev_id; - pDpa = (PDPA) (dev->priv); + pDpa = dev->priv; if (pDpa->shutdown) dprintk("shutdown: service irq\n"); @@ -681,7 +687,7 @@ static void rc_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - PDPA pDpa = (PDPA) (dev->priv); + PDPA pDpa = dev->priv; int init_status; static int retry; int post_buffers = MAX_NMBR_RCV_BUFFERS; @@ -760,7 +766,7 @@ static int RCclose(struct net_device *dev) { - PDPA pDpa = (PDPA) dev->priv; + PDPA pDpa = dev->priv; netif_stop_queue(dev); 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 Sun Mar 25 18:24:31 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,34 +253,37 @@ 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]; - if (!pci_dma_supported(pci_dev, SIS900_DMA_MASK)) { + /* setup various bits in PCI command register */ + ret = pci_enable_device (pci_dev); + if (ret) return ret; + + i = pci_set_dma_mask(pci_dev, SIS900_DMA_MASK); + if (i) { printk(KERN_ERR "sis900.c: architecture does not support " "32bit PCI busmaster DMA\n"); - return -ENODEV; + return i; } - /* setup various bits in PCI command register */ - if (pci_enable_device (pci_dev)) - return -ENODEV; pci_set_master(pci_dev); - net_dev = init_etherdev(NULL, sizeof(struct sis900_private)); + irq = pci_dev->irq; + ioaddr = pci_resource_start(pci_dev, 0); + + net_dev = alloc_etherdev(sizeof(struct sis900_private)); if (!net_dev) return -ENOMEM; SET_MODULE_OWNER(net_dev); - if (!request_region(ioaddr, SIS900_TOTAL_SIZE, net_dev->name)) { - printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%lX\n", ioaddr); - ret = -EBUSY; + ret = pci_request_regions(pci_dev, "sis900"); + if (ret) goto err_out; - } pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); if (revision == SIS630E_900_REV || revision == SIS630EA1_900_REV) @@ -294,13 +298,6 @@ goto err_out_region; } - /* print some information about our NIC */ - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, - card_name, ioaddr, irq); - for (i = 0; i < 5; i++) - printk("%2.2x:", (u8)net_dev->dev_addr[i]); - printk("%2.2x.\n", net_dev->dev_addr[i]); - sis_priv = net_dev->priv; /* We do a request_region() to register /proc/ioports info. */ @@ -315,8 +312,7 @@ goto err_out_region; } - pci_dev->driver_data = net_dev; - pci_dev->dma_mask = SIS900_DMA_MASK; + pci_set_drvdata(pci_dev, net_dev); /* The SiS900-specific entries in the device structure. */ net_dev->open = &sis900_open; @@ -329,12 +325,24 @@ net_dev->tx_timeout = sis900_tx_timeout; net_dev->watchdog_timeo = TX_TIMEOUT; + ret = register_netdev(net_dev); + if (ret) + goto err_out_cleardev; + + /* print some information about our NIC */ + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, + card_name, ioaddr, irq); + for (i = 0; i < 5; i++) + printk("%2.2x:", (u8)net_dev->dev_addr[i]); + printk("%2.2x.\n", net_dev->dev_addr[i]); + return 0; +err_out_cleardev: + pci_set_drvdata(pci_dev, NULL); err_out_region: - release_region(ioaddr, SIS900_TOTAL_SIZE); + pci_release_regions(pci_dev); err_out: - unregister_netdev(net_dev); kfree(net_dev); return ret; } @@ -350,7 +358,7 @@ static int __init sis900_mii_probe (struct net_device * net_dev) { - struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private * sis_priv = net_dev->priv; int phy_addr; u8 revision; @@ -608,7 +616,7 @@ static int sis900_open(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; u8 revision; int ret; @@ -701,7 +709,7 @@ static void sis900_init_tx_ring(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int i; @@ -735,7 +743,7 @@ static void sis900_init_rx_ring(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int i; @@ -806,7 +814,7 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; u16 reg14h, eq_value, max_value=0, min_value=0; u8 host_bridge_rev; int i, maxcount=10; @@ -873,7 +881,7 @@ static void sis900_timer(unsigned long data) { struct net_device *net_dev = (struct net_device *)data; - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; struct mii_phy *mii_phy = sis_priv->mii; static int next_tick = 5*HZ; u16 status; @@ -950,7 +958,7 @@ static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_phy) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; int speed, duplex; u32 tx_flags = 0, rx_flags = 0; @@ -1169,7 +1177,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; unsigned long flags; int i; @@ -1222,7 +1230,7 @@ static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; unsigned int entry; unsigned long flags; @@ -1271,8 +1279,8 @@ static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct net_device *net_dev = (struct net_device *)dev_instance; - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct net_device *net_dev = dev_instance; + struct sis900_private *sis_priv = net_dev->priv; int boguscnt = max_interrupt_work; long ioaddr = net_dev->base_addr; u32 status; @@ -1330,7 +1338,7 @@ static int sis900_rx(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; @@ -1459,7 +1467,7 @@ static void sis900_finish_xmit (struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) { unsigned int entry; @@ -1469,14 +1477,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 +1499,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++; @@ -1524,7 +1532,7 @@ sis900_close(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; int i; netif_stop_queue(net_dev); @@ -1568,7 +1576,7 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; u16 *data = (u16 *)&rq->ifr_data; switch(cmd) { @@ -1598,7 +1606,7 @@ static struct net_device_stats * sis900_get_stats(struct net_device *net_dev) { - struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + struct sis900_private *sis_priv = net_dev->priv; return &sis_priv->stats; } @@ -1615,7 +1623,7 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map) { - struct sis900_private *sis_priv = (struct sis900_private *)dev->priv; + struct sis900_private *sis_priv = dev->priv; struct mii_phy *mii_phy = sis_priv->mii; u16 status; @@ -1838,11 +1846,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_release_regions(pci_dev); + pci_set_drvdata(pci_dev, NULL); } #define SIS900_MODULE_NAME "sis900" diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/h/lm80.h linux/drivers/net/sk98lin/h/lm80.h --- v2.4.2/linux/drivers/net/sk98lin/h/lm80.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/lm80.h Tue Mar 20 12:04:59 2001 @@ -126,7 +126,7 @@ #define LM80_IS_BTI (1<<1) /* state of BTI# pin */ #define LM80_IS_FAN1 (1<<2) /* count limit exceeded for Fan 1 */ #define LM80_IS_FAN2 (1<<3) /* count limit exceeded for Fan 2 */ -#define LM80_IS_CI (1<<4) /* Chassis Intrusion occured */ +#define LM80_IS_CI (1<<4) /* Chassis Intrusion occurred */ #define LM80_IS_OS (1<<5) /* OS temperature limit exceeded */ /* bit 6 and 7 are reserved in LM80_ISRC_2 */ #define LM80_IS_HT_IRQ_MD (1<<6) /* Hot temperature interrupt mode */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/h/skgehw.h linux/drivers/net/sk98lin/h/skgehw.h --- v2.4.2/linux/drivers/net/sk98lin/h/skgehw.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/skgehw.h Tue Mar 20 12:04:59 2001 @@ -499,7 +499,7 @@ /* * The HW-Spec. call this registers Timeout Value 0..11. But this names are * not usable in SW. Please notice these are NOT real timeouts, these are - * the number of qWords transfered continously. + * the number of qWords transferred continously. */ #define B3_RI_WTO_R1 0x0190 /* 8 bit RAM Iface WR Timeout Queue R1 (TO0) */ #define B3_RI_WTO_XA1 0x0191 /* 8 bit RAM Iface WR Timeout Queue XA1 (TO1) */ @@ -984,7 +984,7 @@ /* B3_RI_TEST 8 bit RAM Iface Test Register */ /* Bit 15..4: reserved */ -#define RI_T_EV (1<<3) /* Bit 3: Timeout Event occured */ +#define RI_T_EV (1<<3) /* Bit 3: Timeout Event occurred */ #define RI_T_ON (1<<2) /* Bit 2: Timeout Timer Test On */ #define RI_T_OFF (1<<1) /* Bit 1: Timeout Timer Test Off */ #define RI_T_STEP (1<<0) /* Bit 0: Timeout Timer Step */ @@ -1034,19 +1034,19 @@ /* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ /* B3_PA_TEST 16 bit Packet Arbiter Test Register */ /* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ -#define TX2_T_EV (1<<15) /* Bit 15: TX2 Timeout/Recv Event occured*/ +#define TX2_T_EV (1<<15) /* Bit 15: TX2 Timeout/Recv Event occurred*/ #define TX2_T_ON (1<<14) /* Bit 14: TX2 Timeout/Recv Timer Test On*/ #define TX2_T_OFF (1<<13) /* Bit 13: TX2 Timeout/Recv Timer Tst Off*/ #define TX2_T_STEP (1<<12) /* Bit 12: TX2 Timeout/Recv Timer Step */ -#define TX1_T_EV (1<<11) /* Bit 11: TX1 Timeout/Recv Event occured*/ +#define TX1_T_EV (1<<11) /* Bit 11: TX1 Timeout/Recv Event occurred*/ #define TX1_T_ON (1<<10) /* Bit 10: TX1 Timeout/Recv Timer Test On*/ #define TX1_T_OFF (1<<9) /* Bit 9: TX1 Timeout/Recv Timer Tst Off*/ #define TX1_T_STEP (1<<8) /* Bit 8: TX1 Timeout/Recv Timer Step */ -#define RX2_T_EV (1<<7) /* Bit 7: RX2 Timeout/Recv Event occured*/ +#define RX2_T_EV (1<<7) /* Bit 7: RX2 Timeout/Recv Event occurred*/ #define RX2_T_ON (1<<6) /* Bit 6: RX2 Timeout/Recv Timer Test On*/ #define RX2_T_OFF (1<<5) /* Bit 5: RX2 Timeout/Recv Timer Tst Off*/ #define RX2_T_STEP (1<<4) /* Bit 4: RX2 Timeout/Recv Timer Step */ -#define RX1_T_EV (1<<3) /* Bit 3: RX1 Timeout/Recv Event occured*/ +#define RX1_T_EV (1<<3) /* Bit 3: RX1 Timeout/Recv Event occurred*/ #define RX1_T_ON (1<<2) /* Bit 2: RX1 Timeout/Recv Timer Test On*/ #define RX1_T_OFF (1<<1) /* Bit 1: RX1 Timeout/Recv Timer Tst Off*/ #define RX1_T_STEP (1<<0) /* Bit 0: RX1 Timeout/Recv Timer Step */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/h/xmac_ii.h linux/drivers/net/sk98lin/h/xmac_ii.h --- v2.4.2/linux/drivers/net/sk98lin/h/xmac_ii.h Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/h/xmac_ii.h Tue Mar 20 12:04:59 2001 @@ -277,7 +277,7 @@ * XMAC Bit Definitions * * If the bit access behaviour differs from the register access behaviour - * (r/w, ro) this is docomented after the bit number. The following bit + * (r/w, ro) this is documented after the bit number. The following bit * access behaviours are used: * (sc) self clearing * (ro) read only @@ -412,7 +412,7 @@ #define XM_ST_BC (1L<<7) /* Bit 7: Broadcast packet */ #define XM_ST_MC (1L<<6) /* Bit 6: Multicast packet */ #define XM_ST_UC (1L<<5) /* Bit 5: Unicast packet */ -#define XM_ST_TX_UR (1L<<4) /* Bit 4: FIFO Underrun occured */ +#define XM_ST_TX_UR (1L<<4) /* Bit 4: FIFO Underrun occurred */ #define XM_ST_CS_ERR (1L<<3) /* Bit 3: Carrier Sense Error */ #define XM_ST_LAT_COL (1L<<2) /* Bit 2: Late Collision Error */ #define XM_ST_MUL_COL (1L<<1) /* Bit 1: Multiple Collisions */ 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/sk98lin/skgeinit.c linux/drivers/net/sk98lin/skgeinit.c --- v2.4.2/linux/drivers/net/sk98lin/skgeinit.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skgeinit.c Tue Mar 20 12:04:59 2001 @@ -122,7 +122,7 @@ * chg: Default is autosensing with AUTOFULL mode * * Revision 1.31 1998/11/25 15:36:16 gklug - * fix: do NOT stop LED Timer when port should be stoped + * fix: do NOT stop LED Timer when port should be stopped * * Revision 1.30 1998/11/24 13:15:28 gklug * add: Init PCkeckPar struct member @@ -1118,10 +1118,10 @@ * * Dir = SK_STOP_TX Stops the transmit path only and resets * the XMAC. The receive queue is still and - * the pending rx frames may still transfered + * the pending rx frames may still transferred * into the RxD. * SK_STOP_RX Stop the receive path. The tansmit path - * has to be stoped once before. + * has to be stopped once before. * SK_STOP_ALL SK_STOP_TX + SK_STOP_RX * * RstMode=SK_SOFT_RST Resets the XMAC. The PHY is still alive. @@ -1129,7 +1129,7 @@ * * Example: * 1) A Link Down event was signaled for a port. Therefore the activity - * of this port should be stoped and a hardware reset should be issued + * of this port should be stopped and a hardware reset should be issued * to enable the workaround of XMAC errata #2. But the received frames * should not be discarded. * ... diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skgepnmi.c linux/drivers/net/sk98lin/skgepnmi.c --- v2.4.2/linux/drivers/net/sk98lin/skgepnmi.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skgepnmi.c Tue Mar 20 12:04:59 2001 @@ -149,7 +149,7 @@ * Fixed: Couldnot delete VPD keys on UNIX. * * Revision 1.48 1998/12/09 14:11:10 mhaveman - * -Add: Debugmessage for XMAC_RESET supressed to minimize output. + * -Add: Debugmessage for XMAC_RESET suppressed to minimize output. * -Fixed: RlmtChangeThreshold will now be initialized. * -Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char. * -Fixed: On VPD key creation an invalid key name could be created @@ -206,7 +206,7 @@ * -Fixed bug for RX counters. On an RX overflow interrupt the high * words of all RX counters were incremented. * -SET operations on FLOWCTRL_MODE and LINK_MODE accept now the - * value 0, which has no effect. It is usefull for multiple instance + * value 0, which has no effect. It is useful for multiple instance * SETs. * * Revision 1.37 1998/11/20 08:02:04 mhaveman @@ -1600,7 +1600,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed - * SK_PNMI_ERR_GENERAL A general severe internal error occured + * SK_PNMI_ERR_GENERAL A general severe internal error occurred * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take * the data. * SK_PNMI_ERR_UNKNOWN_OID The requested OID is unknown @@ -1632,13 +1632,13 @@ * Description: * Calls a general sub-function for all this stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is usefull to check if a set might be successfull. + * new value. This is useful to check if a set might be successful. * If as instance a -1 is passed, an array of values is supposed and * all instance of the OID will be set. * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1674,13 +1674,13 @@ * Description: * Calls a general sub-function for all this stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is usefull to check if a set might be successfull. + * new value. This is useful to check if a set might be successful. * If as instance a -1 is passed, an array of values is supposed and * all instance of the OID will be set. * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1723,7 +1723,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed - * SK_PNMI_ERR_GENERAL A general severe internal error occured + * SK_PNMI_ERR_GENERAL A general severe internal error occurred * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to take * the data. */ @@ -1884,7 +1884,7 @@ * Description: * Calls a general sub-function for all this set stuff. The preset does * the same as a set, but returns just before finally setting the - * new value. This is usefull to check if a set might be successfull. + * new value. This is useful to check if a set might be successful. * The sub-function runs through the IdTable, checks which OIDs are able * to set, and calls the handler function of the OID to perform the * preset. The return value of the function will also be stored in @@ -1893,7 +1893,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -1929,7 +1929,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -2816,7 +2816,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -2883,7 +2883,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3017,7 +3017,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3159,7 +3159,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3299,7 +3299,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3509,7 +3509,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3628,7 +3628,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -3872,7 +3872,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -4352,7 +4352,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -4956,7 +4956,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -5264,7 +5264,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -5449,7 +5449,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -6052,7 +6052,7 @@ * * Returns: * SK_PNMI_ERR_OK The request was successfully performed. - * SK_PNMI_ERR_GENERAL A general severe internal error occured. + * SK_PNMI_ERR_GENERAL A general severe internal error occurred. * SK_PNMI_ERR_TOO_SHORT The passed buffer is too short to contain * the correct data (e.g. a 32bit value is * needed, but a 16 bit value was passed). @@ -6502,7 +6502,7 @@ * * Description: * The COMMON module only tells us if the mode is half or full duplex. - * But in the decade of auto sensing it is usefull for the user to + * But in the decade of auto sensing it is useful for the user to * know if the mode was negotiated or forced. Therefore we have a * look to the mode, which was last used by the negotiation process. * @@ -6764,7 +6764,7 @@ /* * It is an auto-clearing register. If the command bits - * went to zero again, the statistics are transfered. + * went to zero again, the statistics are transferred. * Normally the command should be executed immediately. * But just to be sure we execute a loop. */ @@ -7037,7 +7037,7 @@ * * Description: * The trap buffer stores various events. A user application somehow - * gets notified that an event occured and retrieves the trap buffer + * gets notified that an event occurred and retrieves the trap buffer * contens (or simply polls the buffer). The buffer is organized as * a ring which stores the newest traps at the beginning. The oldest * traps are overwritten by the newest ones. Each trap entry has a diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skgesirq.c linux/drivers/net/sk98lin/skgesirq.c --- v2.4.2/linux/drivers/net/sk98lin/skgesirq.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skgesirq.c Tue Mar 20 12:04:59 2001 @@ -695,14 +695,14 @@ /* Check whether XMACs are correctly initialized */ if ((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) && !pAC->GIni.GP[MAC_1].PState) { - /* XMAC was not initialized but Packet timeout occured */ + /* XMAC was not initialized but Packet timeout occurred */ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004, SKERR_SIRQ_E004MSG) ; } if ((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) && !pAC->GIni.GP[MAC_2].PState) { - /* XMAC was not initialized but Packet timeout occured */ + /* XMAC was not initialized but Packet timeout occurred */ SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005, SKERR_SIRQ_E005MSG) ; } @@ -1012,7 +1012,7 @@ */ /* * we received a bunch of frames or no - * CRC error occured on the network -> + * CRC error occurred on the network -> * ok. */ pPrt->PPrevRx = RxCts; @@ -1255,7 +1255,7 @@ SkHWLinkUp(pAC, IoC, Port) ; Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debuging only */ + /* Get PHY parameters, for debugging only */ PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP, &LpAb); PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI, @@ -1294,7 +1294,7 @@ pPrt->PAutoNegTimeOut ++; if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) { /* - * Timeout occured. + * Timeout occurred. * What do we need now? */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM, @@ -1304,7 +1304,7 @@ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && pPrt->PLipaAutoNeg != SK_LIPA_AUTO) { /* - * Timeout occured + * Timeout occurred * Set Link manually up. */ SkHWSenseSetNext(pAC, IoC, Port, @@ -1445,7 +1445,7 @@ SkHWLinkUp(pAC, IoC, Port); Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debuging only */ + /* Get PHY parameters, for debugging only */ PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LpAb); @@ -1583,7 +1583,7 @@ SkHWLinkUp(pAC, IoC, Port) ; Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { - /* Get PHY parameters, for debuging only */ + /* Get PHY parameters, for debugging only */ PHY_READ(IoC, pPrt, Port, PHY_LONE_AUNE_LP, &LpAb); @@ -1624,7 +1624,7 @@ pPrt->PAutoNegTimeOut ++; if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) { /* - * Timeout occured. + * Timeout occurred. * What do we need now? */ SK_DBG_MSG(pAC,SK_DBGMOD_HWM, @@ -1634,7 +1634,7 @@ if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE && pPrt->PLipaAutoNeg != SK_LIPA_AUTO) { /* - * Timeout occured + * Timeout occurred * Set Link manually up. */ SkHWSenseSetNext(pAC, IoC, Port, diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/ski2c.c linux/drivers/net/sk98lin/ski2c.c --- v2.4.2/linux/drivers/net/sk98lin/ski2c.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/ski2c.c Tue Mar 20 12:04:59 2001 @@ -1000,7 +1000,7 @@ /* Get the current time */ CurrTime = SkOsGetTime(pAC); - /* Set para to the most usefull setting: + /* Set para to the most useful setting: * The current sensor. */ ParaLocal.Para64 = (SK_U64) pAC->I2c.CurrSens; diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skqueue.c linux/drivers/net/sk98lin/skqueue.c --- v2.4.2/linux/drivers/net/sk98lin/skqueue.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skqueue.c Tue Mar 20 12:04:59 2001 @@ -147,7 +147,7 @@ * send command to state machine * end * return error reported by individual Event function - * 0 if no error occured. + * 0 if no error occurred. */ int SkEventDispatcher( SK_AC *pAC, /* Adapters Context */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skxmac2.c linux/drivers/net/sk98lin/skxmac2.c --- v2.4.2/linux/drivers/net/sk98lin/skxmac2.c Fri Sep 15 14:34:19 2000 +++ linux/drivers/net/sk98lin/skxmac2.c Tue Mar 20 12:04:59 2001 @@ -278,7 +278,7 @@ * o don't set XMR_FS_ERR in frame SK_BIG_PK_OK_ON/OFF * status for frames > 1514 bytes * - * for incomming packets may be enabled/disabled by this function. + * for incoming packets may be enabled/disabled by this function. * Additional modes may be added later. * Multiple modes can be enabled/disabled at the same time. * The new configuration is stored into the HWAC port configuration @@ -755,8 +755,8 @@ /* * configure the XMACs Station Address - * B2_MAC_2 = xx xx xx xx xx x1 is programed to XMAC A - * B2_MAC_3 = xx xx xx xx xx x2 is programed to XMAC B + * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A + * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B */ for (i = 0; i < 3; i++) { /* diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.4.2/linux/drivers/net/sk_g16.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/sk_g16.c Tue Mar 20 12:05:00 2001 @@ -218,9 +218,9 @@ * */ -#define SK_IOREG (board->ioreg) /* LANCE data registers. */ -#define SK_PORT (board->port) /* Control, Status register */ -#define SK_IOCOM (board->iocom) /* I/O Command */ +#define SK_IOREG (&board->ioreg) /* LANCE data registers. */ +#define SK_PORT (&board->port) /* Control, Status register */ +#define SK_IOCOM (&board->iocom) /* I/O Command */ /* * SK_G16 Status/Control Register bits @@ -1102,7 +1102,7 @@ writel((unsigned long) p->tmdbufs[i], tmdp->u.buffer); /* assign buffer */ /* Mark TMD as start and end of packet */ - writeb(TX_STP | TX_ENP, tmdp->u.s.status); + writeb(TX_STP | TX_ENP, &tmdp->u.s.status); } @@ -1122,32 +1122,32 @@ * receiving packets, set status and release RMD */ - writeb(RX_OWN, rmdp->u.s.status); + writeb(RX_OWN, &rmdp->u.s.status); - writew(-PKT_BUF_SZ, rmdp->blen); /* Buffer Size (two's complement) */ + writew(-PKT_BUF_SZ, &rmdp->blen); /* Buffer Size (two's complement) */ - writeb(0, rmdp->mlen); /* init message length */ + writeb(0, &rmdp->mlen); /* init message length */ } /* Fill LANCE Initialize Block */ - writew(mode, (p->ram)->ib.mode); /* Set operation mode */ + writew(mode, (&((p->ram)->ib.mode))); /* Set operation mode */ for (i = 0; i < ETH_ALEN; i++) /* Set physical address */ { - writeb(dev->dev_addr[i], (p->ram)->ib.paddr[i]); + writeb(dev->dev_addr[i], (&((p->ram)->ib.paddr[i]))); } for (i = 0; i < 8; i++) /* Set multicast, logical address */ { - writeb(0, (p->ram)->ib.laddr[i]); /* We do not use logical addressing */ + writeb(0, (&((p->ram)->ib.laddr[i]))); /* We do not use logical addressing */ } /* Set ring descriptor pointers and set number of descriptors */ - writel((int)p->rmdhead | RMDNUMMASK, (p->ram)->ib.rdrp); - writel((int)p->tmdhead | TMDNUMMASK, (p->ram)->ib.tdrp); + writel((int)p->rmdhead | RMDNUMMASK, (&((p->ram)->ib.rdrp))); + writel((int)p->tmdhead | TMDNUMMASK, (&((p->ram)->ib.tdrp))); /* Prepare LANCE Control and Status Registers */ @@ -1281,7 +1281,7 @@ memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len); - writew(-len, tmdp->blen); /* set length to transmit */ + writew(-len, &tmdp->blen); /* set length to transmit */ /* * Packet start and end is always set because we use the maximum @@ -1289,7 +1289,7 @@ * Relinquish ownership to LANCE */ - writeb(TX_OWN | TX_STP | TX_ENP, tmdp->u.s.status); + writeb(TX_OWN | TX_STP | TX_ENP, &tmdp->u.s.status); /* Start Demand Transmission */ SK_write_reg(CSR0, CSR0_TDMD | CSR0_INEA); @@ -1301,7 +1301,7 @@ p->tmdnum &= TMDNUM-1; /* Do we own the next transmit buffer ? */ - if (! (readb((p->tmdhead + p->tmdnum)->u.s.status) & TX_OWN) ) + if (! (readb(&((p->tmdhead + p->tmdnum)->u.s.status)) & TX_OWN) ) { /* * We own next buffer and are ready to transmit, so @@ -1421,7 +1421,7 @@ p->tmdlast++; p->tmdlast &= TMDNUM-1; - tmdstat = readb(tmdp->u.s.status); + tmdstat = readb(&tmdp->u.s.status); /* * We check status of transmitted packet. @@ -1429,7 +1429,7 @@ */ if (tmdstat & TX_ERR) /* Error occurred */ { - int stat2 = readw(tmdp->status2); + int stat2 = readw(&tmdp->status2); printk("%s: TX error: %04x %04x\n", dev->name, tmdstat, stat2); @@ -1458,7 +1458,7 @@ p->stats.tx_errors++; - writew(0, tmdp->status2); /* Clear error flags */ + writew(0, &tmdp->status2); /* Clear error flags */ } else if (tmdstat & TX_MORE) /* Collisions occurred ? */ { @@ -1534,7 +1534,7 @@ * it up to higher layer */ - while (!( (rmdstat = readb(rmdp->u.s.status)) & RX_OWN)) + while (!( (rmdstat = readb(&rmdp->u.s.status)) & RX_OWN)) { /* * Start and end of packet must be set, because we use @@ -1564,7 +1564,7 @@ * packets. */ - writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */ + writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ } else if (rmdstat & RX_ERR) /* Receive Error ? */ @@ -1576,13 +1576,13 @@ if (rmdstat & RX_FRAM) p->stats.rx_frame_errors++; if (rmdstat & RX_CRC) p->stats.rx_crc_errors++; - writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */ + writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ } else /* We have a packet which can be queued for the upper layers */ { - int len = readw(rmdp->mlen) & 0x0fff; /* extract message length from receive buffer */ + int len = readw(&rmdp->mlen) & 0x0fff; /* extract message length from receive buffer */ struct sk_buff *skb; skb = dev_alloc_skb(len+2); /* allocate socket buffer */ @@ -1595,7 +1595,7 @@ * to Lance, update statistics and go ahead. */ - writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */ + writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ printk("%s: Couldn't allocate sk_buff, deferring packet.\n", dev->name); p->stats.rx_dropped++; @@ -1633,7 +1633,7 @@ * free our descriptor and update statistics */ - writeb(RX_OWN, rmdp->u.s.status); + writeb(RX_OWN, &rmdp->u.s.status); dev->last_rx = jiffies; p->stats.rx_packets++; p->stats.rx_bytes += len; diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/drvfbi.c linux/drivers/net/skfp/drvfbi.c --- v2.4.2/linux/drivers/net/skfp/drvfbi.c Sun Mar 12 19:11:17 2000 +++ linux/drivers/net/skfp/drvfbi.c Tue Mar 20 12:04:59 2001 @@ -849,7 +849,7 @@ #ifdef EISA -/*arrays with io adresses of dma controller length and adress registers*/ +/*arrays with io addresses of dma controller length and address registers*/ static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ; static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ; static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ; diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/fplustm.c linux/drivers/net/skfp/fplustm.c --- v2.4.2/linux/drivers/net/skfp/fplustm.c Wed Jul 5 10:56:13 2000 +++ linux/drivers/net/skfp/fplustm.c Tue Mar 20 12:04:59 2001 @@ -87,7 +87,7 @@ /* - * usefull interrupt bits + * useful interrupt bits */ static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ; static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| @@ -1381,7 +1381,7 @@ CHECK_CAM() ; /* - * wirte the multicast addres into the CAM + * write the multicast address into the CAM */ outpw(FM_A(FM_AFCOMP2), (u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ; diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/h/skfbi.h linux/drivers/net/skfp/h/skfbi.h --- v2.4.2/linux/drivers/net/skfp/h/skfbi.h Fri Feb 18 14:55:53 2000 +++ linux/drivers/net/skfp/h/skfbi.h Sun Mar 25 18:24:31 2001 @@ -90,7 +90,7 @@ #define SKFDDI_PSZ 32 /* address PROM size */ /* - * address transmision from logical to physical offset address on board + * address transmission from logical to physical offset address on board */ #define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */ #define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */ @@ -347,7 +347,7 @@ #define SA_PMD_TYPE (8) /* start addr. PMD-Type */ /* - * address transmision from logical to physical offset address on board + * address transmission from logical to physical offset address on board */ #define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */ #define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */ @@ -677,7 +677,7 @@ #ifdef ISA /* - * address transmision from logic NPADDR6-0 to physical offset address on board + * address transmission from logic NPADDR6-0 to physical offset address on board */ #define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */ #define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/ @@ -942,7 +942,7 @@ /* PCI_SUB_ID 16 bit Subsystem ID */ /* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ -#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE addres (1st) */ +#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE address (1st) */ #define PCI_ROMBASZ 0x0001c000L /* Bit 16..14: Treat as BASE or SIZE */ #define PCI_ROMSIZE 0x00003800L /* Bit 13..11: ROM Size Requirements */ #define PCI_ROMEN 0x00000001L /* Bit 0: Address Decode enable */ @@ -1685,7 +1685,7 @@ #define PCI_PROG_INTFC 0x00 /* PCI programming Interface (=0) */ /* - * address transmision from logical to physical offset address on board + * address transmission from logical to physical offset address on board */ #define FMA(a) (0x0400|((a)<<2)) /* FORMAC+ (r/w) (SN3) */ #define P1(a) (0x0380|((a)<<2)) /* PLC1 (r/w) (DAS) */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/h/smc.h linux/drivers/net/skfp/h/smc.h --- v2.4.2/linux/drivers/net/skfp/h/smc.h Fri Feb 18 14:55:53 2000 +++ linux/drivers/net/skfp/h/smc.h Tue Mar 20 12:05:00 2001 @@ -297,7 +297,7 @@ #define RS_NORINGOP (1<< 5) /* no ring op */ #define RS_VERSION (1<< 4) /* SMT version mismatch */ #define RS_STUCKBYPASSS (1<< 3) /* stuck bypass */ -#define RS_EVENT (1<< 2) /* FDDI event occured */ +#define RS_EVENT (1<< 2) /* FDDI event occurred */ #define RS_RINGOPCHANGE (1<< 1) /* ring op changed */ #define RS_RES0 (1<< 0) /* reserved */ diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/pcmplc.c linux/drivers/net/skfp/pcmplc.c --- v2.4.2/linux/drivers/net/skfp/pcmplc.c Fri Feb 18 14:55:53 2000 +++ linux/drivers/net/skfp/pcmplc.c Tue Mar 20 12:05:00 2001 @@ -1722,7 +1722,7 @@ } if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/ /* - * Check whether the SRF Condition occured. + * Check whether the SRF Condition occurred. */ if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){ /* 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/skfp/srf.c linux/drivers/net/skfp/srf.c --- v2.4.2/linux/drivers/net/skfp/srf.c Wed Jul 5 10:56:13 2000 +++ linux/drivers/net/skfp/srf.c Sun Mar 25 18:24:31 2001 @@ -197,7 +197,7 @@ struct s_srf_evc *evc ; int cond_asserted = 0 ; int cond_deasserted = 0 ; - int event_occured = 0 ; + int event_occurred = 0 ; int tsr ; int T_Limit = 2*TICKS_PER_SECOND ; @@ -246,7 +246,7 @@ *evc->evc_multiple = FALSE ; } smc->srf.any_report = TRUE ; - event_occured = TRUE ; + event_occurred = TRUE ; } #ifdef FDDI_MIB snmp_srf_event(smc,evc) ; @@ -268,7 +268,7 @@ break ; } /* SR01c */ - if (event_occured && tsr < T_Limit) { + if (event_occurred && tsr < T_Limit) { smc->srf.sr_state = SR1_HOLDOFF ; break ; } @@ -286,7 +286,7 @@ break ; } /* SR00d */ - if (event_occured && tsr >= T_Limit) { + if (event_occurred && tsr >= T_Limit) { smc->srf.TSR = smt_get_time() ; smt_send_srf(smc) ; break ; 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/smc-ultra.c linux/drivers/net/smc-ultra.c --- v2.4.2/linux/drivers/net/smc-ultra.c Wed Feb 21 18:20:28 2001 +++ linux/drivers/net/smc-ultra.c Tue Mar 20 12:05:00 2001 @@ -20,6 +20,7 @@ ultra_probe() Detecting and initializing the card. ultra_probe1() + ultra_probe_isapnp() ultra_open() The card-specific details of starting, stopping ultra_reset_8390() and resetting the 8390 NIC core. @@ -43,11 +44,19 @@ Paul Gortmaker : multiple card support for module users. Donald Becker : 4/17/96 PIO support, minor potential problems avoided. Donald Becker : 6/6/96 correctly set auto-wrap bit. + Alexander Sotirov : 1/20/01 Added support for ISAPnP cards + + Note about the ISA PnP support: + + This driver can not autoprobe for more than one SMC EtherEZ PnP card. + You have to configure the second card manually through the /proc/isapnp + interface and then load the module with an explicit io=0x___ option. */ static const char *version = "smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +#include #include #include @@ -55,6 +64,7 @@ #include #include #include +#include #include #include @@ -69,6 +79,10 @@ int ultra_probe(struct net_device *dev); static int ultra_probe1(struct net_device *dev, int ioaddr); +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static int ultra_probe_isapnp(struct net_device *dev); +#endif + static int ultra_open(struct net_device *dev); static void ultra_reset_8390(struct net_device *dev); static void ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, @@ -85,6 +99,17 @@ const unsigned char *buf, const int start_page); static int ultra_close_card(struct net_device *dev); +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static struct isapnp_device_id ultra_device_ids[] __initdata = { + { ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), + ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416), + (long) "SMC EtherEZ (8416)" }, + { } /* terminate list */ +}; + +MODULE_DEVICE_TABLE(isapnp, ultra_device_ids); +#endif + #define START_PG 0x00 /* First page of TX buffer */ @@ -114,6 +139,14 @@ else if (base_addr != 0) /* Don't probe at all. */ return -ENXIO; +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + /* Look for any installed ISAPnP cards */ + if (isapnp_present() && (ultra_probe_isapnp(dev) == 0)) + return 0; + + printk(KERN_NOTICE "smc-ultra.c: No ISAPnP cards found, trying standard ones...\n"); +#endif + for (i = 0; ultra_portlist[i]; i++) if (ultra_probe1(dev, ultra_portlist[i]) == 0) return 0; @@ -245,6 +278,48 @@ return retval; } +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE +static int __init ultra_probe_isapnp(struct net_device *dev) +{ + int i; + + for (i = 0; ultra_device_ids[i].vendor != 0; i++) { + struct pci_dev *idev = NULL; + + while ((idev = isapnp_find_dev(NULL, + ultra_device_ids[i].vendor, + ultra_device_ids[i].function, + idev))) { + /* Avoid already found cards from previous calls */ + if (idev->prepare(idev)) + continue; + if (idev->activate(idev)) + continue; + /* if no irq, search for next */ + if (idev->irq_resource[0].start == 0) + continue; + /* found it */ + dev->base_addr = idev->resource[0].start; + dev->irq = idev->irq_resource[0].start; + printk(KERN_INFO "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", + (char *) ultra_device_ids[i].driver_data, + + dev->base_addr, dev->irq); + if (ultra_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ + printk(KERN_ERR "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr); return -ENXIO; + } + ei_status.priv = (unsigned long)idev; + break; + } + if (!idev) + continue; + return 0; + } + + return -ENODEV; +} +#endif + static int ultra_open(struct net_device *dev) { @@ -465,6 +540,13 @@ if (dev->priv != NULL) { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE + struct pci_dev *idev = (struct pci_dev *)ei_status.priv; + if (idev) + idev->deactivate(idev); +#endif + unregister_netdev(dev); release_region(ioaddr, ULTRA_IO_EXTENT); kfree(dev->priv); 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 Tue Mar 20 12:05:01 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,11 +1396,10 @@ 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 ); - - - return; } 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 Sun Mar 25 18:24:31 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,33 +388,28 @@ return -EIO; pci_set_master(pdev); - dev = init_etherdev(NULL, sizeof(*np)); + irq = pdev->irq; + + dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); + if (pci_request_regions(pdev, "sundance")) + 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; #endif - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); dev->base_addr = ioaddr; dev->irq = irq; @@ -453,10 +449,20 @@ if (mtu) dev->mtu = mtu; + i = register_netdev(dev); + if (i) + goto err_out_cleardev; + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + 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; @@ -483,13 +489,14 @@ card_idx++; return 0; +err_out_cleardev: + pci_set_drvdata(pdev, NULL); #ifndef USE_IO_OPS + iounmap((void *)ioaddr); err_out_iomem: - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[chip_idx].io_size); #endif + pci_release_regions(pdev); err_out_netdev: - unregister_netdev (dev); kfree (dev); return -ENODEV; } @@ -604,7 +611,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 +674,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 +696,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 +713,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 +742,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 +793,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 +847,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 +944,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 +1035,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 +1064,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 +1174,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 +1236,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/sungem.c linux/drivers/net/sungem.c --- v2.4.2/linux/drivers/net/sungem.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sungem.c Sun Mar 25 18:14:21 2001 @@ -0,0 +1,1494 @@ +/* $Id: sungem.c,v 1.8 2001/03/22 22:48:51 davem Exp $ + * sungem.c: Sun GEM ethernet driver. + * + * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef __sparc__ +#include +#include +#include +#include +#endif + +#include "sungem.h" + +static char version[] __devinitdata = + "sungem.c:v0.75 21/Mar/01 David S. Miller (davem@redhat.com)\n"; + +MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); +MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver"); +MODULE_PARM(gem_debug, "i"); + +#define GEM_MODULE_NAME "gem" +#define PFX GEM_MODULE_NAME ": " + +#ifdef GEM_DEBUG +int gem_debug = GEM_DEBUG; +#else +int gem_debug = 1; +#endif + +static struct pci_device_id gem_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_GEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + + /* These models only differ from the original GEM in + * that their tx/rx fifos are of a different size and + * they only support 10/100 speeds. -DaveM + */ + { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +#if 0 + /* Need to figure this one out. */ + { PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_PPC_GEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, +#endif + {0, } +}; + +MODULE_DEVICE_TABLE(pci, gem_pci_tbl); + +static u16 phy_read(struct gem *gp, int reg) +{ + u32 cmd; + int limit = 10000; + + cmd = (1 << 30); + cmd |= (2 << 28); + cmd |= (gp->mii_phy_addr << 23) & MIF_FRAME_PHYAD; + cmd |= (reg << 18) & MIF_FRAME_REGAD; + cmd |= (MIF_FRAME_TAMSB); + writel(cmd, gp->regs + MIF_FRAME); + + while (limit--) { + cmd = readl(gp->regs + MIF_FRAME); + if (cmd & MIF_FRAME_TALSB) + break; + + udelay(10); + } + + if (!limit) + cmd = 0xffff; + + return cmd & MIF_FRAME_DATA; +} + +static void phy_write(struct gem *gp, int reg, u16 val) +{ + u32 cmd; + int limit = 10000; + + cmd = (1 << 30); + cmd |= (1 << 28); + cmd |= (gp->mii_phy_addr << 23) & MIF_FRAME_PHYAD; + cmd |= (reg << 18) & MIF_FRAME_REGAD; + cmd |= (MIF_FRAME_TAMSB); + cmd |= (val & MIF_FRAME_DATA); + writel(cmd, gp->regs + MIF_FRAME); + + while (limit--) { + cmd = readl(gp->regs + MIF_FRAME); + if (cmd & MIF_FRAME_TALSB) + break; + + udelay(10); + } +} + +static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits) +{ +} + +static int gem_pcs_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 pcs_istat = readl(gp->regs + PCS_ISTAT); + u32 pcs_miistat; + + if (!(pcs_istat & PCS_ISTAT_LSC)) { + printk(KERN_ERR "%s: PCS irq but no link status change???\n", + dev->name); + return 0; + } + + /* The link status bit latches on zero, so you must + * read it twice in such a case to see a transition + * to the link being up. + */ + pcs_miistat = readl(gp->regs + PCS_MIISTAT); + if (!(pcs_miistat & PCS_MIISTAT_LS)) + pcs_miistat |= + (readl(gp->regs + PCS_MIISTAT) & + PCS_MIISTAT_LS); + + if (pcs_miistat & PCS_MIISTAT_ANC) { + /* The remote-fault indication is only valid + * when autoneg has completed. + */ + if (pcs_miistat & PCS_MIISTAT_RF) + printk(KERN_INFO "%s: PCS AutoNEG complete, " + "RemoteFault\n", dev->name); + else + printk(KERN_INFO "%s: PCS AutoNEG complete.\n", + dev->name); + } + + if (pcs_miistat & PCS_MIISTAT_LS) + printk(KERN_INFO "%s: PCS link is now up.\n", + dev->name); + else + printk(KERN_INFO "%s: PCS link is now down.\n", + dev->name); + + return 0; +} + +static int gem_txmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 txmac_stat = readl(gp->regs + MAC_TXSTAT); + + /* Defer timer expiration is quite normal, + * don't even log the event. + */ + if ((txmac_stat & MAC_TXSTAT_DTE) && + !(txmac_stat & ~MAC_TXSTAT_DTE)) + return 0; + + if (txmac_stat & MAC_TXSTAT_URUN) { + printk("%s: TX MAC xmit underrun.\n", + dev->name); + gp->net_stats.tx_fifo_errors++; + } + + if (txmac_stat & MAC_TXSTAT_MPE) { + printk("%s: TX MAC max packet size error.\n", + dev->name); + gp->net_stats.tx_errors++; + } + + /* The rest are all cases of one of the 16-bit TX + * counters expiring. + */ + if (txmac_stat & MAC_TXSTAT_NCE) + gp->net_stats.collisions += 0x10000; + + if (txmac_stat & MAC_TXSTAT_ECE) { + gp->net_stats.tx_aborted_errors += 0x10000; + gp->net_stats.collisions += 0x10000; + } + + if (txmac_stat & MAC_TXSTAT_LCE) { + gp->net_stats.tx_aborted_errors += 0x10000; + gp->net_stats.collisions += 0x10000; + } + + /* We do not keep track of MAC_TXSTAT_FCE and + * MAC_TXSTAT_PCE events. + */ + return 0; +} + +static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT); + + if (rxmac_stat & MAC_RXSTAT_OFLW) { + printk("%s: RX MAC fifo overflow.\n", + dev->name); + gp->net_stats.rx_over_errors++; + gp->net_stats.rx_fifo_errors++; + } + + if (rxmac_stat & MAC_RXSTAT_ACE) + gp->net_stats.rx_frame_errors += 0x10000; + + if (rxmac_stat & MAC_RXSTAT_CCE) + gp->net_stats.rx_crc_errors += 0x10000; + + if (rxmac_stat & MAC_RXSTAT_LCE) + gp->net_stats.rx_length_errors += 0x10000; + + /* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE + * events. + */ + return 0; +} + +static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 mac_cstat = readl(gp->regs + MAC_CSTAT); + + /* This interrupt is just for pause frame and pause + * tracking. It is useful for diagnostics and debug + * but probably by default we will mask these events. + */ + if (mac_cstat & MAC_CSTAT_PS) + gp->pause_entered++; + + if (mac_cstat & MAC_CSTAT_PRCV) + gp->pause_last_time_recvd = (mac_cstat >> 16); + + return 0; +} + +static int gem_mif_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 mif_status = readl(gp->regs + MIF_STATUS); + u32 reg_val, changed_bits; + + reg_val = (mif_status & MIF_STATUS_DATA) >> 16; + changed_bits = (mif_status & MIF_STATUS_STAT); + + gem_handle_mif_event(gp, reg_val, changed_bits); + + return 0; +} + +static int gem_pci_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + u32 pci_estat = readl(gp->regs + GREG_PCIESTAT); + + if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { + printk(KERN_ERR "%s: PCI error [%04x] ", + dev->name, pci_estat); + + if (pci_estat & GREG_PCIESTAT_BADACK) + printk(" "); + if (pci_estat & GREG_PCIESTAT_DTRTO) + printk(" "); + if (pci_estat & GREG_PCIESTAT_OTHER) + printk(""); + printk("\n"); + } else { + pci_estat |= GREG_PCIESTAT_OTHER; + printk(KERN_ERR "%s: PCI error\n", dev->name); + } + + if (pci_estat & GREG_PCIESTAT_OTHER) { + u16 pci_cfg_stat; + + /* Interrogate PCI config space for the + * true cause. + */ + pci_read_config_word(gp->pdev, PCI_STATUS, + &pci_cfg_stat); + printk(KERN_ERR "%s: Read PCI cfg space status [%04x]\n", + dev->name, pci_cfg_stat); + if (pci_cfg_stat & PCI_STATUS_PARITY) + printk(KERN_ERR "%s: PCI parity error detected.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_SIG_TARGET_ABORT) + printk(KERN_ERR "%s: PCI target abort.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_REC_TARGET_ABORT) + printk(KERN_ERR "%s: PCI master acks target abort.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_REC_MASTER_ABORT) + printk(KERN_ERR "%s: PCI master abort.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_SIG_SYSTEM_ERROR) + printk(KERN_ERR "%s: PCI system error SERR#.\n", + dev->name); + if (pci_cfg_stat & PCI_STATUS_DETECTED_PARITY) + printk(KERN_ERR "%s: PCI parity error.\n", + dev->name); + + /* Write the error bits back to clear them. */ + pci_cfg_stat &= (PCI_STATUS_PARITY | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | + PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR | + PCI_STATUS_DETECTED_PARITY); + pci_write_config_word(gp->pdev, + PCI_STATUS, pci_cfg_stat); + } + + /* For all PCI errors, we should reset the chip. */ + return 1; +} + +static void gem_stop(struct gem *, unsigned long); +static void gem_init_rings(struct gem *, int); +static void gem_init_hw(struct gem *); + +/* All non-normal interrupt conditions get serviced here. + * Returns non-zero if we should just exit the interrupt + * handler right now (ie. if we reset the card which invalidates + * all of the other original irq status bits). + */ +static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + if (gem_status & GREG_STAT_RXNOBUF) { + /* Frame arrived, no free RX buffers available. */ + gp->net_stats.rx_dropped++; + } + + if (gem_status & GREG_STAT_RXTAGERR) { + /* corrupt RX tag framing */ + gp->net_stats.rx_errors++; + + goto do_reset; + } + + if (gem_status & GREG_STAT_PCS) { + if (gem_pcs_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_TXMAC) { + if (gem_txmac_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_RXMAC) { + if (gem_rxmac_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_MAC) { + if (gem_mac_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_MIF) { + if (gem_mif_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + if (gem_status & GREG_STAT_PCIERR) { + if (gem_pci_interrupt(dev, gp, gem_status)) + goto do_reset; + } + + return 0; + +do_reset: + gem_stop(gp, gp->regs); + gem_init_rings(gp, 1); + gem_init_hw(gp); + return 1; +} + +static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_status) +{ + int entry, limit; + + entry = gp->tx_old; + limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT); + while (entry != limit) { + struct sk_buff *skb; + struct gem_txd *txd; + u32 dma_addr; + + txd = &gp->init_block->txd[entry]; + skb = gp->tx_skbs[entry]; + dma_addr = (u32) le64_to_cpu(txd->buffer); + pci_unmap_single(gp->pdev, dma_addr, + skb->len, PCI_DMA_TODEVICE); + gp->tx_skbs[entry] = NULL; + + gp->net_stats.tx_bytes += skb->len; + gp->net_stats.tx_packets++; + + dev_kfree_skb_irq(skb); + + entry = NEXT_TX(entry); + } + gp->tx_old = entry; + + if (netif_queue_stopped(dev) && + TX_BUFFS_AVAIL(gp) > 0) + netif_wake_queue(dev); +} + +static __inline__ void gem_post_rxds(struct gem *gp, int limit) +{ + int cluster_start, curr, count, kick; + + cluster_start = curr = (gp->rx_new & ~(4 - 1)); + count = 0; + kick = -1; + while (curr != limit) { + curr = NEXT_RX(curr); + if (++count == 4) { + struct gem_rxd *rxd = + &gp->init_block->rxd[cluster_start]; + for (;;) { + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH); + rxd++; + cluster_start = NEXT_RX(cluster_start); + if (cluster_start == curr) + break; + } + kick = curr; + count = 0; + } + } + if (kick >= 0) + writel(kick, gp->regs + RXDMA_KICK); +} + +static void gem_rx(struct gem *gp) +{ + int entry, drops; + + entry = gp->rx_new; + drops = 0; + for (;;) { + struct gem_rxd *rxd = &gp->init_block->rxd[entry]; + struct sk_buff *skb; + u64 status = cpu_to_le64(rxd->status_word); + u32 dma_addr; + int len; + + if ((status & RXDCTRL_OWN) != 0) + break; + + skb = gp->rx_skbs[entry]; + + len = (status & RXDCTRL_BUFSZ) >> 16; + if ((len < ETH_ZLEN) || (status & RXDCTRL_BAD)) { + gp->net_stats.rx_errors++; + if (len < ETH_ZLEN) + gp->net_stats.rx_length_errors++; + if (len & RXDCTRL_BAD) + gp->net_stats.rx_crc_errors++; + + /* We'll just return it to GEM. */ + drop_it: + gp->net_stats.rx_dropped++; + goto next; + } + + dma_addr = (u32) cpu_to_le64(rxd->buffer); + if (len > RX_COPY_THRESHOLD) { + struct sk_buff *new_skb; + + new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + if (new_skb == NULL) { + drops++; + goto drop_it; + } + pci_unmap_single(gp->pdev, dma_addr, + RX_BUF_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + gp->rx_skbs[entry] = new_skb; + new_skb->dev = gp->dev; + skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); + rxd->buffer = cpu_to_le64(pci_map_single(gp->pdev, + new_skb->data, + RX_BUF_ALLOC_SIZE, + PCI_DMA_FROMDEVICE)); + skb_reserve(new_skb, RX_OFFSET); + + /* Trim the original skb for the netif. */ + skb_trim(skb, len); + } else { + struct sk_buff *copy_skb = dev_alloc_skb(len + 2); + + if (copy_skb == NULL) { + drops++; + goto drop_it; + } + + copy_skb->dev = gp->dev; + skb_reserve(copy_skb, 2); + skb_put(copy_skb, len); + pci_dma_sync_single(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); + memcpy(copy_skb->data, skb->data, len); + + /* We'll reuse the original ring buffer. */ + skb = copy_skb; + } + + skb->protocol = eth_type_trans(skb, gp->dev); + netif_rx(skb); + + gp->net_stats.rx_packets++; + gp->net_stats.rx_bytes += len; + + next: + entry = NEXT_RX(entry); + } + + gem_post_rxds(gp, entry); + + gp->rx_new = entry; + + if (drops) + printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", + gp->dev->name); +} + +static void gem_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct gem *gp = (struct gem *) dev->priv; + u32 gem_status = readl(gp->regs + GREG_STAT); + + spin_lock(&gp->lock); + + if (gem_status & GREG_STAT_ABNORMAL) { + if (gem_abnormal_irq(dev, gp, gem_status)) + goto out; + } + if (gem_status & (GREG_STAT_TXALL | GREG_STAT_TXINTME)) + gem_tx(dev, gp, gem_status); + if (gem_status & GREG_STAT_RXDONE) + gem_rx(gp); + +out: + spin_unlock(&gp->lock); +} + +static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct gem *gp = (struct gem *) dev->priv; + long len; + int entry, avail; + u32 mapping; + + len = skb->len; + mapping = pci_map_single(gp->pdev, skb->data, len, PCI_DMA_TODEVICE); + + spin_lock_irq(&gp->lock); + entry = gp->tx_new; + gp->tx_skbs[entry] = skb; + + gp->tx_new = NEXT_TX(entry); + avail = TX_BUFFS_AVAIL(gp); + if (avail <= 0) + netif_stop_queue(dev); + + { + struct gem_txd *txd = &gp->init_block->txd[entry]; + u64 ctrl = (len & TXDCTRL_BUFSZ) | TXDCTRL_EOF | TXDCTRL_SOF; + + txd->control_word = cpu_to_le64(ctrl); + txd->buffer = cpu_to_le64(mapping); + } + + writel(gp->tx_new, gp->regs + TXDMA_KICK); + spin_unlock_irq(&gp->lock); + + dev->trans_start = jiffies; + + return 0; +} + +#define STOP_TRIES 32 + +static void gem_stop(struct gem *gp, unsigned long regs) +{ + int limit; + u32 val; + + writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, regs + GREG_SWRST); + + limit = STOP_TRIES; + + do { + udelay(20); + val = readl(regs + GREG_SWRST); + if (limit-- <= 0) + break; + } while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST)); + + if (limit <= 0) + printk(KERN_ERR "gem: SW reset is ghetto.\n"); +} + +/* A link-up condition has occurred, initialize and enable the + * rest of the chip. + */ +static void gem_set_link_modes(struct gem *gp) +{ + u32 val; + int full_duplex, speed; + + full_duplex = 0; + speed = 10; + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + if (gp->lstate == aneg_wait) { + val = phy_read(gp, PHY_LPA); + if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL)) + full_duplex = 1; + if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF)) + speed = 100; + } else { + val = phy_read(gp, PHY_CTRL); + if (val & PHY_CTRL_FDPLX) + full_duplex = 1; + if (val & PHY_CTRL_SPD100) + speed = 100; + } + } else { + u32 pcs_lpa = readl(gp->regs + PCS_MIILP); + + if (pcs_lpa & PCS_MIIADV_FD) + full_duplex = 1; + speed = 1000; + } + + printk(KERN_INFO "%s: Link is up at %d Mbps, %s-duplex.\n", + gp->dev->name, speed, (full_duplex ? "full" : "half")); + + val = (MAC_TXCFG_EIPG0 | MAC_TXCFG_NGU); + if (full_duplex) { + val |= (MAC_TXCFG_ICS | MAC_TXCFG_ICOLL); + } else { + /* MAC_TXCFG_NBO must be zero. */ + } + writel(val, gp->regs + MAC_TXCFG); + + val = (MAC_XIFCFG_OE | MAC_XIFCFG_LLED); + if (!full_duplex && + (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1)) { + val |= MAC_XIFCFG_DISE; + } else if (full_duplex) { + val |= MAC_XIFCFG_FLED; + } + writel(val, gp->regs + MAC_XIFCFG); + + if (gp->phy_type == phy_serialink || + gp->phy_type == phy_serdes) { + u32 pcs_lpa = readl(gp->regs + PCS_MIILP); + + val = readl(gp->regs + MAC_MCCFG); + if (pcs_lpa & (PCS_MIIADV_SP | PCS_MIIADV_AP)) + val |= (MAC_MCCFG_SPE | MAC_MCCFG_RPE); + else + val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE); + writel(val, gp->regs + MAC_MCCFG); + + /* XXX Set up PCS MII Control and Serialink Control + * XXX registers. + */ + + if (!full_duplex) + writel(512, gp->regs + MAC_STIME); + else + writel(64, gp->regs + MAC_STIME); + } else { + /* Set slot-time of 64. */ + writel(64, gp->regs + MAC_STIME); + } + + /* We are ready to rock, turn everything on. */ + val = readl(gp->regs + TXDMA_CFG); + writel(val | TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG); + val = readl(gp->regs + RXDMA_CFG); + writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG); + val = readl(gp->regs + MAC_TXCFG); + writel(val | MAC_TXCFG_ENAB, gp->regs + MAC_TXCFG); + val = readl(gp->regs + MAC_RXCFG); + writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); +} + +static int gem_mdio_link_not_up(struct gem *gp) +{ + if (gp->lstate == aneg_wait) { + u16 val = phy_read(gp, PHY_CTRL); + + /* Try forced modes. */ + val &= ~(PHY_CTRL_ANRES | PHY_CTRL_ANENAB); + val &= ~(PHY_CTRL_FDPLX); + val |= PHY_CTRL_SPD100; + phy_write(gp, PHY_CTRL, val); + gp->timer_ticks = 0; + gp->lstate = force_wait; + return 1; + } else { + /* Downgrade from 100 to 10 Mbps if necessary. + * If already at 10Mbps, warn user about the + * situation every 10 ticks. + */ + u16 val = phy_read(gp, PHY_CTRL); + if (val & PHY_CTRL_SPD100) { + val &= ~PHY_CTRL_SPD100; + phy_write(gp, PHY_CTRL, val); + gp->timer_ticks = 0; + return 1; + } else { + printk(KERN_ERR "%s: Link down, cable problem?\n", + gp->dev->name); + val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB); + phy_write(gp, PHY_CTRL, val); + gp->timer_ticks = 1; + gp->lstate = aneg_wait; + return 1; + } + } +} + +static void gem_link_timer(unsigned long data) +{ + struct gem *gp = (struct gem *) data; + int restart_timer = 0; + + gp->timer_ticks++; + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + u16 val = phy_read(gp, PHY_STAT); + + if (val & PHY_STAT_LSTAT) { + gem_set_link_modes(gp); + } else if (gp->timer_ticks < 10) { + restart_timer = 1; + } else { + restart_timer = gem_mdio_link_not_up(gp); + } + } else { + /* XXX Code PCS support... XXX */ + } + + if (restart_timer) { + gp->link_timer.expires = jiffies + ((12 * HZ) / 10); + add_timer(&gp->link_timer); + } +} + +static void gem_clean_rings(struct gem *gp) +{ + struct gem_init_block *gb = gp->init_block; + struct sk_buff *skb; + int i; + u32 dma_addr; + + for (i = 0; i < RX_RING_SIZE; i++) { + struct gem_rxd *rxd; + + rxd = &gb->rxd[i]; + if (gp->rx_skbs[i] != NULL) { + + skb = gp->rx_skbs[i]; + dma_addr = (u32) le64_to_cpu(rxd->buffer); + pci_unmap_single(gp->pdev, dma_addr, + RX_BUF_ALLOC_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any(skb); + gp->rx_skbs[i] = NULL; + } + rxd->status_word = 0; + rxd->buffer = 0; + } + + for (i = 0; i < TX_RING_SIZE; i++) { + if (gp->tx_skbs[i] != NULL) { + struct gem_txd *txd; + + skb = gp->tx_skbs[i]; + txd = &gb->txd[i]; + dma_addr = (u32) le64_to_cpu(txd->buffer); + pci_unmap_single(gp->pdev, dma_addr, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + gp->tx_skbs[i] = NULL; + } + } +} + +static void gem_init_rings(struct gem *gp, int from_irq) +{ + struct gem_init_block *gb = gp->init_block; + struct net_device *dev = gp->dev; + int i, gfp_flags = GFP_KERNEL; + u32 dma_addr; + + if (from_irq) + gfp_flags = GFP_ATOMIC; + + gp->rx_new = gp->rx_old = gp->tx_new = gp->tx_old = 0; + + gem_clean_rings(gp); + + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb; + struct gem_rxd *rxd = &gb->rxd[i]; + + skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags); + if (!skb) { + rxd->buffer = 0; + rxd->status_word = 0; + continue; + } + + gp->rx_skbs[i] = skb; + skb->dev = dev; + skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); + dma_addr = pci_map_single(gp->pdev, skb->data, + RX_BUF_ALLOC_SIZE, + PCI_DMA_FROMDEVICE); + rxd->buffer = cpu_to_le64(dma_addr); + rxd->status_word = cpu_to_le64(RXDCTRL_FRESH); + skb_reserve(skb, RX_OFFSET); + } + + for (i = 0; i < TX_RING_SIZE; i++) { + struct gem_txd *txd = &gb->txd[i]; + + txd->control_word = 0; + txd->buffer = 0; + } +} + +static void gem_init_phy(struct gem *gp) +{ + if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { + /* Init datapath mode register. */ + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE); + } else if (gp->phy_type == phy_serialink) { + writel(PCS_DMODE_SM, gp->regs + PCS_DMODE); + } else { + writel(PCS_DMODE_ESM, gp->regs + PCS_DMODE); + } + } + + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) { + u16 val = phy_read(gp, PHY_CTRL); + int limit = 10000; + + /* Take PHY out of isloate mode and reset it. */ + val &= ~PHY_CTRL_ISO; + val |= PHY_CTRL_RST; + phy_write(gp, PHY_CTRL, val); + + while (limit--) { + val = phy_read(gp, PHY_CTRL); + if ((val & PHY_CTRL_RST) == 0) + break; + udelay(10); + } + + /* Init advertisement and enable autonegotiation. */ + phy_write(gp, PHY_ADV, + (PHY_ADV_10HALF | PHY_ADV_10FULL | + PHY_ADV_100HALF | PHY_ADV_100FULL)); + + val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB); + phy_write(gp, PHY_CTRL, val); + } else { + /* XXX Implement me XXX */ + } +} + +static void gem_init_dma(struct gem *gp) +{ + u32 val; + + val = (TXDMA_CFG_BASE | (0x4ff << 10) | TXDMA_CFG_PMODE); + writel(val, gp->regs + TXDMA_CFG); + + writel(0, gp->regs + TXDMA_DBHI); + writel(gp->gblock_dvma, gp->regs + TXDMA_DBLOW); + + writel(0, gp->regs + TXDMA_KICK); + + val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) | + ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128); + writel(val, gp->regs + RXDMA_CFG); + + writel(0, gp->regs + RXDMA_DBHI); + writel((gp->gblock_dvma + + (TX_RING_SIZE * sizeof(struct gem_txd))), + gp->regs + RXDMA_DBLOW); + + writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); + + val = (((gp->rx_pause_off / 64) << 0) & RXDMA_PTHRESH_OFF); + val |= (((gp->rx_pause_on / 64) << 12) & RXDMA_PTHRESH_ON); + writel(val, gp->regs + RXDMA_PTHRESH); + + if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN) + writel(((5 & RXDMA_BLANK_IPKTS) | + ((8 << 12) & RXDMA_BLANK_ITIME)), + gp->regs + RXDMA_BLANK); + else + writel(((5 & RXDMA_BLANK_IPKTS) | + ((4 << 12) & RXDMA_BLANK_ITIME)), + gp->regs + RXDMA_BLANK); +} + +#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ + +static void gem_init_mac(struct gem *gp) +{ + unsigned char *e = &gp->dev->dev_addr[0]; + u32 rxcfg; + + if (gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) + writel(0x1bf0, gp->regs + MAC_SNDPAUSE); + + writel(0x00, gp->regs + MAC_IPG0); + writel(0x08, gp->regs + MAC_IPG1); + writel(0x04, gp->regs + MAC_IPG2); + writel(0x40, gp->regs + MAC_STIME); + writel(0x40, gp->regs + MAC_MINFSZ); + writel(0x5ee, gp->regs + MAC_MAXFSZ); + writel(0x07, gp->regs + MAC_PASIZE); + writel(0x04, gp->regs + MAC_JAMSIZE); + writel(0x10, gp->regs + MAC_ATTLIM); + writel(0x8808, gp->regs + MAC_MCTYPE); + + writel((e[5] | (e[4] << 8)) & 0x3ff, gp->regs + MAC_RANDSEED); + + writel((e[4] << 8) | e[5], gp->regs + MAC_ADDR0); + writel((e[2] << 8) | e[3], gp->regs + MAC_ADDR1); + writel((e[0] << 8) | e[1], gp->regs + MAC_ADDR2); + + writel(0, gp->regs + MAC_ADDR3); + writel(0, gp->regs + MAC_ADDR4); + writel(0, gp->regs + MAC_ADDR5); + + writel(0x0001, gp->regs + MAC_ADDR6); + writel(0xc200, gp->regs + MAC_ADDR7); + writel(0x0180, gp->regs + MAC_ADDR8); + + writel(0, gp->regs + MAC_AFILT0); + writel(0, gp->regs + MAC_AFILT1); + writel(0, gp->regs + MAC_AFILT2); + writel(0, gp->regs + MAC_AF21MSK); + writel(0, gp->regs + MAC_AF0MSK); + + rxcfg = 0; + if ((gp->dev->flags & IFF_ALLMULTI) || + (gp->dev->mc_count > 256)) { + writel(0xffff, gp->regs + MAC_HASH0); + writel(0xffff, gp->regs + MAC_HASH1); + writel(0xffff, gp->regs + MAC_HASH2); + writel(0xffff, gp->regs + MAC_HASH3); + writel(0xffff, gp->regs + MAC_HASH4); + writel(0xffff, gp->regs + MAC_HASH5); + writel(0xffff, gp->regs + MAC_HASH6); + writel(0xffff, gp->regs + MAC_HASH7); + writel(0xffff, gp->regs + MAC_HASH8); + writel(0xffff, gp->regs + MAC_HASH9); + writel(0xffff, gp->regs + MAC_HASH10); + writel(0xffff, gp->regs + MAC_HASH11); + writel(0xffff, gp->regs + MAC_HASH12); + writel(0xffff, gp->regs + MAC_HASH13); + writel(0xffff, gp->regs + MAC_HASH14); + writel(0xffff, gp->regs + MAC_HASH15); + } else if (gp->dev->flags & IFF_PROMISC) { + rxcfg |= MAC_RXCFG_PROM; + } else { + u16 hash_table[16]; + u32 crc, poly = CRC_POLYNOMIAL_LE; + struct dev_mc_list *dmi = gp->dev->mc_list; + int i, j, bit, byte; + + for (i = 0; i < 16; i++) + hash_table[i] = 0; + + for (i = 0; i < gp->dev->mc_count; i++) { + char *addrs = dmi->dmi_addr; + + dmi = dmi->next; + + if (!(*addrs & 1)) + continue; + + crc = 0xffffffffU; + for (byte = 0; byte < 6; byte++) { + for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + int test; + + test = ((bit ^ crc) & 0x01); + crc >>= 1; + if (test) + crc = crc ^ poly; + } + } + crc >>= 24; + hash_table[crc >> 4] |= 1 << (crc & 0xf); + } + writel(hash_table[0], gp->regs + MAC_HASH0); + writel(hash_table[1], gp->regs + MAC_HASH1); + writel(hash_table[2], gp->regs + MAC_HASH2); + writel(hash_table[3], gp->regs + MAC_HASH3); + writel(hash_table[4], gp->regs + MAC_HASH4); + writel(hash_table[5], gp->regs + MAC_HASH5); + writel(hash_table[6], gp->regs + MAC_HASH6); + writel(hash_table[7], gp->regs + MAC_HASH7); + writel(hash_table[8], gp->regs + MAC_HASH8); + writel(hash_table[9], gp->regs + MAC_HASH9); + writel(hash_table[10], gp->regs + MAC_HASH10); + writel(hash_table[11], gp->regs + MAC_HASH11); + writel(hash_table[12], gp->regs + MAC_HASH12); + writel(hash_table[13], gp->regs + MAC_HASH13); + writel(hash_table[14], gp->regs + MAC_HASH14); + writel(hash_table[15], gp->regs + MAC_HASH15); + } + + writel(0, gp->regs + MAC_NCOLL); + writel(0, gp->regs + MAC_FASUCC); + writel(0, gp->regs + MAC_ECOLL); + writel(0, gp->regs + MAC_LCOLL); + writel(0, gp->regs + MAC_DTIMER); + writel(0, gp->regs + MAC_PATMPS); + writel(0, gp->regs + MAC_RFCTR); + writel(0, gp->regs + MAC_LERR); + writel(0, gp->regs + MAC_AERR); + writel(0, gp->regs + MAC_FCSERR); + writel(0, gp->regs + MAC_RXCVERR); + + /* Clear RX/TX/MAC/XIF config, we will set these up and enable + * them once a link is established. + */ + writel(0, gp->regs + MAC_TXCFG); + writel(rxcfg, gp->regs + MAC_RXCFG); + writel(0, gp->regs + MAC_MCCFG); + writel(0, gp->regs + MAC_XIFCFG); + + writel((MAC_TXSTAT_URUN | MAC_TXSTAT_MPE | + MAC_TXSTAT_NCE | MAC_TXSTAT_ECE | + MAC_TXSTAT_LCE | MAC_TXSTAT_FCE | + MAC_TXSTAT_DTE | MAC_TXSTAT_PCE), gp->regs + MAC_TXMASK); + writel((MAC_RXSTAT_OFLW | MAC_RXSTAT_FCE | + MAC_RXSTAT_ACE | MAC_RXSTAT_CCE | + MAC_RXSTAT_LCE | MAC_RXSTAT_VCE), gp->regs + MAC_RXMASK); + writel(0, gp->regs + MAC_MCMASK); +} + +static void gem_init_hw(struct gem *gp) +{ + gem_init_phy(gp); + gem_init_dma(gp); + gem_init_mac(gp); + + writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK); + + gp->timer_ticks = 0; + gp->lstate = aneg_wait; + gp->link_timer.expires = jiffies + ((12 * HZ) / 10); + add_timer(&gp->link_timer); +} + +static int gem_open(struct net_device *dev) +{ + struct gem *gp = (struct gem *) dev->priv; + unsigned long regs = gp->regs; + + del_timer(&gp->link_timer); + + if (request_irq(gp->pdev->irq, gem_interrupt, + SA_SHIRQ, dev->name, (void *)dev)) + return -EAGAIN; + + gem_stop(gp, regs); + gem_init_rings(gp, 0); + gem_init_hw(gp); + + return 0; +} + +static int gem_close(struct net_device *dev) +{ + struct gem *gp = dev->priv; + + free_irq(gp->pdev->irq, (void *)dev); + return 0; +} + +static struct net_device_stats *gem_get_stats(struct net_device *dev) +{ + struct gem *gp = dev->priv; + struct net_device_stats *stats = &gp->net_stats; + + stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); + writel(0, gp->regs + MAC_FCSERR); + + stats->rx_frame_errors += readl(gp->regs + MAC_AERR); + writel(0, gp->regs + MAC_AERR); + + stats->rx_length_errors += readl(gp->regs + MAC_LERR); + writel(0, gp->regs + MAC_LERR); + + stats->tx_aborted_errors += readl(gp->regs + MAC_ECOLL); + stats->collisions += + (readl(gp->regs + MAC_ECOLL) + + readl(gp->regs + MAC_LCOLL)); + writel(0, gp->regs + MAC_ECOLL); + writel(0, gp->regs + MAC_LCOLL); + + return &gp->net_stats; +} + +static void gem_set_multicast(struct net_device *dev) +{ + struct gem *gp = dev->priv; + + netif_stop_queue(dev); + + if ((gp->dev->flags & IFF_ALLMULTI) || + (gp->dev->mc_count > 256)) { + writel(0xffff, gp->regs + MAC_HASH0); + writel(0xffff, gp->regs + MAC_HASH1); + writel(0xffff, gp->regs + MAC_HASH2); + writel(0xffff, gp->regs + MAC_HASH3); + writel(0xffff, gp->regs + MAC_HASH4); + writel(0xffff, gp->regs + MAC_HASH5); + writel(0xffff, gp->regs + MAC_HASH6); + writel(0xffff, gp->regs + MAC_HASH7); + writel(0xffff, gp->regs + MAC_HASH8); + writel(0xffff, gp->regs + MAC_HASH9); + writel(0xffff, gp->regs + MAC_HASH10); + writel(0xffff, gp->regs + MAC_HASH11); + writel(0xffff, gp->regs + MAC_HASH12); + writel(0xffff, gp->regs + MAC_HASH13); + writel(0xffff, gp->regs + MAC_HASH14); + writel(0xffff, gp->regs + MAC_HASH15); + } else if (gp->dev->flags & IFF_PROMISC) { + u32 rxcfg = readl(gp->regs + MAC_RXCFG); + int limit = 10000; + + writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG); + while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) { + if (!limit--) + break; + udelay(10); + } + + rxcfg |= MAC_RXCFG_PROM; + writel(rxcfg, gp->regs + MAC_RXCFG); + } else { + u16 hash_table[16]; + u32 crc, poly = CRC_POLYNOMIAL_LE; + struct dev_mc_list *dmi = gp->dev->mc_list; + int i, j, bit, byte; + + for (i = 0; i < 16; i++) + hash_table[i] = 0; + + for (i = 0; i < dev->mc_count; i++) { + char *addrs = dmi->dmi_addr; + + dmi = dmi->next; + + if (!(*addrs & 1)) + continue; + + crc = 0xffffffffU; + for (byte = 0; byte < 6; byte++) { + for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) { + int test; + + test = ((bit ^ crc) & 0x01); + crc >>= 1; + if (test) + crc = crc ^ poly; + } + } + crc >>= 24; + hash_table[crc >> 4] |= 1 << (crc & 0xf); + } + writel(hash_table[0], gp->regs + MAC_HASH0); + writel(hash_table[1], gp->regs + MAC_HASH1); + writel(hash_table[2], gp->regs + MAC_HASH2); + writel(hash_table[3], gp->regs + MAC_HASH3); + writel(hash_table[4], gp->regs + MAC_HASH4); + writel(hash_table[5], gp->regs + MAC_HASH5); + writel(hash_table[6], gp->regs + MAC_HASH6); + writel(hash_table[7], gp->regs + MAC_HASH7); + writel(hash_table[8], gp->regs + MAC_HASH8); + writel(hash_table[9], gp->regs + MAC_HASH9); + writel(hash_table[10], gp->regs + MAC_HASH10); + writel(hash_table[11], gp->regs + MAC_HASH11); + writel(hash_table[12], gp->regs + MAC_HASH12); + writel(hash_table[13], gp->regs + MAC_HASH13); + writel(hash_table[14], gp->regs + MAC_HASH14); + writel(hash_table[15], gp->regs + MAC_HASH15); + } + + netif_wake_queue(dev); +} + +static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + return -EINVAL; +} + +static int __devinit gem_check_invariants(struct gem *gp) +{ + struct pci_dev *pdev = gp->pdev; + u32 mif_cfg = readl(gp->regs + MIF_CFG); + + if (pdev->device == PCI_DEVICE_ID_SUN_RIO_GEM +#if 0 + || pdev->device == PCI_DEVICE_ID_SUN_PPC_GEM +#endif + ) { + /* One of the MII PHYs _must_ be present + * as these chip versions have no gigabit + * PHY. + */ + if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) { + printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n", + mif_cfg); + return -1; + } + } + + /* Determine initial PHY interface type guess. MDIO1 is the + * external PHY and thus takes precedence over MDIO0. + */ + if (mif_cfg & MIF_CFG_MDI1) + gp->phy_type = phy_mii_mdio1; + else if (mif_cfg & MIF_CFG_MDI0) + gp->phy_type = phy_mii_mdio0; + else + gp->phy_type = phy_serialink; + + if (gp->phy_type == phy_mii_mdio1 || + gp->phy_type == phy_mii_mdio0) { + int i; + + for (i = 0; i < 32; i++) { + gp->mii_phy_addr = i; + if (phy_read(gp, PHY_CTRL) != 0xffff) + break; + } + } + + /* Fetch the FIFO configurations now too. */ + gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64; + gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64; + + if (pdev->device == PCI_DEVICE_ID_SUN_GEM) { + if (gp->tx_fifo_sz != (9 * 1024) || + gp->rx_fifo_sz != (20 * 1024)) { + printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n", + gp->tx_fifo_sz, gp->rx_fifo_sz); + return -1; + } + } else { + if (gp->tx_fifo_sz != (2 * 1024) || + gp->rx_fifo_sz != (2 * 1024)) { + printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n", + gp->tx_fifo_sz, gp->rx_fifo_sz); + return -1; + } + } + + /* Calculate pause thresholds. Setting the OFF threshold to the + * full RX fifo size effectively disables PAUSE generation which + * is what we do for 10/100 only GEMs which have FIFOs too small + * to make real gains from PAUSE. + */ + if (gp->rx_fifo_sz <= (2 * 1024)) { + gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz; + } else { + int off = ((gp->rx_fifo_sz * 3) / 4); + int on = off - (1 * 1024); + + gp->rx_pause_off = off; + gp->rx_pause_on = on; + } + + { + u32 bifcfg = readl(gp->regs + GREG_BIFCFG); + + bifcfg |= GREG_BIFCFG_B64DIS; + writel(bifcfg, gp->regs + GREG_BIFCFG); + } + + return 0; +} + +static int __devinit gem_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int gem_version_printed = 0; + unsigned long gemreg_base, gemreg_len; + struct net_device *dev; + struct gem *gp; + int i; + + if (gem_version_printed++ == 0) + printk(KERN_INFO "%s", version); + + gemreg_base = pci_resource_start(pdev, 0); + gemreg_len = pci_resource_len(pdev, 0); + + if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) { + printk(KERN_ERR PFX "Cannot find proper PCI device " + "base address, aborting.\n"); + return -ENODEV; + } + + dev = init_etherdev(NULL, sizeof(*gp)); + if (!dev) { + printk(KERN_ERR PFX "Etherdev init failed, aborting.\n"); + return -ENOMEM; + } + + if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) { + printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, " + "aborting.\n", gemreg_base, gemreg_len); + goto err_out_free_netdev; + } + + if (pci_enable_device(pdev)) { + printk(KERN_ERR PFX "Cannot enable MMIO operation, " + "aborting.\n"); + goto err_out_free_mmio_res; + } + + pci_set_master(pdev); + + gp = dev->priv; + memset(gp, 0, sizeof(*gp)); + + gp->pdev = pdev; + dev->base_addr = (long) pdev; + + spin_lock_init(&gp->lock); + + gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len); + if (gp->regs == 0UL) { + printk(KERN_ERR PFX "Cannot map device registers, " + "aborting.\n"); + goto err_out_free_mmio_res; + } + + if (gem_check_invariants(gp)) + goto err_out_iounmap; + + /* It is guarenteed that the returned buffer will be at least + * PAGE_SIZE aligned. + */ + gp->init_block = (struct gem_init_block *) + pci_alloc_consistent(pdev, sizeof(struct gem_init_block), + &gp->gblock_dvma); + if (!gp->init_block) { + printk(KERN_ERR PFX "Cannot allocate init block, " + "aborting.\n"); + goto err_out_iounmap; + } + + pci_set_drvdata(pdev, dev); + + printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ", + dev->name); + +#ifdef __sparc__ + memcpy(dev->dev_addr, idprom->id_ethaddr, 6); +#endif + + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], + i == 5 ? ' ' : ':'); + printk("\n"); + + init_timer(&gp->link_timer); + gp->link_timer.function = gem_link_timer; + gp->link_timer.data = (unsigned long) gp; + + gp->dev = dev; + dev->open = gem_open; + dev->stop = gem_close; + dev->hard_start_xmit = gem_start_xmit; + dev->get_stats = gem_get_stats; + dev->set_multicast_list = gem_set_multicast; + dev->do_ioctl = gem_ioctl; + dev->irq = pdev->irq; + dev->dma = 0; + + return 0; + +err_out_iounmap: + iounmap((void *) gp->regs); + +err_out_free_mmio_res: + release_mem_region(gemreg_base, gemreg_len); + +err_out_free_netdev: + unregister_netdev(dev); + kfree(dev); + + return -ENODEV; + +} + +static void gem_suspend(struct pci_dev *pdev) +{ +} + +static void gem_resume(struct pci_dev *pdev) +{ +} + +static void __devexit gem_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + struct gem *gp = dev->priv; + + unregister_netdev(dev); + + pci_free_consistent(pdev, + sizeof(struct gem_init_block), + gp->init_block, + gp->gblock_dvma); + iounmap((void *) gp->regs); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + kfree(dev); + + pci_set_drvdata(pdev, NULL); + } +} + +static struct pci_driver gem_driver = { + name: GEM_MODULE_NAME, + id_table: gem_pci_tbl, + probe: gem_init_one, + remove: gem_remove_one, + suspend: gem_suspend, + resume: gem_resume, +}; + +static int __init gem_init(void) +{ + return pci_module_init(&gem_driver); +} + +static void __exit gem_cleanup(void) +{ + pci_unregister_driver(&gem_driver); +} + +module_init(gem_init); +module_exit(gem_cleanup); diff -u --recursive --new-file v2.4.2/linux/drivers/net/sungem.h linux/drivers/net/sungem.h --- v2.4.2/linux/drivers/net/sungem.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sungem.h Sun Mar 25 18:14:21 2001 @@ -0,0 +1,969 @@ +/* $Id: sungem.h,v 1.5 2001/03/21 23:02:04 davem Exp $ + * sungem.h: Definitions for Sun GEM ethernet driver. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +#ifndef _SUNGEM_H +#define _SUNGEM_H + +/* Global Registers */ +#define GREG_SEBSTATE 0x0000UL /* SEB State Register */ +#define GREG_CFG 0x0004UL /* Configuration Register */ +#define GREG_STAT 0x000CUL /* Status Register */ +#define GREG_IMASK 0x0010UL /* Interrupt Mask Register */ +#define GREG_IACK 0x0014UL /* Interrupt ACK Register */ +#define GREG_STAT2 0x001CUL /* Alias of GREG_STAT */ +#define GREG_PCIESTAT 0x1000UL /* PCI Error Status Register */ +#define GREG_PCIEMASK 0x1004UL /* PCI Error Mask Register */ +#define GREG_BIFCFG 0x1008UL /* BIF Configuration Register */ +#define GREG_BIFDIAG 0x100CUL /* BIF Diagnostics Register */ +#define GREG_SWRST 0x1010UL /* Software Reset Register */ + +/* Global SEB State Register */ +#define GREG_SEBSTATE_ARB 0x00000003 /* State of Arbiter */ +#define GREG_SEBSTATE_RXWON 0x00000004 /* RX won internal arbitration */ + +/* Global Configuration Register */ +#define GREG_CFG_IBURST 0x00000001 /* Infinite Burst */ +#define GREG_CFG_TXDMALIM 0x0000003e /* TX DMA grant limit */ +#define GREG_CFG_RXDMALIM 0x000007c0 /* RX DMA grant limit */ + +/* Global Interrupt Status Register. + * + * Reading this register automatically clears bits 0 through 6. + * This auto-clearing does not occur when the alias at GREG_STAT2 + * is read instead. The rest of the interrupt bits only clear when + * the secondary interrupt status register corresponding to that + * bit is read (ie. if GREG_STAT_PCS is set, it will be cleared by + * reading PCS_ISTAT). + */ +#define GREG_STAT_TXINTME 0x00000001 /* TX INTME frame transferred */ +#define GREG_STAT_TXALL 0x00000002 /* All TX frames transferred */ +#define GREG_STAT_TXDONE 0x00000004 /* One TX frame transferred */ +#define GREG_STAT_RXDONE 0x00000010 /* One RX frame arrived */ +#define GREG_STAT_RXNOBUF 0x00000020 /* No free RX buffers available */ +#define GREG_STAT_RXTAGERR 0x00000040 /* RX tag framing is corrupt */ +#define GREG_STAT_PCS 0x00002000 /* PCS signalled interrupt */ +#define GREG_STAT_TXMAC 0x00004000 /* TX MAC signalled interrupt */ +#define GREG_STAT_RXMAC 0x00008000 /* RX MAC signalled interrupt */ +#define GREG_STAT_MAC 0x00010000 /* MAC Control signalled irq */ +#define GREG_STAT_MIF 0x00020000 /* MIF signalled interrupt */ +#define GREG_STAT_PCIERR 0x00040000 /* PCI Error interrupt */ +#define GREG_STAT_TXNR 0xfff80000 /* == TXDMA_TXDONE reg val */ +#define GREG_STAT_TXNR_SHIFT 19 + +#define GREG_STAT_ABNORMAL (GREG_STAT_RXNOBUF | GREG_STAT_RXTAGERR | \ + GREG_STAT_PCS | GREG_STAT_TXMAC | GREG_STAT_RXMAC | \ + GREG_STAT_MAC | GREG_STAT_MIF | GREG_STAT_PCIERR) + +/* The layout of GREG_IMASK and GREG_IACK is identical to GREG_STAT. + * Bits set in GREG_IMASK will prevent that interrupt type from being + * signalled to the cpu. GREG_IACK can be used to clear specific top-level + * interrupt conditions in GREG_STAT, ie. it only works for bits 0 through 6. + * Setting the bit will clear that interrupt, clear bits will have no effect + * on GREG_STAT. + */ + +/* Global PCI Error Status Register */ +#define GREG_PCIESTAT_BADACK 0x00000001 /* No ACK64# during ABS64 cycle */ +#define GREG_PCIESTAT_DTRTO 0x00000002 /* Delayed transaction timeout */ +#define GREG_PCIESTAT_OTHER 0x00000004 /* Other PCI error, check cfg space */ + +/* The layout of the GREG_PCIEMASK is identical to that of GREG_PCIESTAT. + * Bits set in GREG_PCIEMASK will prevent that interrupt type from being + * signalled to the cpu. + */ + +/* Global BIF Configuration Register */ +#define GREG_BIFCFG_SLOWCLK 0x00000001 /* Set if PCI runs < 25Mhz */ +#define GREG_BIFCFG_B64DIS 0x00000002 /* Disable 64bit wide data cycle*/ +#define GREG_BIFCFG_M66EN 0x00000004 /* Set if on 66Mhz PCI segment */ + +/* Global BIF Diagnostics Register */ +#define GREG_BIFDIAG_BURSTSM 0x007f0000 /* PCI Burst state machine */ +#define GREG_BIFDIAG_BIFSM 0xff000000 /* BIF state machine */ + +/* Global Software Reset Register. + * + * This register is used to perform a global reset of the RX and TX portions + * of the GEM asic. Setting the RX or TX reset bit will start the reset. + * The driver _MUST_ poll these bits until they clear. One may not attempt + * to program any other part of GEM until the bits clear. + */ +#define GREG_SWRST_TXRST 0x00000001 /* TX Software Reset */ +#define GREG_SWRST_RXRST 0x00000002 /* RX Software Reset */ +#define GREG_SWRST_RSTOUT 0x00000004 /* Force RST# pin active */ + +/* TX DMA Registers */ +#define TXDMA_KICK 0x2000UL /* TX Kick Register */ +#define TXDMA_CFG 0x2004UL /* TX Configuration Register */ +#define TXDMA_DBLOW 0x2008UL /* TX Desc. Base Low */ +#define TXDMA_DBHI 0x200CUL /* TX Desc. Base High */ +#define TXDMA_FWPTR 0x2014UL /* TX FIFO Write Pointer */ +#define TXDMA_FSWPTR 0x2018UL /* TX FIFO Shadow Write Pointer */ +#define TXDMA_FRPTR 0x201CUL /* TX FIFO Read Pointer */ +#define TXDMA_FSRPTR 0x2020UL /* TX FIFO Shadow Read Pointer */ +#define TXDMA_PCNT 0x2024UL /* TX FIFO Packet Counter */ +#define TXDMA_SMACHINE 0x2028UL /* TX State Machine Register */ +#define TXDMA_DPLOW 0x2030UL /* TX Data Pointer Low */ +#define TXDMA_DPHI 0x2034UL /* TX Data Pointer High */ +#define TXDMA_TXDONE 0x2100UL /* TX Completion Register */ +#define TXDMA_FADDR 0x2104UL /* TX FIFO Address */ +#define TXDMA_FTAG 0x2108UL /* TX FIFO Tag */ +#define TXDMA_DLOW 0x210CUL /* TX FIFO Data Low */ +#define TXDMA_DHIT1 0x2110UL /* TX FIFO Data HighT1 */ +#define TXDMA_DHIT0 0x2114UL /* TX FIFO Data HighT0 */ +#define TXDMA_FSZ 0x2118UL /* TX FIFO Size */ + +/* TX Kick Register. + * + * This 13-bit register is programmed by the driver to hold the descriptor + * entry index which follows the last valid transmit descriptor. + */ + +/* TX Completion Register. + * + * This 13-bit register is updated by GEM to hold to descriptor entry index + * which follows the last descriptor already processed by GEM. Note that + * this value is mirrored in GREG_STAT which eliminates the need to even + * access this register in the driver during interrupt processing. + */ + +/* TX Configuration Register. + * + * Note that TXDMA_CFG_FTHRESH, the TX FIFO Threshold, is an obsolete feature + * that was meant to be used with jumbo packets. It should be set to the + * maximum value of 0x4ff, else one risks getting TX MAC Underrun errors. + */ +#define TXDMA_CFG_ENABLE 0x00000001 /* Enable TX DMA channel */ +#define TXDMA_CFG_RINGSZ 0x0000001e /* TX descriptor ring size */ +#define TXDMA_CFG_RINGSZ_32 0x00000000 /* 32 TX descriptors */ +#define TXDMA_CFG_RINGSZ_64 0x00000002 /* 64 TX descriptors */ +#define TXDMA_CFG_RINGSZ_128 0x00000004 /* 128 TX descriptors */ +#define TXDMA_CFG_RINGSZ_256 0x00000006 /* 256 TX descriptors */ +#define TXDMA_CFG_RINGSZ_512 0x00000008 /* 512 TX descriptors */ +#define TXDMA_CFG_RINGSZ_1K 0x0000000a /* 1024 TX descriptors */ +#define TXDMA_CFG_RINGSZ_2K 0x0000000c /* 2048 TX descriptors */ +#define TXDMA_CFG_RINGSZ_4K 0x0000000e /* 4096 TX descriptors */ +#define TXDMA_CFG_RINGSZ_8K 0x00000010 /* 8192 TX descriptors */ +#define TXDMA_CFG_PIOSEL 0x00000020 /* Enable TX FIFO PIO from cpu */ +#define TXDMA_CFG_FTHRESH 0x001ffc00 /* TX FIFO Threshold, obsolete */ +#define TXDMA_CFG_PMODE 0x00200000 /* TXALL irq means TX FIFO empty*/ + +/* TX Descriptor Base Low/High. + * + * These two registers store the 53 most significant bits of the base address + * of the TX descriptor table. The 11 least significant bits are always + * zero. As a result, the TX descriptor table must be 2K aligned. + */ + +/* The rest of the TXDMA_* registers are for diagnostics and debug, I will document + * them later. -DaveM + */ + +/* Receive DMA Registers */ +#define RXDMA_CFG 0x4000UL /* RX Configuration Register */ +#define RXDMA_DBLOW 0x4004UL /* RX Descriptor Base Low */ +#define RXDMA_DBHI 0x4008UL /* RX Descriptor Base High */ +#define RXDMA_FWPTR 0x400CUL /* RX FIFO Write Pointer */ +#define RXDMA_FSWPTR 0x4010UL /* RX FIFO Shadow Write Pointer */ +#define RXDMA_FRPTR 0x4014UL /* RX FIFO Read Pointer */ +#define RXDMA_PCNT 0x4018UL /* RX FIFO Packet Counter */ +#define RXDMA_SMACHINE 0x401CUL /* RX State Machine Register */ +#define RXDMA_PTHRESH 0x4020UL /* Pause Thresholds */ +#define RXDMA_DPLOW 0x4024UL /* RX Data Pointer Low */ +#define RXDMA_DPHI 0x4028UL /* RX Data Pointer High */ +#define RXDMA_KICK 0x4100UL /* RX Kick Register */ +#define RXDMA_DONE 0x4104UL /* RX Completion Register */ +#define RXDMA_BLANK 0x4108UL /* RX Blanking Register */ +#define RXDMA_FADDR 0x410CUL /* RX FIFO Address */ +#define RXDMA_FTAG 0x4110UL /* RX FIFO Tag */ +#define RXDMA_DLOW 0x4114UL /* RX FIFO Data Low */ +#define RXDMA_DHIT1 0x4118UL /* RX FIFO Data HighT0 */ +#define RXDMA_DHIT0 0x411CUL /* RX FIFO Data HighT1 */ +#define RXDMA_FSZ 0x4120UL /* RX FIFO Size */ + +/* RX Configuration Register. */ +#define RXDMA_CFG_ENABLE 0x00000001 /* Enable RX DMA channel */ +#define RXDMA_CFG_RINGSZ 0x0000001e /* RX descriptor ring size */ +#define RXDMA_CFG_RINGSZ_32 0x00000000 /* - 32 entries */ +#define RXDMA_CFG_RINGSZ_64 0x00000002 /* - 64 entries */ +#define RXDMA_CFG_RINGSZ_128 0x00000004 /* - 128 entries */ +#define RXDMA_CFG_RINGSZ_256 0x00000006 /* - 256 entries */ +#define RXDMA_CFG_RINGSZ_512 0x00000008 /* - 512 entries */ +#define RXDMA_CFG_RINGSZ_1K 0x0000000a /* - 1024 entries */ +#define RXDMA_CFG_RINGSZ_2K 0x0000000c /* - 2048 entries */ +#define RXDMA_CFG_RINGSZ_4K 0x0000000e /* - 4096 entries */ +#define RXDMA_CFG_RINGSZ_8K 0x00000010 /* - 8192 entries */ +#define RXDMA_CFG_RINGSZ_BDISAB 0x00000020 /* Disable RX desc batching */ +#define RXDMA_CFG_FBOFF 0x00001c00 /* Offset of first data byte */ +#define RXDMA_CFG_CSUMOFF 0x000fe000 /* Skip bytes before csum calc */ +#define RXDMA_CFG_FTHRESH 0x07000000 /* RX FIFO dma start threshold */ +#define RXDMA_CFG_FTHRESH_64 0x00000000 /* - 64 bytes */ +#define RXDMA_CFG_FTHRESH_128 0x01000000 /* - 128 bytes */ +#define RXDMA_CFG_FTHRESH_256 0x02000000 /* - 256 bytes */ +#define RXDMA_CFG_FTHRESH_512 0x03000000 /* - 512 bytes */ +#define RXDMA_CFG_FTHRESH_1K 0x04000000 /* - 1024 bytes */ +#define RXDMA_CFG_FTHRESH_2K 0x05000000 /* - 2048 bytes */ + +/* RX Descriptor Base Low/High. + * + * These two registers store the 53 most significant bits of the base address + * of the RX descriptor table. The 11 least significant bits are always + * zero. As a result, the RX descriptor table must be 2K aligned. + */ + +/* RX PAUSE Thresholds. + * + * These values determine when XOFF and XON PAUSE frames are emitted by + * GEM. The thresholds measure RX FIFO occupancy in units of 64 bytes. + */ +#define RXDMA_PTHRESH_OFF 0x000001ff /* XOFF emitted w/FIFO > this */ +#define RXDMA_PTHRESH_ON 0x001ff000 /* XON emitted w/FIFO < this */ + +/* RX Kick Register. + * + * This 13-bit register is written by the host CPU and holds the last + * valid RX descriptor number plus one. This is, if 'N' is written to + * this register, it means that all RX descriptors up to but excluding + * 'N' are valid. + * + * The hardware requires that RX descriptors are posted in increments + * of 4. This means 'N' must be a multiple of four. For the best + * performance, the first new descriptor being posted should be (PCI) + * cache line aligned. + */ + +/* RX Completion Register. + * + * This 13-bit register is updated by GEM to indicate which RX descriptors + * have already been used for receive frames. All descriptors up to but + * excluding the value in this register are ready to be processed. GEM + * updates this register value after the RX FIFO empties completely into + * the RX descriptor's buffer, but before the RX_DONE bit is set in the + * interrupt status register. + */ + +/* RX Blanking Register. */ +#define RXDMA_BLANK_IPKTS 0x000001ff /* RX_DONE asserted after this + * many packets received since + * previous RX_DONE. + */ +#define RXDMA_BLANK_ITIME 0x000ff000 /* RX_DONE asserted after this + * many clocks (measured in 2048 + * PCI clocks) were counted since + * the previous RX_DONE. + */ + +/* RX FIFO Size. + * + * This 11-bit read-only register indicates how large, in units of 64-bytes, + * the RX FIFO is. The driver uses this to properly configure the RX PAUSE + * thresholds. + */ + +/* The rest of the RXDMA_* registers are for diagnostics and debug, I will document + * them later. -DaveM + */ + +/* MAC Registers */ +#define MAC_TXRST 0x6000UL /* TX MAC Software Reset Command*/ +#define MAC_RXRST 0x6004UL /* RX MAC Software Reset Command*/ +#define MAC_SNDPAUSE 0x6008UL /* Send Pause Command Register */ +#define MAC_TXSTAT 0x6010UL /* TX MAC Status Register */ +#define MAC_RXSTAT 0x6014UL /* RX MAC Status Register */ +#define MAC_CSTAT 0x6018UL /* MAC Control Status Register */ +#define MAC_TXMASK 0x6020UL /* TX MAC Mask Register */ +#define MAC_RXMASK 0x6024UL /* RX MAC Mask Register */ +#define MAC_MCMASK 0x6028UL /* MAC Control Mask Register */ +#define MAC_TXCFG 0x6030UL /* TX MAC Configuration Register*/ +#define MAC_RXCFG 0x6034UL /* RX MAC Configuration Register*/ +#define MAC_MCCFG 0x6038UL /* MAC Control Config Register */ +#define MAC_XIFCFG 0x603CUL /* XIF Configuration Register */ +#define MAC_IPG0 0x6040UL /* InterPacketGap0 Register */ +#define MAC_IPG1 0x6044UL /* InterPacketGap1 Register */ +#define MAC_IPG2 0x6048UL /* InterPacketGap2 Register */ +#define MAC_STIME 0x604CUL /* SlotTime Register */ +#define MAC_MINFSZ 0x6050UL /* MinFrameSize Register */ +#define MAC_MAXFSZ 0x6054UL /* MaxFrameSize Register */ +#define MAC_PASIZE 0x6058UL /* PA Size Register */ +#define MAC_JAMSIZE 0x605CUL /* JamSize Register */ +#define MAC_ATTLIM 0x6060UL /* Attempt Limit Register */ +#define MAC_MCTYPE 0x6064UL /* MAC Control Type Register */ +#define MAC_ADDR0 0x6080UL /* MAC Address 0 Register */ +#define MAC_ADDR1 0x6084UL /* MAC Address 1 Register */ +#define MAC_ADDR2 0x6088UL /* MAC Address 2 Register */ +#define MAC_ADDR3 0x608CUL /* MAC Address 3 Register */ +#define MAC_ADDR4 0x6090UL /* MAC Address 4 Register */ +#define MAC_ADDR5 0x6094UL /* MAC Address 5 Register */ +#define MAC_ADDR6 0x6098UL /* MAC Address 6 Register */ +#define MAC_ADDR7 0x609CUL /* MAC Address 7 Register */ +#define MAC_ADDR8 0x60A0UL /* MAC Address 8 Register */ +#define MAC_AFILT0 0x60A4UL /* Address Filter 0 Register */ +#define MAC_AFILT1 0x60A8UL /* Address Filter 1 Register */ +#define MAC_AFILT2 0x60ACUL /* Address Filter 2 Register */ +#define MAC_AF21MSK 0x60B0UL /* Address Filter 2&1 Mask Reg */ +#define MAC_AF0MSK 0x60B4UL /* Address Filter 0 Mask Reg */ +#define MAC_HASH0 0x60C0UL /* Hash Table 0 Register */ +#define MAC_HASH1 0x60C4UL /* Hash Table 1 Register */ +#define MAC_HASH2 0x60C8UL /* Hash Table 2 Register */ +#define MAC_HASH3 0x60CCUL /* Hash Table 3 Register */ +#define MAC_HASH4 0x60D0UL /* Hash Table 4 Register */ +#define MAC_HASH5 0x60D4UL /* Hash Table 5 Register */ +#define MAC_HASH6 0x60D8UL /* Hash Table 6 Register */ +#define MAC_HASH7 0x60DCUL /* Hash Table 7 Register */ +#define MAC_HASH8 0x60E0UL /* Hash Table 8 Register */ +#define MAC_HASH9 0x60E4UL /* Hash Table 9 Register */ +#define MAC_HASH10 0x60E8UL /* Hash Table 10 Register */ +#define MAC_HASH11 0x60ECUL /* Hash Table 11 Register */ +#define MAC_HASH12 0x60F0UL /* Hash Table 12 Register */ +#define MAC_HASH13 0x60F4UL /* Hash Table 13 Register */ +#define MAC_HASH14 0x60F8UL /* Hash Table 14 Register */ +#define MAC_HASH15 0x60FCUL /* Hash Table 15 Register */ +#define MAC_NCOLL 0x6100UL /* Normal Collision Counter */ +#define MAC_FASUCC 0x6104UL /* First Attmpt. Succ Coll Ctr. */ +#define MAC_ECOLL 0x6108UL /* Excessive Collision Counter */ +#define MAC_LCOLL 0x610CUL /* Late Collision Counter */ +#define MAC_DTIMER 0x6110UL /* Defer Timer */ +#define MAC_PATMPS 0x6114UL /* Peak Attempts Register */ +#define MAC_RFCTR 0x6118UL /* Receive Frame Counter */ +#define MAC_LERR 0x611CUL /* Length Error Counter */ +#define MAC_AERR 0x6120UL /* Alignment Error Counter */ +#define MAC_FCSERR 0x6124UL /* FCS Error Counter */ +#define MAC_RXCVERR 0x6128UL /* RX code Violation Error Ctr */ +#define MAC_RANDSEED 0x6130UL /* Random Number Seed Register */ +#define MAC_SMACHINE 0x6134UL /* State Machine Register */ + +/* TX MAC Software Reset Command. */ +#define MAC_TXRST_CMD 0x00000001 /* Start sw reset, self-clears */ + +/* RX MAC Software Reset Command. */ +#define MAC_RXRST_CMD 0x00000001 /* Start sw reset, self-clears */ + +/* Send Pause Command. */ +#define MAC_SNDPAUSE_TS 0x0000ffff /* The pause_time operand used in + * Send_Pause and flow-control + * handshakes. + */ +#define MAC_SNDPAUSE_SP 0x00010000 /* Setting this bit instructs the MAC + * to send a Pause Flow Control + * frame onto the network. + */ + +/* TX MAC Status Register. */ +#define MAC_TXSTAT_XMIT 0x00000001 /* Frame Transmitted */ +#define MAC_TXSTAT_URUN 0x00000002 /* TX Underrun */ +#define MAC_TXSTAT_MPE 0x00000004 /* Max Packet Size Error */ +#define MAC_TXSTAT_NCE 0x00000008 /* Normal Collision Cntr Expire */ +#define MAC_TXSTAT_ECE 0x00000010 /* Excess Collision Cntr Expire */ +#define MAC_TXSTAT_LCE 0x00000020 /* Late Collision Cntr Expire */ +#define MAC_TXSTAT_FCE 0x00000040 /* First Collision Cntr Expire */ +#define MAC_TXSTAT_DTE 0x00000080 /* Defer Timer Expire */ +#define MAC_TXSTAT_PCE 0x00000100 /* Peak Attempts Cntr Expire */ + +/* RX MAC Status Register. */ +#define MAC_RXSTAT_RCV 0x00000001 /* Frame Received */ +#define MAC_RXSTAT_OFLW 0x00000002 /* Receive Overflow */ +#define MAC_RXSTAT_FCE 0x00000004 /* Frame Cntr Expire */ +#define MAC_RXSTAT_ACE 0x00000008 /* Align Error Cntr Expire */ +#define MAC_RXSTAT_CCE 0x00000010 /* CRC Error Cntr Expire */ +#define MAC_RXSTAT_LCE 0x00000020 /* Length Error Cntr Expire */ +#define MAC_RXSTAT_VCE 0x00000040 /* Code Violation Cntr Expire */ + +/* MAC Control Status Register. */ +#define MAC_CSTAT_PRCV 0x00000001 /* Pause Received */ +#define MAC_CSTAT_PS 0x00000002 /* Paused State */ +#define MAC_CSTAT_NPS 0x00000004 /* Not Paused State */ +#define MAC_CSTAT_PTR 0xffff0000 /* Pause Time Received */ + +/* The layout of the MAC_{TX,RX,C}MASK registers is identical to that + * of MAC_{TX,RX,C}STAT. Bits set in MAC_{TX,RX,C}MASK will prevent + * that interrupt type from being signalled to front end of GEM. For + * the interrupt to actually get sent to the cpu, it is necessary to + * properly set the appropriate GREG_IMASK_{TX,RX,}MAC bits as well. + */ + +/* TX MAC Configuration Register. + * + * NOTE: The TX MAC Enable bit must be cleared and polled until + * zero before any other bits in this register are changed. + * + * Also, enabling the Carrier Extension feature of GEM is + * a 3 step process 1) Set TX Carrier Extension 2) Set + * RX Carrier Extension 3) Set Slot Time to 0x200. This + * mode must be enabled when in half-duplex at 1Gbps, else + * it must be disabled. + */ +#define MAC_TXCFG_ENAB 0x00000001 /* TX MAC Enable */ +#define MAC_TXCFG_ICS 0x00000002 /* Ignore Carrier Sense */ +#define MAC_TXCFG_ICOLL 0x00000004 /* Ignore Collisions */ +#define MAC_TXCFG_EIPG0 0x00000008 /* Enable IPG0 */ +#define MAC_TXCFG_NGU 0x00000010 /* Never Give Up */ +#define MAC_TXCFG_NGUL 0x00000020 /* Never Give Up Limit */ +#define MAC_TXCFG_NBO 0x00000040 /* No Backoff */ +#define MAC_TXCFG_SD 0x00000080 /* Slow Down */ +#define MAC_TXCFG_NFCS 0x00000100 /* No FCS */ +#define MAC_TXCFG_TCE 0x00000200 /* TX Carrier Extension */ + +/* RX MAC Configuration Register. + * + * NOTE: The RX MAC Enable bit must be cleared and polled until + * zero before any other bits in this register are changed. + * + * Similar rules apply to the Hash Filter Enable bit when + * programming the hash table registers, and the Address Filter + * Enable bit when programming the address filter registers. + */ +#define MAC_RXCFG_ENAB 0x00000001 /* RX MAC Enable */ +#define MAC_RXCFG_SPAD 0x00000002 /* Strip Pad */ +#define MAC_RXCFG_SFCS 0x00000004 /* Strip FCS */ +#define MAC_RXCFG_PROM 0x00000008 /* Promiscuous Mode */ +#define MAC_RXCFG_PGRP 0x00000010 /* Promiscuous Group */ +#define MAC_RXCFG_HFE 0x00000020 /* Hash Filter Enable */ +#define MAC_RXCFG_AFE 0x00000040 /* Address Filter Enable */ +#define MAC_RXCFG_DDE 0x00000080 /* Disable Discard on Error */ +#define MAC_RXCFG_RCE 0x00000100 /* RX Carrier Extension */ + +/* MAC Control Config Register. */ +#define MAC_MCCFG_SPE 0x00000001 /* Send Pause Enable */ +#define MAC_MCCFG_RPE 0x00000002 /* Receive Pause Enable */ +#define MAC_MCCFG_PMC 0x00000004 /* Pass MAC Control */ + +/* XIF Configuration Register. + * + * NOTE: When leaving or entering loopback mode, a global hardware + * init of GEM should be performed. + */ +#define MAC_XIFCFG_OE 0x00000001 /* MII TX Output Driver Enable */ +#define MAC_XIFCFG_LBCK 0x00000002 /* Loopback TX to RX */ +#define MAC_XIFCFG_DISE 0x00000004 /* Disable RX path during TX */ +#define MAC_XIFCFG_GMII 0x00000008 /* Use GMII clocks + datapath */ +#define MAC_XIFCFG_MBOE 0x00000010 /* Controls MII_BUF_EN pin */ +#define MAC_XIFCFG_LLED 0x00000020 /* Force LINKLED# active (low) */ +#define MAC_XIFCFG_FLED 0x00000040 /* Force FDPLXLED# active (low) */ + +/* InterPacketGap0 Register. This 8-bit value is used as an extension + * to the InterPacketGap1 Register. Specifically it contributes to the + * timing of the RX-to-TX IPG. This value is ignored and presumed to + * be zero for TX-to-TX IPG calculations and/or when the Enable IPG0 bit + * is cleared in the TX MAC Configuration Register. + * + * This value in this register in terms of media byte time. + * + * Recommended value: 0x00 + */ + +/* InterPacketGap1 Register. This 8-bit value defines the first 2/3 + * portion of the Inter Packet Gap. + * + * This value in this register in terms of media byte time. + * + * Recommended value: 0x08 + */ + +/* InterPacketGap2 Register. This 8-bit value defines the second 1/3 + * portion of the Inter Packet Gap. + * + * This value in this register in terms of media byte time. + * + * Recommended value: 0x04 + */ + +/* Slot Time Register. This 10-bit value specifies the slot time + * parameter in units of media byte time. It determines the physical + * span of the network. + * + * Recommended value: 0x40 + */ + +/* Minimum Frame Size Register. This 10-bit register specifies the + * smallest sized frame the TXMAC will send onto the medium, and the + * RXMAC will receive from the medium. + * + * Recommended value: 0x40 + */ + +/* Maximum Frame and Burst Size Register. + * + * This register specifies two things. First it specifies the maximum + * sized frame the TXMAC will send and the RXMAC will recognize as + * valid. Second, it specifies the maximum run length of a burst of + * packets sent in half-duplex gigabit modes. + * + * Recommended value: 0x200005ee + */ +#define MAC_MAXFSZ_MFS 0x00007fff /* Max Frame Size */ +#define MAC_MAXFSZ_MBS 0x7fff0000 /* Max Burst Size */ + +/* PA Size Register. This 10-bit register specifies the number of preamble + * bytes which will be transmitted at the beginning of each frame. A + * value of two or greater should be programmed here. + * + * Recommended value: 0x07 + */ + +/* Jam Size Register. This 4-bit register specifies the duration of + * the jam in units of media byte time. + * + * Recommended value: 0x04 + */ + +/* Attempts Limit Register. This 8-bit register specifies the number + * of attempts that the TXMAC will make to transmit a frame, before it + * resets its Attempts Counter. After reaching the Attempts Limit the + * TXMAC may or may not drop the frame, as determined by the NGU + * (Never Give Up) and NGUL (Never Give Up Limit) bits in the TXMAC + * Configuration Register. + * + * Recommended value: 0x10 + */ + +/* MAX Control Type Register. This 16-bit register specifies the + * "type" field of a MAC Control frame. The TXMAC uses this field to + * encapsulate the MAC Control frame for transmission, and the RXMAC + * uses it for decoding valid MAC Control frames received from the + * network. + * + * Recommended value: 0x8808 + */ + +/* MAC Address Registers. Each of these registers specify the + * ethernet MAC of the interface, 16-bits at a time. Register + * 0 specifies bits [47:32], register 1 bits [31:16], and register + * 2 bits [15:0]. + * + * Registers 3 through and including 5 specify an alternate + * MAC address for the interface. + * + * Registers 6 through and including 8 specify the MAC Control + * Address, which must be the reserved multicast address for MAC + * Control frames. + * + * Example: To program primary station address a:b:c:d:e:f into + * the chip. + * MAC_Address_2 = (a << 8) | b + * MAC_Address_1 = (c << 8) | d + * MAC_Address_0 = (e << 8) | f + */ + +/* Address Filter Registers. Registers 0 through 2 specify bit + * fields [47:32] through [15:0], respectively, of the address + * filter. The Address Filter 2&1 Mask Register denotes the 8-bit + * nibble mask for Address Filter Registers 2 and 1. The Address + * Filter 0 Mask Register denotes the 16-bit mask for the Address + * Filter Register 0. + */ + +/* Hash Table Registers. Registers 0 through 15 specify bit fields + * [255:240] through [15:0], respectively, of the hash table. + */ + +/* Statistics Registers. All of these registers are 16-bits and + * track occurances of a specific event. GEM can be configured + * to interrupt the host cpu when any of these counters overflow. + * They should all be explicitly initialized to zero when the interface + * is brought up. + */ + +/* Random Number Seed Register. This 10-bit value is used as the + * RNG seed inside GEM for the CSMA/CD backoff algorithm. It is + * recommended to program this register to the 10 LSB of the + * interfaces MAC address. + */ + +/* Pause Timer, read-only. This 16-bit timer is used to time the pause + * interval as indicated by a received pause flow control frame. + * A non-zero value in this timer indicates that the MAC is currently in + * the paused state. + */ + +/* MIF Registers */ +#define MIF_BBCLK 0x6200UL /* MIF Bit-Bang Clock */ +#define MIF_BBDATA 0x6204UL /* MIF Bit-Band Data */ +#define MIF_BBOENAB 0x6208UL /* MIF Bit-Bang Output Enable */ +#define MIF_FRAME 0x620CUL /* MIF Frame/Output Register */ +#define MIF_CFG 0x6210UL /* MIF Configuration Register */ +#define MIF_MASK 0x6214UL /* MIF Mask Register */ +#define MIF_STATUS 0x6218UL /* MIF Status Register */ +#define MIF_SMACHINE 0x621CUL /* MIF State Machine Register */ + +/* MIF Bit-Bang Clock. This 1-bit register is used to generate the + * MDC clock waveform on the MII Management Interface when the MIF is + * programmed in the "Bit-Bang" mode. Writing a '1' after a '0' into + * this register will create a rising edge on the MDC, while writing + * a '0' after a '1' will create a falling edge. For every bit that + * is transferred on the management interface, both edges have to be + * generated. + */ + +/* MIF Bit-Bang Data. This 1-bit register is used to generate the + * outgoing data (MDO) on the MII Management Interface when the MIF + * is programmed in the "Bit-Bang" mode. The daa will be steered to the + * appropriate MDIO based on the state of the PHY_Select bit in the MIF + * Configuration Register. + */ + +/* MIF Big-Band Output Enable. THis 1-bit register is used to enable + * ('1') or disable ('0') the I-directional driver on the MII when the + * MIF is programmed in the "Bit-Bang" mode. The MDIO should be enabled + * when data bits are transferred from the MIF to the transceiver, and it + * should be disabled when the interface is idle or when data bits are + * transferred from the transceiver to the MIF (data portion of a read + * instruction). Only one MDIO will be enabled at a given time, depending + * on the state of the PHY_Select bit in the MIF Configuration Register. + */ + +/* MIF Configuration Register. This 15-bit register controls the operation + * of the MIF. + */ +#define MIF_CFG_PSELECT 0x00000001 /* Xcvr slct: 0=mdio0 1=mdio1 */ +#define MIF_CFG_POLL 0x00000002 /* Enable polling mechanism */ +#define MIF_CFG_BBMODE 0x00000004 /* 1=bit-bang 0=frame mode */ +#define MIF_CFG_PRADDR 0x000000f8 /* Xcvr poll register address */ +#define MIF_CFG_MDI0 0x00000100 /* MDIO_0 present or read-bit */ +#define MIF_CFG_MDI1 0x00000200 /* MDIO_1 present or read-bit */ +#define MIF_CFG_PPADDR 0x00007c00 /* Xcvr poll PHY address */ + +/* MIF Frame/Output Register. This 32-bit register allows the host to + * communicate with a transceiver in frame mode (as opposed to big-bang + * mode). Writes by the host specify an instrution. After being issued + * the host must poll this register for completion. Also, after + * completion this register holds the data returned by the transceiver + * if applicable. + */ +#define MIF_FRAME_ST 0xc0000000 /* STart of frame */ +#define MIF_FRAME_OP 0x30000000 /* OPcode */ +#define MIF_FRAME_PHYAD 0x0f800000 /* PHY ADdress */ +#define MIF_FRAME_REGAD 0x007c0000 /* REGister ADdress */ +#define MIF_FRAME_TAMSB 0x00020000 /* Turn Around MSB */ +#define MIF_FRAME_TALSB 0x00010000 /* Turn Around LSB */ +#define MIF_FRAME_DATA 0x0000ffff /* Instruction Payload */ + +/* MIF Status Register. This register reports status when the MIF is + * operating in the poll mode. The poll status field is auto-clearing + * on read. + */ +#define MIF_STATUS_DATA 0xffff0000 /* Live image of XCVR reg */ +#define MIF_STATUS_STAT 0x0000ffff /* Which bits have changed */ + +/* MIF Mask Register. This 16-bit register is used when in poll mode + * to say which bits of the polled register will cause an interrupt + * when changed. + */ + +/* PCS/Serialink Registers */ +#define PCS_MIICTRL 0x9000UL /* PCS MII Control Register */ +#define PCS_MIISTAT 0x9004UL /* PCS MII Status Register */ +#define PCS_MIIADV 0x9008UL /* PCS MII Advertisement Reg */ +#define PCS_MIILP 0x900CUL /* PCS MII Link Partner Ability */ +#define PCS_CFG 0x9010UL /* PCS Configuration Register */ +#define PCS_SMACHINE 0x9014UL /* PCS State Machine Register */ +#define PCS_ISTAT 0x9018UL /* PCS Interrupt Status Reg */ +#define PCS_DMODE 0x9050UL /* Datapath Mode Register */ +#define PCS_SCTRL 0x9054UL /* Serialink Control Register */ +#define PCS_SOS 0x9058UL /* Shared Output Select Reg */ +#define PCS_SSTATE 0x905CUL /* Serialink State Register */ + +/* PCD MII Control Register. */ +#define PCS_MIICTRL_SPD 0x00000040 /* Read as one, writes ignored */ +#define PCS_MIICTRL_CT 0x00000080 /* Force COL signal active */ +#define PCS_MIICTRL_DM 0x00000100 /* Duplex mode, forced low */ +#define PCS_MIICTRL_RAN 0x00000200 /* Restart auto-neg, self clear */ +#define PCS_MIICTRL_ISO 0x00000400 /* Read as zero, writes ignored */ +#define PCS_MIICTRL_PD 0x00000800 /* Read as zero, writes ignored */ +#define PCS_MIICTRL_ANE 0x00001000 /* Auto-neg enable */ +#define PCS_MIICTRL_SS 0x00002000 /* Read as zero, writes ignored */ +#define PCS_MIICTRL_WB 0x00004000 /* Wrapback, loopback at 10-bit + * input side of Serialink + */ +#define PCS_MIICTRL_RST 0x00008000 /* Resets PCS, self clearing */ + +/* PCS MII Status Register. */ +#define PCS_MIISTAT_EC 0x00000001 /* Ext Capability: Read as zero */ +#define PCS_MIISTAT_JD 0x00000002 /* Jabber Detect: Read as zero */ +#define PCS_MIISTAT_LS 0x00000004 /* Link Status: 1=up 0=down */ +#define PCS_MIISTAT_ANA 0x00000008 /* Auto-neg Ability, always 1 */ +#define PCS_MIISTAT_RF 0x00000010 /* Remote Fault */ +#define PCS_MIISTAT_ANC 0x00000020 /* Auto-neg complete */ +#define PCS_MIISTAT_ES 0x00000100 /* Extended Status, always 1 */ + +/* PCS MII Advertisement Register. */ +#define PCS_MIIADV_FD 0x00000020 /* Advertise Full Duplex */ +#define PCS_MIIADV_HD 0x00000040 /* Advertise Half Duplex */ +#define PCS_MIIADV_SP 0x00000080 /* Advertise Symmetric Pause */ +#define PCS_MIIADV_AP 0x00000100 /* Advertise Asymmetric Pause */ +#define PCS_MIIADV_RF 0x00003000 /* Remote Fault */ +#define PCS_MIIADV_ACK 0x00004000 /* Read-only */ +#define PCS_MIIADV_NP 0x00008000 /* Next-page, forced low */ + +/* PCS MII Link Partner Ability Register. This register is equivalent + * to the Link Partnet Ability Register of the standard MII register set. + * It's layout corresponds to the PCS MII Advertisement Register. + */ + +/* PCS Configuration Register. */ +#define PCS_CFG_ENABLE 0x00000001 /* Must be zero while changing + * PCS MII advertisement reg. + */ +#define PCS_CFG_SDO 0x00000002 /* Signal detect override */ +#define PCS_CFG_SDL 0x00000004 /* Signal detect active low */ +#define PCS_CFG_JS 0x00000018 /* Jitter-study: + * 0 = normal operation + * 1 = high-frequency test pattern + * 2 = low-frequency test pattern + * 3 = reserved + */ +#define PCS_CFG_TO 0x00000020 /* 10ms auto-neg timer override */ + +/* PCS Interrupt Status Register. This register is self-clearing + * when read. + */ +#define PCS_ISTAT_LSC 0x00000004 /* Link Status Change */ + +/* Datapath Mode Register. */ +#define PCS_DMODE_SM 0x00000001 /* 1 = use internal Serialink */ +#define PCS_DMODE_ESM 0x00000002 /* External SERDES mode */ +#define PCS_DMODE_MGM 0x00000004 /* MII/GMII mode */ +#define PCS_DMODE_GMOE 0x00000008 /* GMII Output Enable */ + +/* Serialink Control Register. */ +#define PCS_SCTRL_LOOP 0x00000001 /* Loopback enable */ +#define PCS_SCTRL_ESCD 0x00000002 /* Enable sync char detection */ +#define PCS_SCTRL_LOCK 0x00000004 /* Lock to reference clock */ +#define PCS_SCTRL_EMP 0x00000018 /* Output driver emphasis */ +#define PCS_SCTRL_STEST 0x000001c0 /* Self test patterns */ +#define PCS_SCTRL_PDWN 0x00000200 /* Software power-down */ +#define PCS_SCTRL_RXZ 0x00000c00 /* PLL input to Serialink */ +#define PCS_SCTRL_RXP 0x00003000 /* PLL input to Serialink */ +#define PCS_SCTRL_TXZ 0x0000c000 /* PLL input to Serialink */ +#define PCS_SCTRL_TXP 0x00030000 /* PLL input to Serialink */ + +/* Shared Output Select Register. For test and debug, allows multiplexing + * test outputs into the PROM address pins. Set to zero for normal + * operation. + */ +#define PCS_SOS_PADDR 0x00000003 /* PROM Address */ + +/* PROM Image Space */ +#define PROM_START 0x100000UL /* Expansion ROM run time access*/ +#define PROM_SIZE 0x0fffffUL /* Size of ROM */ +#define PROM_END 0x200000UL /* End of ROM */ + +/* MII phy registers */ +#define PHY_CTRL 0x00 +#define PHY_STAT 0x01 +#define PHY_ADV 0x04 +#define PHY_LPA 0x05 + +#define PHY_CTRL_FDPLX 0x0100 /* Full duplex */ +#define PHY_CTRL_ISO 0x0400 /* Isloate MII from PHY */ +#define PHY_CTRL_ANRES 0x0200 /* Auto-negotiation restart */ +#define PHY_CTRL_ANENAB 0x1000 /* Auto-negotiation enable */ +#define PHY_CTRL_SPD100 0x2000 /* Select 100Mbps */ +#define PHY_CTRL_RST 0x8000 /* Reset PHY */ + +#define PHY_STAT_LSTAT 0x0004 /* Link status */ +#define PHY_STAT_ANEGC 0x0020 /* Auto-negotiation complete */ + +#define PHY_ADV_10HALF 0x0020 +#define PHY_ADV_10FULL 0x0040 +#define PHY_ADV_100HALF 0x0080 +#define PHY_ADV_100FULL 0x0100 + +#define PHY_LPA_10HALF 0x0020 +#define PHY_LPA_10FULL 0x0040 +#define PHY_LPA_100HALF 0x0080 +#define PHY_LPA_100FULL 0x0100 +#define PHY_LPA_FAULT 0x2000 + +/* When it can, GEM internally caches 4 aligned TX descriptors + * at a time, so that it can use full cacheline DMA reads. + * + * Note that unlike HME, there is no ownership bit in the descriptor + * control word. The same functionality is obtained via the TX-Kick + * and TX-Complete registers. As a result, GEM need not write back + * updated values to the TX descriptor ring, it only performs reads. + * + * Since TX descriptors are never modified by GEM, the driver can + * use the buffer DMA address as a place to keep track of allocated + * DMA mappings for a transmitted packet. + */ +struct gem_txd { + u64 control_word; + u64 buffer; +}; + +#define TXDCTRL_BUFSZ 0x0000000000007fff /* Buffer Size */ +#define TXDCTRL_CSTART 0x00000000001f8000 /* CSUM Start Offset */ +#define TXDCTRL_COFF 0x000000001fe00000 /* CSUM Stuff Offset */ +#define TXDCTRL_CENAB 0x0000000020000000 /* CSUM Enable */ +#define TXDCTRL_EOF 0x0000000040000000 /* End of Frame */ +#define TXDCTRL_SOF 0x0000000080000000 /* Start of Frame */ +#define TXDCTRL_INTME 0x0000000100000000 /* "Interrupt Me" */ +#define TXDCTRL_NOCRC 0x0000000200000000 /* No CRC Present */ + +/* GEM requires that RX descriptors are provided four at a time, + * aligned. Also, the RX ring may not wrap around. This means that + * there will be at least 4 unused desciptor entries in the middle + * of the RX ring at all times. + * + * Similar to HME, GEM assumes that it can write garbage bytes before + * the beginning of the buffer and right after the end in order to DMA + * whole cachelines. + * + * Unlike for TX, GEM does update the status word in the RX descriptors + * when packets arrive. Therefore an ownership bit does exist in the + * RX descriptors. It is advisory, GEM clears it but does not check + * it in any way. So when buffers are posted to the RX ring (via the + * RX Kick register) by the driver it must make sure the buffers are + * truly ready and that the ownership bits are set properly. + * + * Even though GEM modifies the RX descriptors, it guarentees that the + * buffer DMA address field will stay the same when it performs these + * updates. Therefore it can be used to keep track of DMA mappings + * by the host driver just as in the TX descriptor case above. + */ +struct gem_rxd { + u64 status_word; + u64 buffer; +}; + +#define RXDCTRL_TCPCSUM 0x000000000000ffff /* TCP Pseudo-CSUM */ +#define RXDCTRL_BUFSZ 0x000000007fff0000 /* Buffer Size */ +#define RXDCTRL_OWN 0x0000000080000000 /* GEM owns this entry */ +#define RXDCTRL_HASHVAL 0x0ffff00000000000 /* Hash Value */ +#define RXDCTRL_HPASS 0x1000000000000000 /* Passed Hash Filter */ +#define RXDCTRL_ALTMAC 0x2000000000000000 /* Matched ALT MAC */ +#define RXDCTRL_BAD 0x4000000000000000 /* Frame has bad CRC */ + +#define RXDCTRL_FRESH \ + ((((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16) & RXDCTRL_BUFSZ) | \ + RXDCTRL_OWN) + +#define TX_RING_SIZE 128 +#define RX_RING_SIZE 128 + +#if TX_RING_SIZE == 32 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_32 +#elif TX_RING_SIZE == 64 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_64 +#elif TX_RING_SIZE == 128 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_128 +#elif TX_RING_SIZE == 256 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_256 +#elif TX_RING_SIZE == 512 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_512 +#elif TX_RING_SIZE == 1024 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_1K +#elif TX_RING_SIZE == 2048 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_2K +#elif TX_RING_SIZE == 4096 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_4K +#elif TX_RING_SIZE == 8192 +#define TXDMA_CFG_BASE TXDMA_CFG_RINGSZ_8K +#else +#error TX_RING_SIZE value is illegal... +#endif + +#if RX_RING_SIZE == 32 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_32 +#elif RX_RING_SIZE == 64 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_64 +#elif RX_RING_SIZE == 128 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_128 +#elif RX_RING_SIZE == 256 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_256 +#elif RX_RING_SIZE == 512 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_512 +#elif RX_RING_SIZE == 1024 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_1K +#elif RX_RING_SIZE == 2048 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_2K +#elif RX_RING_SIZE == 4096 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_4K +#elif RX_RING_SIZE == 8192 +#define RXDMA_CFG_BASE RXDMA_CFG_RINGSZ_8K +#else +#error RX_RING_SIZE is illegal... +#endif + +#define NEXT_TX(N) (((N) + 1) & (TX_RING_SIZE - 1)) +#define NEXT_RX(N) (((N) + 1) & (RX_RING_SIZE - 1)) + +#define TX_BUFFS_AVAIL(GP) \ + (((GP)->tx_old <= (GP)->tx_new) ? \ + (GP)->tx_old + (TX_RING_SIZE - 1) - (GP)->tx_new : \ + (GP)->tx_old - (GP)->tx_new - 1) + +#define RX_OFFSET 2 +#define RX_BUF_ALLOC_SIZE (1546 + RX_OFFSET + 64) + +#define RX_COPY_THRESHOLD 256 + +struct gem_init_block { + struct gem_txd txd[TX_RING_SIZE]; + struct gem_rxd rxd[RX_RING_SIZE]; +}; + +enum gem_phy_type { + phy_mii_mdio0, + phy_mii_mdio1, + phy_serialink, + phy_serdes, +}; + +enum link_state { + aneg_wait, + force_wait, +}; + +struct gem { + spinlock_t lock; + unsigned long regs; + int rx_new, rx_old; + int tx_new, tx_old; + + struct gem_init_block *init_block; + + struct sk_buff *rx_skbs[RX_RING_SIZE]; + struct sk_buff *tx_skbs[RX_RING_SIZE]; + + struct net_device_stats net_stats; + + enum gem_phy_type phy_type; + int tx_fifo_sz; + int rx_fifo_sz; + int rx_pause_off; + int rx_pause_on; + int mii_phy_addr; + + /* Diagnostic counters and state. */ + u64 pause_entered; + u16 pause_last_time_recvd; + + struct timer_list link_timer; + int timer_ticks; + enum link_state lstate; + + dma_addr_t gblock_dvma; + struct pci_dev *pdev; + struct net_device *dev; +}; + +#define ALIGNED_RX_SKB_ADDR(addr) \ + ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr)) +static __inline__ struct sk_buff *gem_alloc_skb(int size, int gfp_flags) +{ + struct sk_buff *skb = alloc_skb(size + 64, gfp_flags); + + if (skb) { + int offset = (int) ALIGNED_RX_SKB_ADDR(skb->data); + if (offset) + skb_reserve(skb, offset); + } + + return skb; +} + +#endif /* _SUNGEM_H */ 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/tlan.c linux/drivers/net/tlan.c --- v2.4.2/linux/drivers/net/tlan.c Mon Dec 11 13:38:29 2000 +++ linux/drivers/net/tlan.c Sun Mar 25 18:24:31 2001 @@ -7,10 +7,10 @@ * * (C) 1997-1998 Caldera, Inc. * (C) 1998 James Banks - * (C) 1999, 2000 Torben Mathiasen + * (C) 1999-2001 Torben Mathiasen * * 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. * ** This file is best viewed/edited with columns>=132. * @@ -136,6 +136,28 @@ * * v1.12 Oct 12, 2000 - Minor fixes (memleak, init, etc.) * + * v1.13 Nov 28, 2000 - Stop flooding console with auto-neg issues + * when link can't be established. + * - Added the bbuf option as a kernel parameter. + * - Fixed ioaddr probe bug. + * - Fixed stupid deadlock with MII interrupts. + * - Added support for speed/duplex selection with + * multiple nics. + * - Added partly fix for TX Channel lockup with + * TLAN v1.0 silicon. This needs to be investigated + * further. + * + * v1.14 Dec 16, 2000 - Added support for servicing multiple frames per. + * interrupt. Thanks goes to + * Adam Keys + * Denis Beaudoin + * for providing the patch. + * - Fixed auto-neg output when using multiple + * adapters. + * - Converted to use new taskq interface. + * + * v1.14a Jan 6, 2001 - Minor adjustments (spinlocks, etc.) + * *******************************************************************************/ @@ -159,17 +181,19 @@ static int TLanDevicesInstalled; -/* Force speed, duplex and aui settings */ -static int aui; -static int duplex; -static int speed; +/* Set speed, duplex and aui settings */ +static int aui[MAX_TLAN_BOARDS]; +static int duplex[MAX_TLAN_BOARDS]; +static int speed[MAX_TLAN_BOARDS]; +static int boards_found; MODULE_AUTHOR("Maintainer: Torben Mathiasen "); MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters"); -MODULE_PARM(aui, "i"); -MODULE_PARM(duplex, "i"); -MODULE_PARM(speed, "i"); +MODULE_PARM(aui, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); +MODULE_PARM(duplex, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); +MODULE_PARM(speed, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i"); MODULE_PARM(debug, "i"); +MODULE_PARM(bbuf, "i"); EXPORT_NO_SYMBOLS; /* Define this to enable Link beat monitoring */ @@ -181,7 +205,7 @@ static int bbuf; static u8 *TLanPadBuffer; static char TLanSignature[] = "TLAN"; -static const char *tlan_banner = "ThunderLAN driver v1.12\n"; +static const char *tlan_banner = "ThunderLAN driver v1.14a\n"; static int tlan_have_pci; static int tlan_have_eisa; @@ -323,17 +347,20 @@ static inline void TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); + TLanPrivateInfo *priv = dev->priv; + unsigned long flags = 0; + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); if ( priv->timer.function != NULL && priv->timerType != TLAN_TIMER_ACTIVITY ) { - spin_unlock_irqrestore(&priv->lock, flags); + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); return; } priv->timer.function = &TLan_Timer; - spin_unlock_irqrestore(&priv->lock, flags); + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); priv->timer.data = (unsigned long) dev; priv->timerSetAt = jiffies; @@ -375,8 +402,8 @@ static void __devexit tlan_remove_one( struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + struct net_device *dev = pci_get_drvdata( pdev ); + TLanPrivateInfo *priv = dev->priv; unregister_netdev( dev ); @@ -388,6 +415,7 @@ kfree( dev ); + pci_set_drvdata( pdev, NULL ); } static struct pci_driver tlan_driver = { @@ -404,7 +432,7 @@ printk(KERN_INFO "%s", tlan_banner); TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, - (GFP_KERNEL | GFP_DMA)); + GFP_KERNEL); if (TLanPadBuffer == NULL) { printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n"); @@ -426,18 +454,19 @@ printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n", TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s", tlan_have_pci, tlan_have_eisa); - - return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV); + if (TLanDevicesInstalled == 0) { + kfree(TLanPadBuffer); + return -ENODEV; + } + return 0; } static int __devinit tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent) { - return TLan_probe1( pdev, pci_resource_start(pdev, 0), pdev->irq, - 0, ent); - + return TLan_probe1( pdev, -1, -1, 0, ent); } @@ -468,6 +497,10 @@ TLanPrivateInfo *priv; u8 pci_rev; u16 device_id; + int reg; + + if (pdev && pci_enable_device(pdev)) + return -EIO; dev = init_etherdev(NULL, sizeof(TLanPrivateInfo)); if (dev == NULL) { @@ -477,23 +510,35 @@ SET_MODULE_OWNER(dev); priv = dev->priv; - - dev->base_addr = ioaddr; - dev->irq = irq; - /* Is this a PCI device? */ if (pdev) { + u32 pci_io_base = 0; + priv->adapter = &board_info[ent->driver_data]; - if (pci_enable_device(pdev)) { + + pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev); + + for ( reg= 0; reg <= 5; reg ++ ) { + if (pci_resource_flags(pdev, reg) & IORESOURCE_IO) { + pci_io_base = pci_resource_start(pdev, reg); + TLAN_DBG( TLAN_DEBUG_GNRL, "IO mapping is available at %x.\n", + pci_io_base); + break; + } + } + if (!pci_io_base) { + printk(KERN_ERR "TLAN: No IO mappings available\n"); unregister_netdev(dev); kfree(dev); - return -1; + return -ENODEV; } - pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev); + + dev->base_addr = pci_io_base; + dev->irq = pdev->irq; priv->adapterRev = pci_rev; pci_set_master(pdev); - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); } else { /* EISA card */ /* This is a hack. We need to know which board structure @@ -507,6 +552,8 @@ priv->adapter = &board_info[14]; priv->adapterRev = 10; /* TLAN 1.0 */ } + dev->base_addr = ioaddr; + dev->irq = irq; } /* Kernel parameters */ @@ -522,21 +569,19 @@ } debug = priv->debug = dev->mem_end; } else { - - if ( ( duplex != 1 ) && ( duplex != 2 ) ) - duplex = 0; - - priv->duplex = duplex; - - if ( ( speed != 10 ) && ( speed != 100 ) ) - speed = 0; - - priv->aui = aui; - priv->speed = speed; + priv->aui = aui[boards_found]; + priv->speed = speed[boards_found]; + priv->duplex = duplex[boards_found]; priv->debug = debug; - } + /* This will be used when we get an adapter error from + * within our irq handler */ + INIT_LIST_HEAD(&priv->tlan_tqueue.list); + priv->tlan_tqueue.sync = 0; + priv->tlan_tqueue.routine = (void *)(void*)TLan_tx_timeout; + priv->tlan_tqueue.data = dev; + spin_lock_init(&priv->lock); if (TLan_Init(dev)) { @@ -547,6 +592,7 @@ } else { TLanDevicesInstalled++; + boards_found++; /* pdev is NULL if this is an EISA device */ if (pdev) @@ -576,7 +622,7 @@ while( tlan_have_eisa ) { dev = TLan_Eisa_Devices; - priv = (TLanPrivateInfo *) dev->priv; + priv = dev->priv; if (priv->dmaStorage) { kfree(priv->dmaStorage); } @@ -730,7 +776,7 @@ int i; TLanPrivateInfo *priv; - priv = (TLanPrivateInfo *) dev->priv; + priv = dev->priv; if (!priv->is_eisa) /* EISA devices have already requested IO */ if (!request_region( dev->base_addr, 0x10, TLanSignature )) { @@ -752,6 +798,7 @@ if ( priv->dmaStorage == NULL ) { printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n", dev->name ); + release_region( dev->base_addr, 0x10 ); return -ENOMEM; } memset( priv->dmaStorage, 0, dma_size ); @@ -812,7 +859,7 @@ static int TLan_Open( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int err; priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); @@ -858,7 +905,7 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 *data = (u16 *)&rq->ifr_data; u32 phy = priv->phy[priv->phyNum]; @@ -901,6 +948,7 @@ TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name); /* Ok so we timed out, lets see what we can do about it...*/ + TLan_FreeLists( dev ); TLan_ResetLists( dev ); TLan_ReadAndClearStats( dev, TLAN_IGNORE ); TLan_ResetAdapter( dev ); @@ -934,7 +982,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; TLanList *tail_list; u8 *tail_buffer; int pad; @@ -947,7 +995,7 @@ } tail_list = priv->txList + priv->txTail; - + if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); netif_stop_queue(dev); @@ -983,10 +1031,9 @@ tail_list->cStat = TLAN_CSTAT_READY; if ( ! priv->txInProgress ) { priv->txInProgress = 1; - outw( 0x4, dev->base_addr + TLAN_HOST_INT ); TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); - outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD ); + outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD ); } else { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); if ( priv->txTail == 0 ) { @@ -1040,8 +1087,8 @@ int type; TLanPrivateInfo *priv; - dev = (struct net_device *) dev_id; - priv = (TLanPrivateInfo *) dev->priv; + dev = dev_id; + priv = dev->priv; spin_lock(&priv->lock); @@ -1081,9 +1128,10 @@ static int TLan_Close(struct net_device *dev) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; netif_stop_queue(dev); + priv->neg_be_verbose = 0; TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); @@ -1120,7 +1168,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int i; /* Should only read stats if open ? */ @@ -1242,7 +1290,6 @@ u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int ) { - host_int = 0; /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */ return 0; @@ -1275,33 +1322,36 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int eoc = 0; TLanList *head_list; - u32 ack = 1; - + u32 ack = 0; + u16 tmpCStat; + TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); - host_int = 0; head_list = priv->txList + priv->txHead; - if ( ! bbuf ) { - dev_kfree_skb_irq( (struct sk_buff *) head_list->buffer[9].address ); - head_list->buffer[9].address = 0; - } + while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { + ack++; + if ( ! bbuf ) { + dev_kfree_skb_any( (struct sk_buff *) head_list->buffer[9].address ); + head_list->buffer[9].address = 0; + } + + if ( tmpCStat & TLAN_CSTAT_EOC ) + eoc = 1; + + priv->stats.tx_bytes += head_list->frameSize; - if ( head_list->cStat & TLAN_CSTAT_EOC ) - eoc = 1; - if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { - printk( "TLAN: Received interrupt for uncompleted TX frame.\n" ); + head_list->cStat = TLAN_CSTAT_UNUSED; + netif_start_queue(dev); + CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); + head_list = priv->txList + priv->txHead; } - priv->stats.tx_bytes += head_list->frameSize; - - head_list->cStat = TLAN_CSTAT_UNUSED; + if (!ack) + printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n"); - netif_start_queue(dev); - - CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); if ( eoc ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; @@ -1312,7 +1362,7 @@ priv->txInProgress = 0; } } - + if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) { TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); if ( priv->timer.function == NULL ) { @@ -1353,7 +1403,6 @@ u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int ) { - host_int = 0; TLan_ReadAndClearStats( dev, TLAN_RECORD ); return 1; @@ -1384,87 +1433,95 @@ * of the list. If the frame was the last in the Rx * channel (EOC), the function restarts the receive channel * by sending an Rx Go command to the adapter. Then it - * activates/continues the the activity LED. + * activates/continues the activity LED. * **************************************************************/ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; - u32 ack = 1; + TLanPrivateInfo *priv = dev->priv; + u32 ack = 0; int eoc = 0; u8 *head_buffer; TLanList *head_list; struct sk_buff *skb; TLanList *tail_list; void *t; + u32 frameSize; + u16 tmpCStat; TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); - host_int = 0; head_list = priv->rxList + priv->rxHead; - tail_list = priv->rxList + priv->rxTail; - - if ( head_list->cStat & TLAN_CSTAT_EOC ) { - eoc = 1; - } + + while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { + frameSize = head_list->frameSize; + ack++; + if (tmpCStat & TLAN_CSTAT_EOC) + eoc = 1; + + if (bbuf) { + skb = dev_alloc_skb(frameSize + 7); + if (skb == NULL) + printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n"); + else { + head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE); + skb->dev = dev; + skb_reserve(skb, 2); + t = (void *) skb_put(skb, frameSize); + + priv->stats.rx_bytes += head_list->frameSize; - if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { - printk( "TLAN: Received interrupt for uncompleted RX frame.\n" ); - } else if ( bbuf ) { - skb = dev_alloc_skb( head_list->frameSize + 7 ); - if ( skb == NULL ) { - printk( "TLAN: Couldn't allocate memory for received data.\n" ); + memcpy( t, head_buffer, frameSize ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + } } else { - head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE ); - skb->dev = dev; - skb_reserve( skb, 2 ); - t = (void *) skb_put( skb, head_list->frameSize ); - - priv->stats.rx_bytes += head_list->frameSize; - - memcpy( t, head_buffer, head_list->frameSize ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - } - } else { - struct sk_buff *new_skb; + struct sk_buff *new_skb; - /* - * I changed the algorithm here. What we now do - * is allocate the new frame. If this fails we - * simply recycle the frame. - */ + /* + * I changed the algorithm here. What we now do + * is allocate the new frame. If this fails we + * simply recycle the frame. + */ - new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); - if ( new_skb != NULL ) { - /* If this ever happened it would be a problem */ - /* not any more - ac */ - skb = (struct sk_buff *) head_list->buffer[9].address; - head_list->buffer[9].address = 0; - skb_trim( skb, head_list->frameSize ); + new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); + + if ( new_skb != NULL ) { + /* If this ever happened it would be a problem */ + /* not any more - ac */ + skb = (struct sk_buff *) head_list->buffer[9].address; + skb_trim( skb, frameSize ); + + priv->stats.rx_bytes += frameSize; + + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + + new_skb->dev = dev; + skb_reserve( new_skb, 2 ); + t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); + head_list->buffer[0].address = virt_to_bus( t ); + head_list->buffer[8].address = (u32) t; + head_list->buffer[9].address = (u32) new_skb; + } else + printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); + } + + head_list->forward = 0; + head_list->cStat = 0; + tail_list = priv->rxList + priv->rxTail; + tail_list->forward = virt_to_bus( head_list ); - priv->stats.rx_bytes += head_list->frameSize; + CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS ); + CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); + head_list = priv->rxList + priv->rxHead; + } - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); + if (!ack) + printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n"); - new_skb->dev = dev; - skb_reserve( new_skb, 2 ); - t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); - head_list->buffer[0].address = virt_to_bus( t ); - head_list->buffer[9].address = (u32) new_skb; - } - else - printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); - } - head_list->forward = 0; - head_list->frameSize = TLAN_MAX_FRAME_SIZE; - head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; - tail_list->forward = virt_to_bus( head_list ); - CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS ); - CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS ); if ( eoc ) { TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail ); @@ -1489,7 +1546,7 @@ } dev->last_rx = jiffies; - + return ack; } /* TLan_HandleRxEOF */ @@ -1516,7 +1573,6 @@ u32 TLan_HandleDummy( struct net_device *dev, u16 host_int ) { - host_int = 0; printk( "TLAN: Test interrupt on %s.\n", dev->name ); return 1; @@ -1547,15 +1603,16 @@ u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; TLanList *head_list; - u32 ack = 1; - + u32 ack = 1; + host_int = 0; if ( priv->tlanRev < 0x30 ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail ); head_list = priv->txList + priv->txHead; if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { + netif_stop_queue(dev); outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); ack |= TLAN_HC_GO; } else { @@ -1592,7 +1649,7 @@ u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u32 ack; u32 error; u8 net_sts; @@ -1602,14 +1659,16 @@ ack = 1; if ( host_int & TLAN_HI_IV_MASK ) { + netif_stop_queue( dev ); error = inl( dev->base_addr + TLAN_CH_PARM ); printk( "TLAN: %s: Adaptor Error = 0x%x\n", dev->name, error ); TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); - TLan_FreeLists( dev ); - TLan_ResetLists( dev ); - TLan_ResetAdapter( dev ); - netif_start_queue(dev); + + queue_task(&priv->tlan_tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + netif_wake_queue(dev); ack = 0; } else { TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name ); @@ -1666,11 +1725,10 @@ u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; TLanList *head_list; u32 ack = 1; - host_int = 0; if ( priv->tlanRev < 0x30 ) { TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail ); head_list = priv->rxList + priv->rxHead; @@ -1728,7 +1786,7 @@ void TLan_Timer( unsigned long data ) { struct net_device *dev = (struct net_device *) data; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u32 elapsed; unsigned long flags = 0; @@ -1808,7 +1866,7 @@ void TLan_ResetLists( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int i; TLanList *list; struct sk_buff *skb; @@ -1826,6 +1884,7 @@ } list->buffer[2].count = 0; list->buffer[2].address = 0; + list->buffer[9].address = 0; } priv->rxHead = 0; @@ -1848,6 +1907,7 @@ t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE ); } list->buffer[0].address = virt_to_bus( t ); + list->buffer[8].address = (u32) t; list->buffer[9].address = (u32) skb; } list->buffer[1].count = 0; @@ -1863,7 +1923,7 @@ void TLan_FreeLists( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int i; TLanList *list; struct sk_buff *skb; @@ -1902,7 +1962,7 @@ * io_base Base IO port of the device of * which to print DIO registers. * - * This function prints out all the the internal (DIO) + * This function prints out all the internal (DIO) * registers of a TLAN chip. * **************************************************************/ @@ -1980,7 +2040,7 @@ void TLan_ReadAndClearStats( struct net_device *dev, int record ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u32 tx_good, tx_under; u32 rx_good, rx_over; u32 def_tx, crc, code; @@ -2056,7 +2116,7 @@ void TLan_ResetAdapter( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; int i; u32 addr; u32 data; @@ -2091,8 +2151,8 @@ /* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */ - outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD ); - outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD ); + outl( TLAN_HC_LD_TMR | 0x3f, dev->base_addr + TLAN_HOST_CMD ); + outl( TLAN_HC_LD_THR | 0x9, dev->base_addr + TLAN_HOST_CMD ); /* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */ @@ -2108,6 +2168,7 @@ } TLan_PhyDetect( dev ); data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN; + if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) { data |= TLAN_NET_CFG_BIT; if ( priv->aui == 1 ) { @@ -2119,6 +2180,7 @@ TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 ); } } + if ( priv->phyNum == 0 ) { data |= TLAN_NET_CFG_PHY_EN; } @@ -2138,7 +2200,7 @@ void TLan_FinishReset( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u8 data; u32 phy; u8 sio; @@ -2161,7 +2223,7 @@ data |= TLAN_NET_MASK_MASK7; } TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data ); - TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE ); + TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7 ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 ); TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 ); @@ -2301,7 +2363,7 @@ void TLan_PhyPrint( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 i, data0, data1, data2, data3, phy; phy = priv->phy[priv->phyNum]; @@ -2350,7 +2412,7 @@ void TLan_PhyDetect( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 control; u16 hi; u16 lo; @@ -2397,7 +2459,7 @@ void TLan_PhyPowerDown( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 value; TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name ); @@ -2422,7 +2484,7 @@ void TLan_PhyPowerUp( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 value; TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name ); @@ -2443,7 +2505,7 @@ void TLan_PhyReset( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 phy; u16 value; @@ -2471,7 +2533,7 @@ void TLan_PhyStartLink( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 ability; u16 control; u16 data; @@ -2558,7 +2620,7 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 an_adv; u16 an_lpa; u16 data; @@ -2576,7 +2638,12 @@ /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while. */ - printk( "TLAN: Giving autonegotiation more time.\n" ); + if (!priv->neg_be_verbose++) { + printk(KERN_INFO "TLAN: Giving autonegotiation more time.\n"); + printk(KERN_INFO "TLAN: Please check that your adapter has\n"); + printk(KERN_INFO "TLAN: been properly connected to a HUB or Switch.\n"); + printk(KERN_INFO "TLAN: Trying to establish link in the background...\n"); + } TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN ); return; } @@ -2637,7 +2704,7 @@ void TLan_PhyMonitor( struct net_device *dev ) { - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; u16 phy; u16 phy_status; @@ -2714,14 +2781,15 @@ u32 i; int err; int minten; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; unsigned long flags = 0; err = FALSE; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; - - spin_lock_irqsave(&priv->lock, flags); + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); TLan_MiiSync(dev->base_addr); @@ -2767,8 +2835,9 @@ TLan_SetBit(TLAN_NET_SIO_MINTEN, sio); *val = tmp; - - spin_unlock_irqrestore(&priv->lock, flags); + + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); return err; @@ -2881,12 +2950,13 @@ u16 sio; int minten; unsigned long flags = 0; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; - - spin_lock_irqsave(&priv->lock, flags); + + if (!in_irq()) + spin_lock_irqsave(&priv->lock, flags); TLan_MiiSync( dev->base_addr ); @@ -2907,8 +2977,9 @@ if ( minten ) TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); - - spin_unlock_irqrestore(&priv->lock, flags); + + if (!in_irq()) + spin_unlock_irqrestore(&priv->lock, flags); } /* TLan_MiiWriteReg */ @@ -3106,7 +3177,7 @@ int TLan_EeReadByte( struct net_device *dev, u8 ee_addr, u8 *data ) { int err; - TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanPrivateInfo *priv = dev->priv; unsigned long flags = 0; int ret=0; diff -u --recursive --new-file v2.4.2/linux/drivers/net/tlan.h linux/drivers/net/tlan.h --- v2.4.2/linux/drivers/net/tlan.h Mon Dec 11 13:01:14 2000 +++ linux/drivers/net/tlan.h Tue Mar 20 12:05:00 2001 @@ -8,10 +8,10 @@ * by James Banks * * (C) 1997-1998 Caldera, Inc. - * (C) 1999-2000 Torben Mathiasen + * (C) 1999-2001 Torben Mathiasen * * 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. * ** This file is best viewed/edited with tabstop=4, colums>=132 * @@ -36,11 +36,11 @@ #define FALSE 0 #define TRUE 1 -#define TLAN_MIN_FRAME_SIZE 60 -#define TLAN_MAX_FRAME_SIZE 1536 +#define TLAN_MIN_FRAME_SIZE 64 +#define TLAN_MAX_FRAME_SIZE 1600 -#define TLAN_NUM_RX_LISTS 4 -#define TLAN_NUM_TX_LISTS 8 +#define TLAN_NUM_RX_LISTS 32 +#define TLAN_NUM_TX_LISTS 64 #define TLAN_IGNORE 0 #define TLAN_RECORD 1 @@ -53,7 +53,7 @@ #define TLAN_DEBUG_PROBE 0x0010 #define TX_TIMEOUT (10*HZ) /* We need time for auto-neg */ - +#define MAX_TLAN_BOARDS 8 /* Max number of boards installed at a time */ /***************************************************************** @@ -209,6 +209,8 @@ spinlock_t lock; u8 link; u8 is_eisa; + struct tq_struct tlan_tqueue; + u8 neg_be_verbose; } TLanPrivateInfo; 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/ibmtr.c linux/drivers/net/tokenring/ibmtr.c --- v2.4.2/linux/drivers/net/tokenring/ibmtr.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/ibmtr.c Tue Mar 20 12:05:00 2001 @@ -255,12 +255,16 @@ * * We expect ibmtr_probe to be called once for each device entry * which references it. + * + * Argument 'dev' should never be NULL. If we are built into + * the kernel, Space.c passed up a net_device. If we are + * -DMODULE, init_module allocates net_devices for us. */ int __init ibmtr_probe(struct net_device *dev) { int i; - int base_addr = dev ? dev->base_addr : 0; + int base_addr = dev->base_addr; if (base_addr > 0x1ff) { @@ -301,7 +305,7 @@ #ifndef MODULE #ifndef PCMCIA - dev = init_trdev(dev,0); + dev = init_trdev(dev, 0); #endif #endif @@ -1877,8 +1881,11 @@ mem[i] = 0; dev_ibmtr[i] = NULL; dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0); - if (dev_ibmtr[i] == NULL) - return -ENOMEM; + if (dev_ibmtr[i] == NULL) { + if (i == 0) + return -ENOMEM; + break; + } dev_ibmtr[i]->base_addr = io[i]; dev_ibmtr[i]->irq = irq[i]; diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c --- v2.4.2/linux/drivers/net/tokenring/lanstreamer.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/lanstreamer.c Tue Mar 20 12:04:59 2001 @@ -59,12 +59,10 @@ * 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing * malloc free checks, reviewed code. * 03/13/00 - Added spinlocks for smp + * 03/08/01 - Added support for module_init() and module_exit() * * To Do: * - * 1) Test Network Monitor Mode - * 2) Add auto reset logic on adapter errors - * 3) Test with varying options * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface @@ -123,7 +121,14 @@ * Official releases will only have an a.b.c version number format. */ -static char *version = "LanStreamer.c v0.3.1 03/13/99 - Mike Sullivan"; +static char *version = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan"; + +static struct pci_device_id streamer_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,}, + {} /* terminating entry */ +}; +MODULE_DEVICE_TABLE(pci,streamer_pci_tbl); + static char *open_maj_error[] = { "No error", "Lobe Media Test", "Physical Insertion", @@ -170,8 +175,7 @@ MODULE_PARM(message_level, "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i"); -static int streamer_scan(struct net_device *dev); -static int streamer_init(struct net_device *dev); +static int streamer_reset(struct net_device *dev); static int streamer_open(struct net_device *dev); static int streamer_xmit(struct sk_buff *skb, struct net_device *dev); static int streamer_close(struct net_device *dev); @@ -186,98 +190,190 @@ static void streamer_asb_bh(struct net_device *dev); #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS +static int streamer_proc_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data); static int sprintf_info(char *buffer, struct net_device *dev); +struct streamer_private *dev_streamer=NULL; #endif #endif -int __init streamer_probe(struct net_device *dev) +static int __devinit streamer_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { - int cards_found; - - cards_found = streamer_scan(dev); - return cards_found ? 0 : -ENODEV; -} - -static int __init streamer_scan(struct net_device *dev) -{ - struct pci_dev *pci_device = NULL; + struct net_device *dev=NULL; struct streamer_private *streamer_priv; - int card_no = 0; - if (pci_present()) - { - while ((pci_device = pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, pci_device))) - { - if (pci_enable_device(pci_device)) - continue; - pci_set_master(pci_device); + __u32 pio_start, pio_end, pio_flags, pio_len; + __u32 mmio_start, mmio_end, mmio_flags, mmio_len; + int rc=0; + static int card_no=-1; - /* Check to see if io has been allocated, if so, we've already done this card, - so continue on the card discovery loop */ +#if STREAMER_DEBUG + printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev); +#endif - if (check_region(pci_resource_start(pci_device,0), STREAMER_IO_SPACE)) - { card_no++; - continue; - } - - streamer_priv = kmalloc(sizeof(struct streamer_private), GFP_KERNEL); - if(streamer_priv==NULL) - { + dev=init_trdev(dev, sizeof(*streamer_priv)); + if(dev==NULL) { printk(KERN_ERR "lanstreamer: out of memory.\n"); - break; - } - memset(streamer_priv, 0, sizeof(struct streamer_private)); - init_waitqueue_head(&streamer_priv->srb_wait); - init_waitqueue_head(&streamer_priv->trb_wait); -#ifndef MODULE - dev = init_trdev(dev, 0); - if(dev==NULL) - { - kfree(streamer_priv); - printk(KERN_ERR "lanstreamer: out of memory.\n"); - break; + return -ENOMEM; } SET_MODULE_OWNER(dev); + streamer_priv=dev->priv; + +#if STREAMER_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + if (!dev_streamer) { + create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); + } + streamer_priv->next=dev_streamer; + dev_streamer=streamer_priv; #endif - dev->priv = (void *) streamer_priv; -#if STREAMER_DEBUG - printk("pci_device: %p, dev:%p, dev->priv: %p\n", - pci_device, dev, dev->priv); #endif - dev->irq = pci_device->irq; - dev->base_addr = pci_resource_start(pci_device, 0); - dev->init = &streamer_init; - streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name; - streamer_priv->streamer_mmio = - ioremap(pci_resource_start(pci_device, 1), 256); - - if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) - streamer_priv->pkt_buf_sz = PKT_BUF_SZ; - else - streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no]; - - streamer_priv->streamer_ring_speed = ringspeed[card_no]; - streamer_priv->streamer_message_level = message_level[card_no]; - - if (streamer_init(dev) == -1) { - unregister_netdevice(dev); - kfree(dev->priv); - return 0; + + if (pci_enable_device(pdev)) { + printk(KERN_ERR "lanstreamer: unable to enable pci device\n"); + rc=-EIO; + goto err_out; + } + + pci_set_master(pdev); + + pio_start = pci_resource_start(pdev, 0); + pio_end = pci_resource_end(pdev, 0); + pio_flags = pci_resource_flags(pdev, 0); + pio_len = pci_resource_len(pdev, 0); + + mmio_start = pci_resource_start(pdev, 1); + mmio_end = pci_resource_end(pdev, 1); + mmio_flags = pci_resource_flags(pdev, 1); + mmio_len = pci_resource_len(pdev, 1); + +#if STREAMER_DEBUG + printk("lanstreamer: pio_start %x pio_end %x pio_len %x pio_flags %x\n", + pio_start, pio_end, pio_len, pio_flags); + printk("lanstreamer: mmio_start %x mmio_end %x mmio_len %x mmio_flags %x\n", + mmio_start, mmio_end, mmio_flags, mmio_len); +#endif + + if (!request_region(pio_start, pio_len, "lanstreamer")) { + printk(KERN_ERR "lanstreamer: unable to get pci io addr %x\n",pio_start); + rc= -EBUSY; + goto err_out; + } + + if (!request_mem_region(mmio_start, mmio_len, "lanstreamer")) { + printk(KERN_ERR "lanstreamer: unable to get pci mmio addr %x\n",mmio_start); + rc= -EBUSY; + goto err_out_free_pio; + } + + streamer_priv->streamer_mmio=ioremap(mmio_start, mmio_len); + if (streamer_priv->streamer_mmio == NULL) { + printk(KERN_ERR "lanstreamer: unable to remap MMIO %x\n",mmio_start); + rc= -EIO; + goto err_out_free_mmio; } + init_waitqueue_head(&streamer_priv->srb_wait); + init_waitqueue_head(&streamer_priv->trb_wait); + dev->open = &streamer_open; dev->hard_start_xmit = &streamer_xmit; dev->change_mtu = &streamer_change_mtu; - dev->stop = &streamer_close; dev->do_ioctl = NULL; dev->set_multicast_list = &streamer_set_rx_mode; dev->get_stats = &streamer_get_stats; dev->set_mac_address = &streamer_set_mac_address; - return 1; + dev->irq = pdev->irq; + dev->base_addr=pio_start; + + streamer_priv->streamer_card_name = (char *)pdev->resource[0].name; + streamer_priv->pci_dev=pdev; + + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) + streamer_priv->pkt_buf_sz = PKT_BUF_SZ; + else + streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no]; + + streamer_priv->streamer_ring_speed = ringspeed[card_no]; + streamer_priv->streamer_message_level = message_level[card_no]; + + pdev->driver_data=dev; + + spin_lock_init(&streamer_priv->streamer_lock); + + printk("%s \n", version); + printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, + streamer_priv->streamer_card_name, + (unsigned int) dev->base_addr, + streamer_priv->streamer_mmio, + dev->irq); + + if (!streamer_reset(dev)) { + return 0; + } + + iounmap(streamer_priv->streamer_mmio); +err_out_free_mmio: + release_mem_region(mmio_start, mmio_len); +err_out_free_pio: + release_region(pio_start, pio_len); +err_out: + unregister_trdev(dev); + kfree(dev); +#if STREAMER_DEBUG + printk("lanstreamer: Exit error %x\n",rc); +#endif + return rc; +} + +static void __devexit streamer_remove_one(struct pci_dev *pdev) { + struct net_device *dev=pdev->driver_data; + struct streamer_private *streamer_priv; + +#if STREAMER_DEBUG + printk("lanstreamer::streamer_remove_one entry pdev %p\n",pdev); +#endif + + if (dev == NULL) { + printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev is NULL\n"); + return; } + + streamer_priv=dev->priv; + if (streamer_priv == NULL) { + printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n"); + return; } - return 0; + +#if STREAMER_NETWORK_MONITOR +#ifdef CONFIG_PROC_FS + { + struct streamer_private *slast; + struct streamer_private *scurrent; + if (streamer_priv == dev_streamer) { + dev_streamer=dev_streamer->next; + } else { + for(slast=scurrent=dev_streamer; dev_streamer; slast=scurrent, scurrent=scurrent->next) { + if (scurrent == streamer_priv) { + slast->next=scurrent->next; + break; + } + } + } + if (!dev_streamer) { + remove_proc_entry("net/streamer_tr", NULL); + } + } +#endif +#endif + + unregister_trdev(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)); + kfree(dev); + pdev->driver_data=NULL; } @@ -424,32 +520,6 @@ return 0; } -static int __init streamer_init(struct net_device *dev) -{ - struct streamer_private *streamer_priv; - __u8 *streamer_mmio; - int rc; - - streamer_priv=(struct streamer_private *)dev->priv; - streamer_mmio=streamer_priv->streamer_mmio; - - spin_lock_init(&streamer_priv->streamer_lock); - - printk("%s \n", version); - printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, - streamer_priv->streamer_card_name, - (unsigned int) dev->base_addr, - streamer_priv->streamer_mmio, - dev->irq); - - request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer"); - - rc=streamer_reset(dev); - return rc; -} - - - static int streamer_open(struct net_device *dev) { struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv; @@ -465,7 +535,7 @@ rc=streamer_reset(dev); } - if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "streamer", dev)) { + if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "lanstreamer", dev)) { return -EAGAIN; } #if STREAMER_DEBUG @@ -563,7 +633,7 @@ * timed out. */ writew(srb_open + 2, streamer_mmio + LAPA); - srb_word = ntohs(readw(streamer_mmio + LAPD)) & 0xFF; + srb_word = ntohs(readw(streamer_mmio + LAPD)) >> 8; if (srb_word == STREAMER_CLEAR_RET_CODE) { printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name); @@ -1618,27 +1688,24 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { + struct streamer_private *sdev=NULL; struct pci_dev *pci_device = NULL; int len = 0; off_t begin = 0; off_t pos = 0; int size; - struct device *dev; - + struct net_device *dev; size = sprintf(buffer, "IBM LanStreamer/MPC Chipset Token Ring Adapters\n"); pos += size; len += size; - while ((pci_device = pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, pci_device))) - { + for(sdev=dev_streamer; sdev; sdev=sdev->next) { + pci_device=sdev->pci_dev; + dev=pci_device->driver_data; - for (dev = dev_base; dev != NULL; dev = dev->next) - { - if (dev->base_addr == pci_device->resource[0].start) - { /* Yep, a Streamer device */ size = sprintf_info(buffer + len, dev); len += size; pos = begin + len; @@ -1649,9 +1716,7 @@ } if (pos > offset + length) break; - } /* if */ } /* for */ - } /* While */ *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Start slop */ @@ -1743,66 +1808,34 @@ #endif #endif -#ifdef MODULE - -static struct net_device *dev_streamer[STREAMER_MAX_ADAPTERS]; - -int init_module(void) -{ - int i; - -#if STREAMER_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS - create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); -#endif +static void streamer_suspend(struct pci_dev *pdev) { +#if STREAMER_DEBUG + printk("lanstreamer::streamer_suspend entry pdev %p\n",pdev); #endif - for (i = 0; (i < STREAMER_MAX_ADAPTERS); i++) - { - dev_streamer[i] = NULL; - dev_streamer[i] = init_trdev(dev_streamer[i], 0); - SET_MODULE_OWNER(dev_streamer[i]); - if (dev_streamer[i] == NULL) - return -ENOMEM; - - dev_streamer[i]->init = &streamer_probe; - - if (register_trdev(dev_streamer[i]) != 0) { - kfree(dev_streamer[i]); - dev_streamer[i] = NULL; - if (i == 0) - { - printk(KERN_INFO "Streamer: No IBM LanStreamer PCI Token Ring cards found in system.\n"); - return -EIO; - } else { - printk(KERN_INFO "Streamer: %d IBM LanStreamer PCI Token Ring card(s) found in system.\n", i); - return 0; - } - } - } +} - return 0; +static void streamer_resume(struct pci_dev *pdev) { +#if STREAMER_DEBUG + printk("lanstreamer::streamer_resume entry pdev %p\n",pdev); +#endif } -void cleanup_module(void) -{ - int i; - struct streamer_private *streamer_priv; +static struct pci_driver streamer_pci_driver = { + name: "lanstreamer", + id_table: streamer_pci_tbl, + probe: streamer_init_one, + remove: streamer_remove_one, + suspend: streamer_suspend, + resume: streamer_resume, +}; - for (i = 0; i < STREAMER_MAX_ADAPTERS; i++) - if (dev_streamer[i]) { - unregister_trdev(dev_streamer[i]); - release_region(dev_streamer[i]->base_addr, STREAMER_IO_SPACE); - streamer_priv=(struct streamer_private *)dev_streamer[i]->priv; - kfree(streamer_priv->streamer_rx_ring); - kfree(streamer_priv->streamer_tx_ring); - kfree(dev_streamer[i]->priv); - kfree(dev_streamer[i]); - dev_streamer[i] = NULL; - } -#if STREAMER_NETWORK_MONITOR -#ifdef CONFIG_PROC_FS - remove_proc_entry("net/streamer_tr", NULL); -#endif -#endif +static int __init streamer_init_module(void) { + return pci_module_init(&streamer_pci_driver); } -#endif /* MODULE */ + +static void __exit streamer_cleanup_module(void) { + pci_unregister_driver(&streamer_pci_driver); +} + +module_init(streamer_init_module); +module_exit(streamer_cleanup_module); diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/lanstreamer.h linux/drivers/net/tokenring/lanstreamer.h --- v2.4.2/linux/drivers/net/tokenring/lanstreamer.h Tue Mar 21 14:43:39 2000 +++ linux/drivers/net/tokenring/lanstreamer.h Tue Mar 20 12:04:59 2001 @@ -257,6 +257,8 @@ __u16 arb; __u16 asb; + struct streamer_private *next; + struct pci_dev *pci_dev; __u8 *streamer_mmio; char *streamer_card_name; 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 20 12:05:00 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); @@ -216,7 +215,11 @@ init_waitqueue_head(&olympic_priv->srb_wait); init_waitqueue_head(&olympic_priv->trb_wait); #ifndef MODULE - dev=init_trdev(dev, 0); + dev = init_trdev(NULL, 0); + if (!dev) { + kfree(olympic_priv); + return 0; + } #endif dev->priv=(void *)olympic_priv; #if OLYMPIC_DEBUG @@ -224,8 +227,9 @@ #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 ; + /* FIXME: check ioremap return val, handle cleanup */ olympic_priv->olympic_mmio = ioremap(pci_resource_start(pci_device,1),256); olympic_priv->olympic_lap = @@ -240,8 +244,11 @@ olympic_priv->olympic_message_level = message_level[card_no] ; if(olympic_init(dev)==-1) { - unregister_netdevice(dev); kfree(dev->priv); +#ifndef MODULE + unregister_netdev(dev); + kfree(dev); +#endif return 0; } @@ -288,6 +295,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)); printk("GPR: %x\n",readw(olympic_mmio+GPR)); @@ -1259,6 +1270,11 @@ } #endif mac_frame = dev_alloc_skb(frame_len) ; + if (!mac_frame) { + printk(KERN_WARNING "%s: Memory squeeze, dropping " + "frame.\n", dev->name); + goto drop_frame; + } /* Walk the buffer chain, creating the frame */ @@ -1281,6 +1297,7 @@ netif_rx(mac_frame) ; dev->last_rx = jiffies ; +drop_frame: /* Now tell the card we have dealt with the received frame */ /* Set LISR Bit 1 */ @@ -1633,8 +1650,11 @@ for (i = 0; (iinit = &olympic_probe; 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 20 12:05:00 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); @@ -4546,20 +4546,24 @@ struct sk_buff *skb; skb = dev_alloc_skb(rx_size); - skb_put(skb, rx_size); + if (skb) { + skb_put(skb, rx_size); - memcpy(skb->data, pbuff, rx_size); - sti(); + memcpy(skb->data, pbuff, rx_size); + sti(); - /* Update Counters */ - tp->MacStat.rx_packets++; - tp->MacStat.rx_bytes += skb->len; - - /* Kick the packet on up. */ - skb->dev = dev; - skb->protocol = tr_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; + /* Update Counters */ + tp->MacStat.rx_packets++; + tp->MacStat.rx_bytes += skb->len; + + /* Kick the packet on up. */ + skb->dev = dev; + skb->protocol = tr_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + } else { + sti(); + } } else smctr_process_rx_packet((MAC_HEADER *)pbuff, 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 Sun Mar 25 18:24:31 2001 @@ -2192,17 +2192,18 @@ } } - if(rpl->SkbStat == SKB_DATA_COPY - || rpl->SkbStat == SKB_DMA_DIRECT) + if(skb && (rpl->SkbStat == SKB_DATA_COPY + || rpl->SkbStat == SKB_DMA_DIRECT)) { if(rpl->SkbStat == SKB_DATA_COPY) - memmove(skb->data, ReceiveDataPtr, Length); + memcpy(skb->data, ReceiveDataPtr, Length); /* Deliver frame to system */ rpl->Skb = NULL; 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/tokenring/tmsisa.c linux/drivers/net/tokenring/tmsisa.c --- v2.4.2/linux/drivers/net/tokenring/tmsisa.c Wed Feb 21 18:20:29 2001 +++ linux/drivers/net/tokenring/tmsisa.c Tue Mar 20 12:05:00 2001 @@ -7,7 +7,7 @@ * Dedicated to my girlfriend Steffi Bopp * * 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. * * This driver module supports the following cards: * - SysKonnect TR4/16(+) ISA (SK-4190) 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 Sun Mar 25 18:24:31 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,8 +493,11 @@ 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)) { + if (pci_set_dma_mask(pdev, 0xffffffff)) { printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n"); goto err_out; } @@ -484,84 +509,48 @@ 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); - dev = init_etherdev(NULL, sizeof(*np)); + dev = alloc_etherdev(sizeof(*np)); 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, "via-rhine")) 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); if (!ioaddr) { printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n", - dev->name, io_size, + pdev->slot_name, io_size, pci_resource_start (pdev, 1)); - goto err_out_free_mmio; + goto err_out_free_res; } #endif - printk(KERN_INFO "%s: %s at 0x%lx, ", - dev->name, via_rhine_chip_info[chip_id].name, ioaddr); - /* Ideally we would read the EEPROM but access may be locked. */ for (i = 0; i < 6; i++) 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); /* 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 +577,22 @@ dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - pdev->driver_data = dev; + i = register_netdev(dev); + if (i) + goto err_out_unmap; + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, via_rhine_chip_info[chip_id].name, ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq); + + 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,34 +609,215 @@ netif_carrier_off(dev); } } + np->mii_cnt = phy_idx; } return 0; +err_out_unmap: #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)); + iounmap((void *)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); -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 +840,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 +871,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 +913,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 +940,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 +973,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 */ + /* protect against concurrent rx interrupts */ + disable_irq(np->pdev->irq); - /* Trigger an immediate transmit demand. */ - /* XXX to do */ + spin_lock(&np->lock); - 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. */ - - 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); + /* 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 @@ -972,7 +1066,7 @@ after the Tx thread. */ static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) { - struct net_device *dev = (struct net_device *)dev_instance; + struct net_device *dev = dev_instance; long ioaddr; u32 intr_status; int boguscnt = max_interrupt_work; @@ -1017,7 +1111,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 +1160,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 +1243,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 +1274,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 +1309,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 +1322,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 +1368,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 +1400,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 +1433,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 +1454,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(); - - 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; - } + spin_unlock_irq(&np->lock); - /* 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 +1467,12 @@ static void __devexit via_rhine_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; - struct netdev_private *np = (struct netdev_private *)(dev->priv); + struct net_device *dev = pci_get_drvdata(pdev); + struct netdev_private *np = 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 +1484,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 Tue Mar 20 12:05:01 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. */ @@ -1459,6 +1460,7 @@ skb->pkt_type = PACKET_HOST; netif_rx(skb); + dev->last_rx = jiffies; /* timestamp */ } /* Convert line speed in bps to a number used by cyclom 2x code. */ 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 20 12:05:00 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 General 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 Sun Mar 25 18:24:31 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*/ @@ -1843,6 +1834,7 @@ dev->last_rx = jiffies; sc->stats.rx_packets++; + sc->stats.rx_bytes += len; LMC_CONSOLE_LOG("recv", skb->data, len); @@ -1879,12 +1871,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 +2121,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 +2130,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/sbni.c linux/drivers/net/wan/sbni.c --- v2.4.2/linux/drivers/net/wan/sbni.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/net/wan/sbni.c Tue Mar 20 12:05:01 2001 @@ -283,7 +283,7 @@ struct net_device *dev = neigh->dev; - if (type == __constant_htons(ETH_P_802_3)) + if (type == htons(ETH_P_802_3)) return -1; sbni->h_proto = type; @@ -742,7 +742,7 @@ */ DP( printk("%s: sbni_recv SendComplete\n",dev->name); ); /* - * We sucessfully sent current packet + * We successfully sent current packet */ if(lp->waitack) @@ -1014,6 +1014,8 @@ skb_pull(skb,SBNI_HH_SZ); + skb->dev->last_rx = jiffies; + lp->stats.rx_bytes += skb->len; netif_rx(skb); lp->stats.rx_packets++; } @@ -1148,7 +1150,7 @@ lp->waitack=0; netif_wake_queue(dev); - DP( printk("%s: queue dropping stoped\n",dev->name); ); + DP( printk("%s: queue dropping stopped\n",dev->name); ); } /* 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 Sun Mar 25 18:24:31 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,48 +379,43 @@ 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); - if(!pci_dma_supported(pdev,0xFFFFffff)) { + irq = pdev->irq; + + if (pci_set_dma_mask(pdev,0xFFFFffff)) { printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n", - pdev->name); + pdev->slot_name); return -EIO; } - dev = init_etherdev(NULL, sizeof(*np)); + dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); + if (pci_request_regions(pdev, "winbond-840")) + 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, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - /* Warning: broken for big-endian machines. */ for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, 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 to erase previous misconfiguration. No hold time required! */ writel(0x00000001, ioaddr + PCIBusCfg); @@ -427,12 +424,12 @@ 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) option = dev->mem_start; @@ -461,9 +458,19 @@ dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + i = register_netdev(dev); + if (i) + goto err_out_cleardev; + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + 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; @@ -483,13 +490,14 @@ find_cnt++; return 0; +err_out_cleardev: + pci_set_drvdata(pdev, NULL); #ifndef USE_IO_OPS -err_out_iomem: - release_mem_region(pci_resource_start(pdev, 1), - pci_id_tbl[chip_idx].io_size); + iounmap((void *)ioaddr); +err_out_free_res: #endif + pci_release_regions(pdev); err_out_netdev: - unregister_netdev (dev); kfree (dev); return -ENODEV; } @@ -535,6 +543,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 +621,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 +654,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 +689,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 +711,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 +734,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 +756,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 +787,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 +797,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 +809,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 +841,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 +866,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 +914,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 +931,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 +942,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 +996,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 +1049,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 +1091,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 +1145,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 +1157,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 +1196,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 +1211,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 +1252,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 +1279,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 +1337,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 +1388,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 Sun Mar 25 18:24:31 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,147 @@ 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 = alloc_etherdev(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; + + 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); + } + + /* 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; + + i = register_netdev(dev); + if (i) + goto err_out_cleardev; + + printk(KERN_INFO "%s: %s type %8x at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, inl(ioaddr + ChipRev), ioaddr); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + 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; + +err_out_cleardev: + pci_set_drvdata(pdev, NULL); +#ifndef USE_IO_OPS + iounmap((void *)ioaddr); +err_out_free_res: +#endif + pci_release_regions(pdev); +err_out_free_netdev: + 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 +530,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; } @@ -409,15 +555,15 @@ static int yellowfin_open(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; 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 +571,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; @@ -490,13 +637,13 @@ static void yellowfin_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; int next_tick = 60*HZ; 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 +660,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; @@ -527,13 +674,13 @@ static void yellowfin_tx_timeout(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; long ioaddr = dev->base_addr; 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,19 +700,18 @@ 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. */ static void yellowfin_init_ring(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; int i; yp->tx_full = 0; @@ -637,13 +783,13 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; unsigned entry; 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 +837,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 */ @@ -710,9 +856,10 @@ after the Tx thread. */ static void yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_instance; + struct net_device *dev = 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) { @@ -722,12 +869,12 @@ #endif ioaddr = dev->base_addr; - yp = (struct yellowfin_private *)dev->priv; + yp = dev->priv; 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 +885,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 +893,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 +903,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 +975,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 +988,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,28 +997,19 @@ 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 for clarity and better register allocation. */ static int yellowfin_rx(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = 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 +1038,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 +1048,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 +1085,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 +1123,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); @@ -1012,7 +1146,7 @@ static void yellowfin_error(struct net_device *dev, int intr_status) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", dev->name, intr_status); @@ -1026,35 +1160,36 @@ static int yellowfin_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; int i; 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 +1198,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,12 +1241,13 @@ dev->name, bogus_rx); } #endif + return 0; } static struct net_device_stats *yellowfin_get_stats(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = dev->priv; return &yp->stats; } @@ -1141,19 +1278,19 @@ static void set_rx_mode(struct net_device *dev) { - struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv; + struct yellowfin_private *yp = 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 +1300,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 +1313,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 = 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 +1338,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 +1370,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 +1392,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 +1407,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/ChangeLog linux/drivers/parport/ChangeLog --- v2.4.2/linux/drivers/parport/ChangeLog Thu Jan 4 14:37:05 2001 +++ linux/drivers/parport/ChangeLog Sun Mar 25 18:22:01 2001 @@ -1,3 +1,22 @@ +2001-03-02 Tim Waugh + + * ieee1284_ops.c (parport_ieee1284_read_nibble): Reset nAutoFd + on timeout. Matches 2.2.x behaviour. + +2001-03-02 Andrew Morton + + * parport_pc.c (registered_parport): New static variable. + (parport_pc_find_ports): Set it when we register PCI driver. + (init_module): Unregister PCI driver if necessary when we + fail. + +2001-03-02 Tim Waugh + + * ieee1284_ops.c (parport_ieee1284_write_compat): Don't use + down_trylock to reset the IRQ count. Don't even use sema_init, + because it's not even necessary to reset the count. I can't + remember why we ever did. + 2001-01-04 Peter Osterlund * ieee1284.c (parport_negotiate): Fix missing printk argument. 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 Mon Mar 26 15:41:19 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, @@ -1690,11 +1691,6 @@ config & 0x80 ? "Level" : "Pulses"); configb = inb (CONFIGB (pb)); - if (!(configb & 0x40)) { - printk (KERN_WARNING "0x%lx: possible IRQ conflict!\n", - pb->base); - pb->irq = PARPORT_IRQ_NONE; - } printk (KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n", pb->base, config, configb); printk (KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); @@ -2605,8 +2601,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 +2665,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 +2690,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/parport/share.c linux/drivers/parport/share.c --- v2.4.2/linux/drivers/parport/share.c Wed Feb 21 18:20:30 2001 +++ linux/drivers/parport/share.c Mon Mar 26 15:41:19 2001 @@ -810,6 +810,10 @@ struct parport *parport_find_number (int number) { struct parport *port, *result = NULL; + + if (!portlist) + get_lowlevel_driver (); + spin_lock (&parportlist_lock); for (port = portlist; port; port = port->next) if (port->number == number) { @@ -835,6 +839,10 @@ struct parport *parport_find_base (unsigned long base) { struct parport *port, *result = NULL; + + if (!portlist) + get_lowlevel_driver (); + spin_lock (&parportlist_lock); for (port = portlist; port; port = port->next) if (port->base == base) { 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 Sun Mar 25 18:14:20 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 @@ -1182,10 +1183,17 @@ 0001 EBUS 1000 EBUS 1001 Happy Meal + 1100 RIO EBUS + 1101 RIO GEM + 1102 RIO 1394 + 1103 RIO USB + 2bad GEM 5000 Simba Advanced PCI Bridge 5043 SunPCI Co-processor - 8000 PCI Bus Module + 8000 Psycho PCI Bus Module + 8001 Schizo PCI Bus Module a000 Ultra IIi + a001 Ultra IIe 108f Systemsoft 1090 Encore Computer Corporation 1091 Intergraph Corporation @@ -1259,7 +1267,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 +3944,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 +4262,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/Makefile linux/drivers/pcmcia/Makefile --- v2.4.2/linux/drivers/pcmcia/Makefile Wed Feb 21 18:20:30 2001 +++ linux/drivers/pcmcia/Makefile Mon Mar 26 15:36:30 2001 @@ -12,7 +12,7 @@ export-objs := ds.o cs.o cb_enabler.o yenta.o pci_socket.o -multi-list = pcmcia_core.o yenta_socket.o +list-multi := pcmcia_core.o yenta_socket.o yenta_socket-objs := pci_socket.o yenta.o pcmcia_core-objs := cistpl.o rsrc_mgr.o bulkmem.o cs.o 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/pnp/Makefile linux/drivers/pnp/Makefile --- v2.4.2/linux/drivers/pnp/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/pnp/Makefile Mon Mar 26 15:36:30 2001 @@ -11,7 +11,7 @@ O_TARGET := pnp.o export-objs := isapnp.o -multi-objs := isa-pnp.o +list-multi := isa-pnp.o proc-$(CONFIG_PROC_FS) = isapnp_proc.o isa-pnp-objs := isapnp.o quirks.o $(proc-y) 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/Makefile linux/drivers/sbus/Makefile --- v2.4.2/linux/drivers/sbus/Makefile Fri Dec 29 14:07:22 2000 +++ linux/drivers/sbus/Makefile Sun Mar 25 18:14:20 2001 @@ -18,6 +18,10 @@ subdir-y += audio subdir-m += audio -obj-$(CONFIG_SPARCAUDIO) += audio/sparcaudio.o + +# This is grotty but works around some problems with modules. +ifeq ($(CONFIG_SPARCAUDIO),y) +obj-y += audio/sparcaudio.o +endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.4.2/linux/drivers/sbus/audio/cs4231.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/audio/cs4231.c Sun Mar 25 18:14:20 2001 @@ -1,4 +1,4 @@ -/* $Id: cs4231.c,v 1.44 2001/02/13 01:16:59 davem Exp $ +/* $Id: cs4231.c,v 1.45 2001/03/23 08:16:13 davem Exp $ * drivers/sbus/audio/cs4231.c * * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu) @@ -2348,6 +2348,25 @@ } #endif +#ifdef EB4231_SUPPORT +static int __init ebus_cs4231_p(struct linux_ebus_device *edev) +{ + if (!strcmp(edev->prom_name, "SUNW,CS4231")) + return 1; + if (!strcmp(edev->prom_name, "audio")) { + char compat[16]; + + prom_getstring(edev->prom_node, "compatible", + compat, sizeof(compat)); + compat[15] = '\0'; + if (!strcmp(compat, "SUNW,CS4231")) + return 1; + } + + return 0; +} +#endif + /* Probe for the cs4231 chip and then attach the driver. */ #ifdef MODULE int init_module(void) @@ -2379,7 +2398,7 @@ #ifdef EB4231_SUPPORT for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "SUNW,CS4231")) { + if (ebus_cs4231_p(edev)) { /* Don't go over the max number of drivers. */ if (num_drivers >= MAX_DRIVERS) continue; diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile --- v2.4.2/linux/drivers/sbus/char/Makefile Sat Feb 3 19:51:29 2001 +++ linux/drivers/sbus/char/Makefile Sun Mar 25 18:14:20 2001 @@ -20,6 +20,7 @@ obj-$(CONFIG_ENVCTRL) += envctrl.o obj-$(CONFIG_DISPLAY7SEG) += display7seg.o obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwatchdog.o +obj-$(CONFIG_WATCHDOG_RIO) += riowatchdog.o obj-$(CONFIG_OBP_FLASH) += flash.o obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o 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 Sun Mar 25 18:14:20 2001 @@ -1,4 +1,4 @@ -/* $Id: aurora.c,v 1.10 2000/12/07 04:35:38 anton Exp $ +/* $Id: aurora.c,v 1.11 2001/03/08 01:43:30 davem Exp $ * linux/drivers/sbus/char/aurora.c -- Aurora multiport driver * * Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro) @@ -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/cpwatchdog.c linux/drivers/sbus/char/cpwatchdog.c --- v2.4.2/linux/drivers/sbus/char/cpwatchdog.c Sat Feb 3 19:51:29 2001 +++ linux/drivers/sbus/char/cpwatchdog.c Sun Mar 25 18:14:20 2001 @@ -173,7 +173,7 @@ 0, SPIN_LOCK_UNLOCKED, 0, 0, 0, 0, }; -struct timer_list wd_timer; +static struct timer_list wd_timer; static int wd0_timeout = 0; static int wd1_timeout = 0; @@ -199,20 +199,20 @@ /* Forward declarations of internal methods */ -void wd_dumpregs(void); -void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs); -void wd_toggleintr(struct wd_timer* pTimer, int enable); -void wd_pingtimer(struct wd_timer* pTimer); -void wd_starttimer(struct wd_timer* pTimer); -void wd_resetbrokentimer(struct wd_timer* pTimer); -void wd_stoptimer(struct wd_timer* pTimer); -void wd_brokentimer(unsigned long data); -int wd_getstatus(struct wd_timer* pTimer); +static void wd_dumpregs(void); +static void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void wd_toggleintr(struct wd_timer* pTimer, int enable); +static void wd_pingtimer(struct wd_timer* pTimer); +static void wd_starttimer(struct wd_timer* pTimer); +static void wd_resetbrokentimer(struct wd_timer* pTimer); +static void wd_stoptimer(struct wd_timer* pTimer); +static void wd_brokentimer(unsigned long data); +static int wd_getstatus(struct wd_timer* pTimer); /* PLD expects words to be written in LSB format, * so we must flip all words prior to writing them to regs */ -inline unsigned short flip_word(unsigned short word) +static inline unsigned short flip_word(unsigned short word) { return ((word & 0xff) << 8) | ((word >> 8) & 0xff); } @@ -355,10 +355,15 @@ case WDIOC_GETSUPPORT: if(copy_to_user((struct watchdog_info *)arg, (struct watchdog_info *)&info, - sizeof(struct watchdog_info *))) { + sizeof(struct watchdog_info))) { return(-EFAULT); } break; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(0, (int *) arg)) + return -EFAULT; + break; case WDIOC_KEEPALIVE: wd_pingtimer(pTimer); break; @@ -417,8 +422,14 @@ return(-EINVAL); } - wd_pingtimer(pTimer); - return(count); + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + wd_pingtimer(pTimer); + return 1; + } + return 0; } static ssize_t wd_read(struct file * file, char * buffer, @@ -432,7 +443,7 @@ #endif /* ifdef WD_DEBUG */ } -void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { /* Only WD0 will interrupt-- others are NMI and we won't * see them here.... @@ -460,7 +471,7 @@ static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops }; static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops }; -void wd_dumpregs(void) +static void wd_dumpregs(void) { /* Reading from downcounters initiates watchdog countdown-- * Example is included below for illustration purposes. @@ -504,7 +515,7 @@ * pTimer - pointer to timer device, or NULL to indicate all timers * enable - non-zero to enable interrupts, zero to disable */ -void wd_toggleintr(struct wd_timer* pTimer, int enable) +static void wd_toggleintr(struct wd_timer* pTimer, int enable) { unsigned char curregs = wd_readb(&wd_dev.regs->pld_regs.intr_mask); unsigned char setregs = @@ -525,7 +536,7 @@ * * pTimer - pointer to timer device */ -void wd_pingtimer(struct wd_timer* pTimer) +static void wd_pingtimer(struct wd_timer* pTimer) { if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { wd_readb(&pTimer->regs->dcntr); @@ -538,7 +549,7 @@ * * pTimer - pointer to timer device */ -void wd_stoptimer(struct wd_timer* pTimer) +static void wd_stoptimer(struct wd_timer* pTimer) { if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { wd_toggleintr(pTimer, WD_INTR_OFF); @@ -560,7 +571,7 @@ * pTimer - pointer to timer device * limit - limit (countdown) value in 1/10th seconds */ -void wd_starttimer(struct wd_timer* pTimer) +static void wd_starttimer(struct wd_timer* pTimer) { if(wd_dev.isbaddoggie) { pTimer->runstatus &= ~WD_STAT_BSTOP; @@ -574,7 +585,7 @@ /* Restarts timer with maximum limit value and * does not unset 'brokenstop' value. */ -void wd_resetbrokentimer(struct wd_timer* pTimer) +static void wd_resetbrokentimer(struct wd_timer* pTimer) { wd_toggleintr(pTimer, WD_INTR_ON); wd_writew(WD_BLIMIT, &pTimer->regs->limit); @@ -583,7 +594,7 @@ /* Timer device initialization helper. * Returns 0 on success, other on failure */ -int wd_inittimer(int whichdog) +static int wd_inittimer(int whichdog) { struct miscdevice *whichmisc; volatile struct wd_timer_regblk *whichregs; @@ -650,7 +661,7 @@ * interrupts within the PLD so me must continually * reset the timers ad infinitum. */ -void wd_brokentimer(unsigned long data) +static void wd_brokentimer(unsigned long data) { struct wd_device* pDev = (struct wd_device*)data; int id, tripped = 0; @@ -676,7 +687,7 @@ } } -int wd_getstatus(struct wd_timer* pTimer) +static int wd_getstatus(struct wd_timer* pTimer) { unsigned char stat = wd_readb(&pTimer->regs->status); unsigned char intr = wd_readb(&wd_dev.regs->pld_regs.intr_mask); diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c --- v2.4.2/linux/drivers/sbus/char/envctrl.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/char/envctrl.c Mon Mar 26 15:43:01 2001 @@ -1,4 +1,4 @@ -/* $Id: envctrl.c,v 1.21 2001/02/13 04:07:38 davem Exp $ +/* $Id: envctrl.c,v 1.22 2001/03/25 09:12:15 davem Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -983,6 +983,17 @@ struct linux_ebus_device *edev = NULL; struct linux_ebus_child *edev_child = NULL; int i = 0; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "bbc")) { + /* If we find a boot-bus controller node, + * then this envctrl driver is not for us. + */ + return -ENODEV; + } + } + } /* Traverse through ebus and ebus device list for i2c device and * adc and gpio nodes. 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/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.4.2/linux/drivers/sbus/char/pcikbd.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/char/pcikbd.c Sun Mar 25 18:14:20 2001 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.51 2001/02/13 01:17:00 davem Exp $ +/* $Id: pcikbd.c,v 1.53 2001/03/21 00:28:33 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -369,9 +369,10 @@ void pcikbd_leds(unsigned char leds) { - if(!send_data(KBD_CMD_SET_LEDS) || !send_data(leds)) + if (!pcikbd_iobase) + return; + if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds)) send_data(KBD_CMD_ENABLE); - } static int __init pcikbd_wait_for_input(void) @@ -414,7 +415,10 @@ /* Timer routine to turn off the beep after the interval expires. */ static void pcikbd_kd_nosound(unsigned long __unused) { - outl(0, pcibeep_iobase); + if (pcibeep_iobase & 0x2UL) + outb(0, pcibeep_iobase); + else + outl(0, pcibeep_iobase); } /* @@ -431,13 +435,20 @@ save_flags(flags); cli(); del_timer(&sound_timer); if (hz) { - outl(1, pcibeep_iobase); + if (pcibeep_iobase & 0x2UL) + outb(1, pcibeep_iobase); + else + outl(1, pcibeep_iobase); if (ticks) { sound_timer.expires = jiffies + ticks; add_timer(&sound_timer); } - } else - outl(0, pcibeep_iobase); + } else { + if (pcibeep_iobase & 0x2UL) + outb(0, pcibeep_iobase); + else + outl(0, pcibeep_iobase); + } restore_flags(flags); } #endif @@ -523,6 +534,25 @@ } } } +#ifdef CONFIG_USB + /* We are being called for the sake of USB keyboard + * state initialization. So we should check for beeper + * device in this case. + */ + edev = 0; + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "beep")) { + pcibeep_iobase = edev->resource[0].start; + kd_mksound = pcikbd_kd_mksound; + printk("8042(speaker): iobase[%016lx]\n", pcibeep_iobase); + return; + } + } + } + + /* No beeper found, ok complain. */ +#endif printk("pcikbd_init_hw: no 8042 found\n"); return; diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/riowatchdog.c linux/drivers/sbus/char/riowatchdog.c --- v2.4.2/linux/drivers/sbus/char/riowatchdog.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sbus/char/riowatchdog.c Sun Mar 25 18:14:20 2001 @@ -0,0 +1,275 @@ +/* $Id: riowatchdog.c,v 1.1 2001/03/24 06:04:24 davem Exp $ + * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO + * + * Copyright (C) 2001 David S. Miller (davem@redhat.com) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/* RIO uses the NatSemi Super I/O power management logical device + * as its' watchdog. + * + * When the watchdog triggers, it asserts a line to the BBC (Boot Bus + * Controller) of the machine. The BBC can be configured to treat the + * assertion of this signal in different ways. It can trigger an XIR + * (external CPU reset) to all the processors or it can trigger a true + * power-on reset which triggers the RST signal of all devices in the machine. + * + * The only Super I/O device register we care about is at index + * 0x05 (WDTO_INDEX) which is the watchdog time-out in minutes (1-255). + * If set to zero, this disables the watchdog. When set, the system + * must periodically (before watchdog expires) clear (set to zero) and + * re-set the watchdog else it will trigger. + * + * There are two other indexed watchdog registers inside this Super I/O + * logical device, but they are unused. The first, at index 0x06 is + * the watchdog control and can be used to make the watchdog timer re-set + * when the PS/2 mouse or serial lines show activity. The second, at + * index 0x07 is merely a sampling of the line from the watchdog to the + * BBC. + * + * The watchdog device generates no interrupts. + */ + +MODULE_AUTHOR("David S. Miller "); +MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO"); +MODULE_SUPPORTED_DEVICE("watchdog"); + +#define RIOWD_NAME "pmc" +#define RIOWD_MINOR 215 + +static spinlock_t riowd_lock = SPIN_LOCK_UNLOCKED; + +static void *riowd_regs; +#define WDTO_INDEX 0x05 + +static int riowd_timeout = 1; /* in minutes */ +static int riowd_xir = 1; /* watchdog generates XIR? */ +MODULE_PARM(riowd_timeout,"i"); +MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes"); +MODULE_PARM(riowd_xir,"i"); +MODULE_PARM_DESC(riowd_xir, "Watchdog generates XIR reset if non-zero"); + +#if 0 /* Currently unused. */ +static u8 riowd_readreg(int index) +{ + unsigned long flags; + u8 ret; + + spin_lock_irqsave(&riowd_lock, flags); + writeb(index, riowd_regs + 0); + ret = readb(riowd_regs + 1); + spin_unlock_irqrestore(&riowd_lock, flags); + + return ret; +} +#endif + +static void riowd_writereg(u8 val, int index) +{ + unsigned long flags; + + spin_lock_irqsave(&riowd_lock, flags); + writeb(index, riowd_regs + 0); + writeb(val, riowd_regs + 1); + spin_unlock_irqrestore(&riowd_lock, flags); +} + +static void riowd_pingtimer(void) +{ + riowd_writereg(riowd_timeout, WDTO_INDEX); +} + +static void riowd_stoptimer(void) +{ + riowd_writereg(0, WDTO_INDEX); +} + +static void riowd_starttimer(void) +{ + riowd_writereg(riowd_timeout, WDTO_INDEX); +} + +static int riowd_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int riowd_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int riowd_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info info = { 0, 0, "Natl. Semiconductor PC97317" }; + unsigned int options; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *) arg, &info, sizeof(info))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(0, (int *) arg)) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + riowd_pingtimer(); + break; + + case WDIOC_SETOPTIONS: + if (copy_from_user(&options, (void *) arg, sizeof(options))) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) + riowd_stoptimer(); + else if (options & WDIOS_ENABLECARD) + riowd_starttimer(); + else + return -EINVAL; + + break; + + default: + return -EINVAL; + }; + + return 0; +} + +static ssize_t riowd_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + riowd_pingtimer(); + return 1; + } + + return 0; +} + +static ssize_t riowd_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static struct file_operations riowd_fops = { + owner: THIS_MODULE, + ioctl: riowd_ioctl, + open: riowd_open, + write: riowd_write, + read: riowd_read, + release: riowd_release, +}; + +static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops }; + +static int __init riowd_bbc_init(void) +{ + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + void *bbc_regs; + u8 val; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "bbc")) + goto found_bbc; + } + } + +found_bbc: + if (!edev) + return -ENODEV; + bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE); + if (!bbc_regs) + return -ENODEV; + + val = readb(bbc_regs + BBC_WDACTION); + if (riowd_xir != 0) + val &= ~BBC_WDACTION_RST; + else + val |= BBC_WDACTION_RST; + writeb(val, bbc_regs + BBC_WDACTION); + + iounmap(bbc_regs); + return 0; +} + +static int __init riowd_init(void) +{ + struct linux_ebus *ebus = NULL; + struct linux_ebus_device *edev = NULL; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, RIOWD_NAME)) + goto ebus_done; + } + } + +ebus_done: + if (!edev) + goto fail; + + riowd_regs = ioremap(edev->resource[0].start, 2); + if (riowd_regs == NULL) { + printk(KERN_ERR "pmc: Cannot map registers.\n"); + return -ENODEV; + } + + if (riowd_bbc_init()) { + printk(KERN_ERR "pmc: Failure initializing BBC config.\n"); + goto fail; + } + + if (misc_register(&riowd_miscdev)) { + printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n"); + goto fail; + } + + printk(KERN_INFO "pmc: Hardware watchdog [%i minutes, %s reset], " + "regs at %p\n", + riowd_timeout, (riowd_xir ? "XIR" : "POR"), + riowd_regs); + + return 0; + +fail: + if (riowd_regs) { + iounmap(riowd_regs); + riowd_regs = NULL; + } + return -ENODEV; +} + +static void __exit riowd_cleanup(void) +{ + misc_deregister(&riowd_miscdev); + iounmap(riowd_regs); + riowd_regs = NULL; +} + +module_init(riowd_init); +module_exit(riowd_cleanup); diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c --- v2.4.2/linux/drivers/sbus/char/rtc.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/char/rtc.c Sun Mar 25 18:14:20 2001 @@ -1,4 +1,4 @@ -/* $Id: rtc.c,v 1.25 2001/02/13 01:17:00 davem Exp $ +/* $Id: rtc.c,v 1.26 2001/03/14 09:30:31 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) @@ -157,11 +157,11 @@ { int error; - if (mstk48t02_regs == 0) { - /* This diagnostic is a debugging aid... But a useful one. */ - printk(KERN_ERR "rtc: no Mostek in this computer\n"); + /* It is possible we are being driven by some other RTC chip + * and thus another RTC driver is handling things. + */ + if (mstk48t02_regs == 0) return -ENODEV; - } error = misc_register(&rtc_dev); if (error) { diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c --- v2.4.2/linux/drivers/sbus/char/sab82532.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/char/sab82532.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.55 2001/02/13 01:17:00 davem Exp $ +/* $Id: sab82532.c,v 1.56 2001/03/15 02:11:10 davem Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -2084,6 +2084,23 @@ for_each_ebusdev(edev, ebus) { if (!strcmp(edev->prom_name, "se")) goto ebus_done; + + if (!strcmp(edev->prom_name, "serial")) { + char compat[32]; + int clen; + + /* On RIO this can be an SE, check it. We could + * just check ebus->is_rio, but this is more portable. + */ + clen = prom_getproperty(edev->prom_node, "compatible", + compat, sizeof(compat)); + if (clen > 0) { + if (strncmp(compat, "sab82532", 8) == 0) { + /* Yep. */ + goto ebus_done; + } + } + } } } ebus_done: @@ -2134,7 +2151,7 @@ static inline void __init show_serial_version(void) { - char *revision = "$Revision: 1.55 $"; + char *revision = "$Revision: 1.56 $"; char *version, *p; version = strchr(revision, ' '); @@ -2316,10 +2333,25 @@ * For each EBus on this PCI... */ while (enode) { - snode = prom_getchild(enode); - snode = prom_searchsiblings(snode, "se"); + int child; + + child = prom_getchild(enode); + snode = prom_searchsiblings(child, "se"); if (snode) goto found; + + snode = prom_searchsiblings(child, "serial"); + if (snode) { + char compat[32]; + int clen; + + clen = prom_getproperty(snode, "compatible", + compat, sizeof(compat)); + if (clen > 0) { + if (strncmp(compat, "sab82532", 8) == 0) + goto found; + } + } enode = prom_getsibling(enode); enode = prom_searchsiblings(enode, "ebus"); diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.4.2/linux/drivers/sbus/char/su.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/char/su.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: su.c,v 1.44 2001/02/13 01:17:00 davem Exp $ +/* $Id: su.c,v 1.45 2001/03/15 02:11:10 davem Exp $ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -352,16 +352,16 @@ do { ch = serial_inp(info, UART_RX); if (info->port_type == SU_PORT_KBD) { - if(ch == SUNKBD_RESET) { + if (ch == SUNKBD_RESET) { l1a_state.kbd_id = 1; l1a_state.l1_down = 0; - } else if(l1a_state.kbd_id) { + } else if (l1a_state.kbd_id) { l1a_state.kbd_id = 0; - } else if(ch == SUNKBD_L1) { + } else if (ch == SUNKBD_L1) { l1a_state.l1_down = 1; - } else if(ch == (SUNKBD_L1|SUNKBD_UP)) { + } else if (ch == (SUNKBD_L1|SUNKBD_UP)) { l1a_state.l1_down = 0; - } else if(ch == SUNKBD_A && l1a_state.l1_down) { + } else if (ch == SUNKBD_A && l1a_state.l1_down) { /* whee... */ batten_down_hatches(); /* Continue execution... */ @@ -1166,7 +1166,7 @@ return; info->cflag &= ~(CBAUDEX | CBAUD); - switch(baud) { + switch (baud) { case 1200: info->cflag |= B1200; break; @@ -2220,7 +2220,7 @@ */ static __inline__ void __init show_su_version(void) { - char *revision = "$Revision: 1.44 $"; + char *revision = "$Revision: 1.45 $"; char *version, *p; version = strchr(revision, ' '); @@ -2578,6 +2578,30 @@ return 0; } +static int su_node_ok(int node, char *name, int namelen) +{ + if (strncmp(name, "su", namelen) == 0 || + strncmp(name, "su_pnp", namelen) == 0) + return 1; + + if (strncmp(name, "serial", namelen) == 0) { + char compat[32]; + int clen; + + /* Is it _really_ a 'su' device? */ + clen = prom_getproperty(node, "compatible", compat, sizeof(compat)); + if (clen > 0) { + if (strncmp(compat, "sab82532", 8) == 0) { + /* Nope, Siemens serial, not for us. */ + return 0; + } + } + return 1; + } + + return 0; +} + /* * We got several platforms which present 'su' in different parts * of device tree. 'su' may be found under obio, ebus, isa and pci. @@ -2593,9 +2617,7 @@ for (; sunode != 0; sunode = prom_getsibling(sunode)) { len = prom_getproperty(sunode, "name", t->prop, SU_PROPSIZE); if (len <= 1) continue; /* Broken PROM node */ - if (strncmp(t->prop, "su", len) == 0 || - strncmp(t->prop, "serial", len) == 0 || - strncmp(t->prop, "su_pnp", len) == 0) { + if (su_node_ok(sunode, t->prop, len)) { info = &su_table[t->devices]; if (t->kbnode != 0 && sunode == t->kbnode) { t->kbx = t->devices; @@ -2844,7 +2866,7 @@ if (options) { baud = simple_strtoul(options, NULL, 10); s = options; - while(*s >= '0' && *s <= '9') + while (*s >= '0' && *s <= '9') s++; if (*s) parity = *s++; if (*s) bits = *s - '0'; @@ -2853,7 +2875,7 @@ /* * Now construct a cflag setting. */ - switch(baud) { + switch (baud) { case 1200: cflag |= B1200; break; @@ -2880,7 +2902,7 @@ cflag |= B9600; break; } - switch(bits) { + switch (bits) { case 7: cflag |= CS7; break; @@ -2889,7 +2911,7 @@ cflag |= CS8; break; } - switch(parity) { + switch (parity) { case 'o': case 'O': cflag |= PARODD; break; diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.4.2/linux/drivers/sbus/char/sunserial.c Tue Mar 21 23:38:25 2000 +++ linux/drivers/sbus/char/sunserial.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.75 2000/03/22 02:45:36 davem Exp $ +/* $Id: sunserial.c,v 1.78 2001/03/21 22:43:11 davem Exp $ * serial.c: Serial port driver infrastructure for the Sparc. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -54,21 +54,23 @@ nop_rs_read_proc }; -int rs_init(void) +void rs_init(void) { - struct initfunc *init; - int err = -ENODEV; + static int invoked = 0; - init = rs_ops.rs_init; - while (init) { - err = init->init(); - init = init->next; + if (!invoked) { + struct initfunc *init; + + invoked = 1; + + init = rs_ops.rs_init; + while (init) { + (void) init->init(); + init = init->next; + } } - return err; } -__initcall(rs_init); - void __init rs_kgdb_hook(int channel) { rs_ops.rs_kgdb_hook(channel); @@ -137,6 +139,15 @@ nop_getkeycode }; +#ifdef CONFIG_USB +extern void pci_compute_shiftstate(void); +extern int pci_setkeycode(unsigned int, unsigned int); +extern int pci_getkeycode(unsigned int); +extern void pci_setledstate(struct kbd_struct *, unsigned int); +extern unsigned char pci_getledstate(void); +extern int pcikbd_init(void); +#endif + int kbd_init(void) { struct initfunc *init; @@ -147,6 +158,18 @@ err = init->init(); init = init->next; } +#ifdef CONFIG_USB + if (!serial_console && + kbd_ops.compute_shiftstate == nop_compute_shiftstate) { + printk("kbd_init: Assuming USB keyboard.\n"); + kbd_ops.compute_shiftstate = pci_compute_shiftstate; + kbd_ops.setledstate = pci_setledstate; + kbd_ops.getledstate = pci_getledstate; + kbd_ops.setkeycode = pci_setkeycode; + kbd_ops.getkeycode = pci_getkeycode; + pcikbd_init(); + } +#endif return err; } 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/sbus/sbus.c linux/drivers/sbus/sbus.c --- v2.4.2/linux/drivers/sbus/sbus.c Wed Feb 21 18:20:31 2001 +++ linux/drivers/sbus/sbus.c Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.94 2001/02/13 07:34:40 davem Exp $ +/* $Id: sbus.c,v 1.95 2001/03/15 02:11:10 davem Exp $ * sbus.c: SBus support routines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -280,6 +280,8 @@ } extern void register_proc_sparc_ioport(void); +extern void firetruck_init(void); +extern void rs_init(void); void __init sbus_init(void) { @@ -310,7 +312,6 @@ prom_halt(); } else { #ifdef __sparc_v9__ - extern void firetruck_init(void); firetruck_init(); #endif } @@ -488,10 +489,10 @@ sun4d_init_sbi_irq(); } + rs_init(); + #ifdef __sparc_v9__ if (sparc_cpu_model == sun4u) { - extern void firetruck_init(void); - firetruck_init(); } #endif 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 Mon Mar 26 15:36:30 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 @@ -24,7 +26,6 @@ endif export-objs := scsi_syms.o -list-multi := scsi_mod.o initio.o a100u2w.o CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS @@ -63,7 +64,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,20 +113,25 @@ 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 - - +list-multi := scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.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 \ scsi_merge.o scsi_dma.o scsi_scan.o \ scsi_syms.o - +sd_mod-objs := sd.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o a100u2w-objs := inia100.o i60uscsi.o @@ -136,8 +142,8 @@ scsi_mod.o: $(scsi_mod-objs) $(LD) -r -o $@ $(scsi_mod-objs) -sd_mod.o: sd.o - $(LD) -r -o $@ sd.o +sd_mod.o: $(sd_mod-objs) + $(LD) -r -o $@ $(sd_mod-objs) sr_mod.o: $(sr_mod-objs) $(LD) -r -o $@ $(sr_mod-objs) @@ -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 Sun Mar 25 18:24:31 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,115 @@ #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() + +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() + +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 +443,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); + } +} - 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); +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 +665,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 +687,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--; - 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++; + } 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++; } @@ -424,186 +780,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; - return pScb; - } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pScb->dma_type = M_RD_DMA_TYPE_NONE; +#endif + + 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 +957,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; } - 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; + + 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; + } + 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 +1824,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; - mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0); /* Set cmdid */ - mboxData[0xF] = 1; /* Set busy */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + volatile mega_mailbox64 *mbox64 = (mega_mailbox64 *) megaCfg->mbox64; +#endif + + u_char byte; - phys_mbox = virt_to_bus (megaCfg->mbox); +#ifdef __LP64__ + u64 phys_mbox; +#else + u32 phys_mbox; +#endif + u8 retval = -1; + + mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE); /* Set cmdid */ + mboxData[0xF] = 1; /* Set busy */ + +#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) { + +#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 count of SG requests */ - return scb->SCpnt->use_sg; + 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 +2114,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]; - memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer)); - memset (mbox, 0, 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); /* - * 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 +2364,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 - pHostTmpl->proc_name = "megaraid"; +#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; + } + + 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, 0x101E, 0x9010, 0); - count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0); - count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); + 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 - return count; + /* + * 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; } /*--------------------------------------------------------------------- * 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]; + 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); + } - megaCfg = (mega_host_config *) pSHost->hostdata; - mbox = (mega_mailbox *) mboxData; + 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 - /* Flush cache to disk */ - memset (mbox, 0, 16); - mboxData[0] = 0xA; + /* + * 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_mailbox *mboxpnt; + unsigned char mbox[16]; + int ret; - free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise - extra interrupt is generated */ + mboxpnt = (mega_mailbox *) mbox; - /* Issue a blocking (interrupts disabled) command to the card */ - megaIssueCmd (megaCfg, mboxData, NULL, 0); + memset (mbox, 0, sizeof (mbox)); + memset ((void *) megacfg->mega_buffer, + 0, sizeof (megacfg->mega_buffer)); - /* Free our resources */ - if (megaCfg->flag & BOARD_QUARTZ) { - iounmap ((void *) megaCfg->base); - } - else { - release_region (megaCfg->host->io_port, 16); - } + /* + * issue command to find out if the BIOS is enbled for this controller + */ + mbox[0] = IS_BIOS_ENABLED; + mbox[2] = GET_BIOS; - mega_freeSgList(megaCfg); - scsi_unregister (pSHost); + mboxpnt->xferaddr = virt_to_bus ((void *) megacfg->mega_buffer); - return 0; + ret = megaIssueCmd (megacfg, mbox, NULL, 0); + + return (*(char *) megacfg->mega_buffer); } -static inline void mega_freeSgList(mega_host_config *megaCfg) +static void mega_reorder_hosts (void) { - int i; + 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; + } + } + + if (boot_host == NULL) { + printk (KERN_WARNING "megaraid: no BIOS enabled.\n"); + return; + } - for (i = 0; i < megaCfg->max_cmds; i++) { - if (megaCfg->scbList[i].sgList) - kfree (megaCfg->scbList[i].sgList); /* free sgList */ - } + /* + * 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 void mega_swap_hosts (struct Scsi_Host *shone, struct Scsi_Host *shtwo) +{ + 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) + 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 +3038,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; + + 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; + } + + 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); + megaCfg->flag &= ~IN_QUEUE; - return 0; + } + + DRIVER_UNLOCK (megaCfg); + return 0; } /*---------------------------------------------------------------------- @@ -1798,167 +3154,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, ...) { - 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; - } - } - } + va_list args; + int i; - megaCfg->flag &= ~IN_RESET; + if (megaCfg->procidx > PROCBUFSIZE) + return 0; - mega_rundoneq(megaCfg); - return rc; + 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 = (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: "); + + 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 +3562,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) { - int heads, sectors, cylinders; - mega_host_config *megaCfg; + 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; - /* Get pointer to host config structure */ - megaCfg = (mega_host_config *) disk->device->host->hostdata; +#if DEBUG + if (megacfg->max_cmds >= MAX_COMMANDS) { + printk ("megaraid:ctlr max cmds = %x : MAX_CMDS = %x", + megacfg->max_cmds, MAX_COMMANDS); + } +#endif - /* 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 (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; } -__setup("megaraid=", megaraid_setup); +/* + * 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 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; + + /* save the user address */ + uaddr = ioc.ui.fcs.buffer; +/* +* 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; +} + +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 Mon Mar 26 15:36:30 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,25 +20,18 @@ 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 -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 +list-multi := qlogic_cs.o fdomain_cs.o aha152x_cs.o +aha152x_cs-objs := aha152x_stub.o aha152x.o +fdomain_cs-objs := fdomain_stub.o fdomain.o +qlogic_cs-objs := qlogic_stub.o qlogicfas.o include $(TOPDIR)/Rules.make -aha152x_cs.o: $(aha152x-objs) - $(LD) -r -o $@ $(aha152x-objs) - -apa1480_cb.o: $(apa1480-objs) - $(LD) -r -o $@ $(apa1480-objs) +aha152x_cs.o: $(aha152x_cs-objs) + $(LD) -r -o $@ $(aha152x_cs-objs) -fdomain_cs.o: $(fdomain-objs) - $(LD) -r -o $@ $(fdomain-objs) +fdomain_cs.o: $(fdomain_cs-objs) + $(LD) -r -o $@ $(fdomain_cs-objs) -qlogic_cs.o: $(qlogic-objs) - $(LD) -r -o $@ $(qlogic-objs) +qlogic_cs.o: $(qlogic_cs-objs) + $(LD) -r -o $@ $(qlogic_cs-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/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.4.2/linux/drivers/scsi/qlogicfc.c Mon Sep 18 13:36:25 2000 +++ linux/drivers/scsi/qlogicfc.c Tue Mar 20 15:05:46 2001 @@ -732,7 +732,7 @@ int wait_time; struct Scsi_Host *host = NULL; struct isp2x00_hostdata *hostdata; - struct pci_dev *pdev = NULL; + struct pci_dev *pdev; unsigned short device_ids[2]; dma64_addr_t busaddr; int i; @@ -751,6 +751,7 @@ } for (i=0; i<2; i++){ + pdev = NULL; while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) { if (pci_enable_device(pdev)) continue; @@ -1428,7 +1429,22 @@ for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++){ if (hostdata->handle_ptrs[i] && (hostdata->port_db[hostdata->handle_ptrs[i]->target].loop_id > QLOGICFC_MAX_LOOP_ID || hostdata->adapter_state & AS_REDO_LOOP_PORTDB)){ if (hostdata->port_db[hostdata->handle_ptrs[i]->target].loop_id != hostdata->port_db[0].loop_id){ + Scsi_Cmnd *Cmnd = hostdata->handle_ptrs[i]; + + if (Cmnd->use_sg) + pci64_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, + Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + else if (Cmnd->request_bufflen && + Cmnd->sc_data_direction != PCI_DMA_NONE) + pci64_unmap_single(hostdata->pci_dev, + *(dma64_addr_t *)&Cmnd->SCp, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + hostdata->handle_ptrs[i]->result = DID_SOFT_ERROR << 16; + if (hostdata->handle_ptrs[i]->scsi_done){ (*hostdata->handle_ptrs[i]->scsi_done) (hostdata->handle_ptrs[i]); } @@ -1521,6 +1537,17 @@ hostdata->handle_serials[handle] = 0; hostdata->queued--; if (Cmnd != NULL) { + if (Cmnd->use_sg) + pci64_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, + Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + else if (Cmnd->request_bufflen && + Cmnd->sc_data_direction != PCI_DMA_NONE) + pci64_unmap_single(hostdata->pci_dev, + *(dma64_addr_t *)&Cmnd->SCp, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); Cmnd->result = 0x0; (*Cmnd->scsi_done) (Cmnd); } else 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 20 12:04:58 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; @@ -13424,7 +13070,7 @@ (int) (PciDeviceFn(pdev) & 7)); #ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING - if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) { + if (pci_set_dma_mask(pdev, (dma_addr_t) (0xffffffffUL))) { printk(KERN_WARNING NAME53C8XX "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); return -1; @@ -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 Mon Mar 26 15:50:08 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 Mon Mar 26 15:49:54 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/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c --- v2.4.2/linux/drivers/sgi/char/graphics.c Wed Feb 21 18:20:34 2001 +++ linux/drivers/sgi/char/graphics.c Mon Mar 19 12:35:09 2001 @@ -153,11 +153,11 @@ * sgi_graphics_mmap */ disable_gconsole (); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); r = do_mmap (file, (unsigned long)vaddr, cards[board].g_regs_size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (r) return r; } diff -u --recursive --new-file v2.4.2/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c --- v2.4.2/linux/drivers/sgi/char/shmiq.c Wed Jul 12 21:58:43 2000 +++ linux/drivers/sgi/char/shmiq.c Mon Mar 19 12:35:09 2001 @@ -286,11 +286,11 @@ s = req.arg * sizeof (struct shmqevent) + sizeof (struct sharedMemoryInputQueue); v = sys_munmap (vaddr, s); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); do_munmap(current->mm, vaddr, s); do_mmap(filp, vaddr, s, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); shmiqs[minor].events = req.arg; shmiqs[minor].mapped = 1; 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/cs46xx.c linux/drivers/sound/cs46xx.c --- v2.4.2/linux/drivers/sound/cs46xx.c Wed Feb 21 18:20:34 2001 +++ linux/drivers/sound/cs46xx.c Tue Mar 20 12:04:58 2001 @@ -4020,8 +4020,8 @@ } memset(card, 0, sizeof(*card)); - card->ba0_addr = pci_dev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK; - card->ba1_addr = pci_dev->resource[1].start&PCI_BASE_ADDRESS_MEM_MASK; + card->ba0_addr = pci_resource_start(pci_dev, 0); + card->ba1_addr = pci_resource_start(pci_dev, 1); card->pci_dev = pci_dev; card->irq = pci_dev->irq; card->magic = CS_CARD_MAGIC; diff -u --recursive --new-file v2.4.2/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c --- v2.4.2/linux/drivers/sound/emu10k1/main.c Wed Feb 21 18:20:34 2001 +++ linux/drivers/sound/emu10k1/main.c Tue Mar 20 12:04:59 2001 @@ -619,7 +619,7 @@ } memset(card, 0, sizeof(struct emu10k1_card)); - if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) { + if (pci_set_dma_mask(pci_dev, EMU10K1_DMA_MASK)) { printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n"); kfree(card); return -ENODEV; diff -u --recursive --new-file v2.4.2/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.4.2/linux/drivers/sound/es1370.c Wed Feb 21 18:20:34 2001 +++ linux/drivers/sound/es1370.c Tue Mar 20 12:04:58 2001 @@ -2524,9 +2524,10 @@ return -1; if (pcidev->irq == 0) return -1; - if (!pci_dma_supported(pcidev, 0xffffffff)) { + i = pci_set_dma_mask(pcidev, 0xffffffff); + if (i) { printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n"); - return -1; + return i; } if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) { printk(KERN_WARNING "es1370: out of memory\n"); @@ -2608,7 +2609,6 @@ set_fs(fs); /* store it in the driver field */ pci_set_drvdata(pcidev, s); - pcidev->dma_mask = 0xffffffff; /* put it into driver list */ list_add_tail(&s->devs, &devs); /* increment devindex */ diff -u --recursive --new-file v2.4.2/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.4.2/linux/drivers/sound/es1371.c Wed Feb 21 18:20:34 2001 +++ linux/drivers/sound/es1371.c Tue Mar 20 12:04:58 2001 @@ -2737,9 +2737,10 @@ return -1; if (pcidev->irq == 0) return -1; - if (!pci_dma_supported(pcidev, 0xffffffff)) { + i = pci_set_dma_mask(pcidev, 0xffffffff); + if (i) { printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); - return -1; + return i; } if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { printk(KERN_WARNING PFX "out of memory\n"); @@ -2874,7 +2875,6 @@ outl(cssr, s->io+ES1371_REG_STATUS); /* store it in the driver field */ pci_set_drvdata(pcidev, s); - pcidev->dma_mask = 0xffffffff; /* put it into driver list */ list_add_tail(&s->devs, &devs); /* increment devindex */ diff -u --recursive --new-file v2.4.2/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.4.2/linux/drivers/sound/esssolo1.c Wed Feb 21 18:20:34 2001 +++ linux/drivers/sound/esssolo1.c Tue Mar 20 12:04:59 2001 @@ -2244,7 +2244,6 @@ { struct solo1_state *s; struct pm_dev *pmdev; - dma_addr_t dma_mask; if (!RSRCISIOREGION(pcidev, 0) || !RSRCISIOREGION(pcidev, 1) || @@ -2253,14 +2252,16 @@ return -1; if (pcidev->irq == 0) return -1; - if (pci_dma_supported(pcidev, 0x00ffffff)) { - dma_mask = 0x00ffffff; /* this enables playback and recording */ - } else if (pci_dma_supported(pcidev, 0xffffffff)) { - dma_mask = 0xffffffff; /* this enables only playback, as the recording BMDMA can handle only 24bits */ - } else { + + /* Recording requires 24-bit DMA, so attempt to set dma mask + * to 24 bits first, then 32 bits (playback only) if that fails. + */ + if (pci_set_dma_mask(pcidev, 0x00ffffff) && + pci_set_dma_mask(pcidev, 0xffffffff)) { printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n"); return -1; } + if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) { printk(KERN_WARNING "solo1: out of memory\n"); return -1; @@ -2318,7 +2319,6 @@ goto err; /* store it in the driver field */ pci_set_drvdata(pcidev, s); - pcidev->dma_mask = dma_mask; /* put it into driver list */ list_add_tail(&s->devs, &devs); 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 Sun Mar 25 18:24:31 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"); @@ -1833,14 +1891,15 @@ { struct i810_card *card; - if (!pci_dma_supported(pci_dev, I810_DMA_MASK)) { + if (pci_enable_device(pci_dev)) + return -EIO; + + if (pci_set_dma_mask(pci_dev, I810_DMA_MASK)) { printk(KERN_ERR "intel810: architecture does not support" " 32bit PCI busmaster DMA\n"); return -ENODEV; } - if (pci_enable_device(pci_dev)) - return -EIO; if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "i810_audio: out of memory\n"); return -ENOMEM; @@ -1865,7 +1924,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]); @@ -1900,7 +1969,6 @@ return -ENODEV; } pci_dev->driver_data = card; - pci_dev->dma_mask = I810_DMA_MASK; return 0; } @@ -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/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.4.2/linux/drivers/sound/sonicvibes.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/sound/sonicvibes.c Tue Mar 20 12:04:59 2001 @@ -2478,7 +2478,7 @@ return -1; if (pcidev->irq == 0) return -1; - if (!pci_dma_supported(pcidev, 0x00ffffff)) { + if (pci_set_dma_mask(pcidev, 0x00ffffff)) { printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n"); return -1; } @@ -2602,7 +2602,6 @@ set_fs(fs); /* store it in the driver field */ pci_set_drvdata(pcidev, s); - pcidev->dma_mask = 0x00ffffff; /* put it into driver list */ list_add_tail(&s->devs, &devs); /* increment devindex */ 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 Tue Mar 20 12:04:59 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,18 +3298,18 @@ 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; struct trident_card *card; u8 revision; - if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) { + if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) { printk(KERN_ERR "trident: architecture does not support" " 30bit PCI busmaster DMA\n"); return -ENODEV; @@ -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); @@ -3224,7 +3429,6 @@ } pci_set_drvdata(pci_dev, card); - pci_dev->dma_mask = TRIDENT_DMA_MASK; /* Enable Address Engine Interrupts */ trident_enable_loop_interrupts(card); 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 20 11:29:01 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/bluetooth.c linux/drivers/usb/bluetooth.c --- v2.4.2/linux/drivers/usb/bluetooth.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/usb/bluetooth.c Mon Mar 19 17:21:54 2001 @@ -1,11 +1,17 @@ /* - * bluetooth.c Version 0.7 + * bluetooth.c Version 0.8 * * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B * + * (2001/03/10) Version 0.8 gkh + * Fixed problem with not unlinking interrupt urb on device close + * and resubmitting the read urb on error with bluetooth struct. + * Thanks to Narayan Mohanram for the + * fixes. + * * (11/29/2000) Version 0.7 gkh * Fixed problem with overrunning the tty flip buffer. * Removed unneeded NULL pointer initialization. @@ -379,6 +385,7 @@ for (i = 0; i < NUM_BULK_URBS; ++i) usb_unlink_urb (bluetooth->write_urb_pool[i]); usb_unlink_urb (bluetooth->read_urb); + usb_unlink_urb (bluetooth->interrupt_in_urb); bluetooth->active = 0; } @@ -852,7 +859,7 @@ if (!bluetooth) { dbg(__FUNCTION__ " - bad bluetooth pointer, exiting"); - goto exit; + return; } if (urb->status) { diff -u --recursive --new-file v2.4.2/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c --- v2.4.2/linux/drivers/usb/dc2xx.c Wed Feb 21 18:20:35 2001 +++ linux/drivers/usb/dc2xx.c Sun Mar 25 18:14:21 2001 @@ -174,7 +174,7 @@ usb_rcvbulkpipe (camera->dev, camera->inEP), camera->buf, len, &count, HZ*10); - dbg ("read (%d) - 0x%x %d", len, retval, count); + dbg ("read (%Zd) - 0x%x %d", len, retval, count); if (!retval) { if (copy_to_user (buf, camera->buf, count)) @@ -187,7 +187,7 @@ break; interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT); - dbg ("read (%d) - retry", len); + dbg ("read (%Zd) - retry", len); } up (&camera->sem); return retval; @@ -271,7 +271,7 @@ } done: up (&camera->sem); - dbg ("wrote %d", bytes_written); + dbg ("wrote %Zd", bytes_written); return bytes_written; } diff -u --recursive --new-file v2.4.2/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.4.2/linux/drivers/usb/devio.c Sun Nov 12 20:45:19 2000 +++ linux/drivers/usb/devio.c Fri Mar 23 11:50:01 2001 @@ -838,7 +838,7 @@ } if (totlen > 32768) { kfree(isopkt); - return -ENOMEM; + return -EINVAL; } uurb.buffer_length = totlen; break; diff -u --recursive --new-file v2.4.2/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.4.2/linux/drivers/usb/hub.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/hub.c Sun Mar 25 18:14:21 2001 @@ -146,6 +146,8 @@ return -1; } + le16_to_cpus(&hub->descriptor->wHubCharacteristics); + hub->nports = dev->maxchild = hub->descriptor->bNbrPorts; info("%d port%s detected", hub->nports, (hub->nports == 1) ? "" : "s"); @@ -291,6 +293,7 @@ INIT_LIST_HEAD(&hub->event_list); hub->dev = dev; + init_MUTEX(&hub->khubd_sem); /* Record the new hub's existence */ spin_lock_irqsave(&hub_event_lock, flags); @@ -334,6 +337,9 @@ spin_unlock_irqrestore(&hub_event_lock, flags); + down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */ + up(&hub->khubd_sem); + if (hub->urb) { usb_unlink_urb(hub->urb); usb_free_urb(hub->urb); @@ -545,6 +551,13 @@ return; } + /* Some low speed devices have problems with the quick delay, so */ + /* be a bit pessimistic with those devices. RHbug #23670 */ + if (portstatus & USB_PORT_STAT_LOW_SPEED) { + wait_ms(400); + delay = HUB_LONG_RESET_TIME; + } + down(&usb_address0_sem); tempstr = kmalloc(1024, GFP_KERNEL); @@ -639,7 +652,7 @@ spin_lock_irqsave(&hub_event_lock, flags); if (list_empty(&hub_event_list)) - goto he_unlock; + break; /* Grab the next entry from the beginning of the list */ tmp = hub_event_list.next; @@ -650,6 +663,7 @@ list_del(tmp); INIT_LIST_HEAD(tmp); + down(&hub->khubd_sem); /* never blocks, we were on list */ spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { @@ -658,6 +672,7 @@ if (usb_hub_reset(hub)) { err("error resetting hub %d - disconnecting", dev->devnum); usb_hub_disconnect(dev); + up(&hub->khubd_sem); continue; } @@ -733,9 +748,9 @@ usb_hub_power_on(hub); } } + up(&hub->khubd_sem); } /* end while (1) */ -he_unlock: spin_unlock_irqrestore(&hub_event_lock, flags); } @@ -905,7 +920,7 @@ if (ret < 0) err("unable to get device descriptor (error=%d)", ret); else - err("USB device descriptor short read (expected %i, got %i)", sizeof(dev->descriptor), ret); + err("USB device descriptor short read (expected %Zi, got %i)", sizeof(dev->descriptor), ret); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; diff -u --recursive --new-file v2.4.2/linux/drivers/usb/hub.h linux/drivers/usb/hub.h --- v2.4.2/linux/drivers/usb/hub.h Thu Dec 7 16:13:38 2000 +++ linux/drivers/usb/hub.h Fri Mar 23 11:50:01 2001 @@ -108,6 +108,8 @@ int nports; struct usb_hub_descriptor *descriptor; + + struct semaphore khubd_sem; }; #endif 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/microtek.c linux/drivers/usb/microtek.c --- v2.4.2/linux/drivers/usb/microtek.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/microtek.c Fri Mar 23 11:50:01 2001 @@ -9,7 +9,7 @@ * This driver implements a SCSI host controller driver and a USB * device driver. To avoid confusion, all the USB related stuff is * prefixed by mts_usb_ and all the SCSI stuff by mts_scsi_. - * + * * Microtek (www.microtek.com) did not release the specifications for * their USB protocol to us, so we had to reverse engineer them. We * don't know for which models they are valid. @@ -52,7 +52,7 @@ * you want it, just send mail. * * Status: - * + * * Untested with multiple scanners. * Untested on SMP. * Untested on a bigendian machine. @@ -104,6 +104,17 @@ * 20000822 Version 0.2.3 * 20000913 Reduced module size if debugging is off * 20000913 Version 0.2.4 + * 20010210 New abort logic + * 20010210 Version 0.3.0 + * 20010217 Merged scatter/gather + * 20010218 Version 0.4.0 + * 20010218 Cosmetic fixes + * 20010218 Version 0.4.1 + * 20010306 Abort while using scatter/gather + * 20010306 Version 0.4.2 + * 20010311 Remove all timeouts and tidy up generally (john) + * 20010320 check return value of scsi_register() + * 20010320 Version 0.4.3 */ #include @@ -128,15 +139,9 @@ #include "microtek.h" -/* Constants */ - -#define MTS_ABORT_TIMEOUT HZ /*jiffies*/ - - /* Should we do debugging? */ -// #define MTS_DO_DEBUG - +//#define MTS_DO_DEBUG /* USB layer driver interface */ @@ -147,7 +152,7 @@ static struct usb_device_id mts_usb_ids []; static struct usb_driver mts_usb_driver = { - name: "microtek", + name: "microtekX6", probe: mts_usb_probe, disconnect: mts_usb_disconnect, id_table: mts_usb_ids, @@ -156,7 +161,7 @@ /* Internal driver stuff */ -#define MTS_VERSION "0.2.4" +#define MTS_VERSION "0.4.3" #define MTS_NAME "microtek usb (rev " MTS_VERSION "): " #define MTS_WARNING(x...) \ @@ -177,8 +182,8 @@ MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ ) #define MTS_DEBUG_INT() \ do { MTS_DEBUG_GOT_HERE(); \ - MTS_DEBUG("transfer = %x context = %x\n",(int)transfer,(int)context ); \ - MTS_DEBUG("status = %x data-length = %x sent = %x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \ + MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \ + MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \ mts_debug_dump(context->instance);\ } while(0) #else @@ -190,23 +195,17 @@ #define MTS_DEBUG_INT() MTS_NUL_STATEMENT #endif - + #define MTS_INT_INIT()\ - do {\ - context = (struct mts_transfer_context*)transfer->context; \ - if (atomic_read(&context->do_abort)) {\ - mts_transfer_cleanup(transfer);\ - return;\ - }\ + struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context; \ MTS_DEBUG_INT();\ - } while (0) #ifdef MTS_DO_DEBUG static inline void mts_debug_dump(struct mts_desc* desc) { - MTS_DEBUG("desc at 0x%x: halted = %x%x, toggle = %x%x\n", + MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n", (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0], (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0] ); @@ -296,60 +295,34 @@ out: MTS_DEBUG( " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], + srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]); } #else -static inline void mts_show_command(Scsi_Cmnd *srb) +static inline void mts_show_command(Scsi_Cmnd * dummy) { - while (0) {} } -static inline void mts_debug_dump(struct mts_desc* desc) +static inline void mts_debug_dump(struct mts_desc* dummy) { - while (0) {} } #endif - - -static inline int mts_is_aborting(struct mts_desc* desc) { +/* static inline int mts_is_aborting(struct mts_desc* desc) { return (atomic_read(&desc->context.do_abort)); -} - -static inline void mts_request_abort(struct mts_desc* desc) { - MTS_DEBUG_GOT_HERE(); - mts_debug_dump(desc); - atomic_set(&desc->context.do_abort,1); -} +} */ static inline void mts_urb_abort(struct mts_desc* desc) { MTS_DEBUG_GOT_HERE(); mts_debug_dump(desc); - if ( desc->urb.status == USB_ST_URB_PENDING ) { - usb_unlink_urb( &desc->urb ); - } -} - -static inline void mts_wait_abort(struct mts_desc* desc) -{ - mts_request_abort(desc); - - while( !atomic_read(&desc->lock.count) ) { -/* Is there a function to check if the semaphore is locked? */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout( MTS_ABORT_TIMEOUT ); - MTS_DEBUG_GOT_HERE(); - mts_urb_abort(desc); - } + usb_unlink_urb( &desc->urb ); } - static struct mts_desc * mts_list; /* list of active scanners */ struct semaphore mts_list_semaphore; @@ -362,10 +335,10 @@ (int)to_remove ); lock_kernel(); - mts_wait_abort(to_remove); + mts_urb_abort(to_remove); MTS_DEBUG_GOT_HERE(); - + if ( to_remove != mts_list ) { MTS_DEBUG_GOT_HERE(); if (to_remove->prev && to_remove->next) @@ -378,7 +351,7 @@ mts_list->prev = 0; } } - + if ( to_remove->next ) { MTS_DEBUG_GOT_HERE(); to_remove->next->prev = to_remove->prev; @@ -387,7 +360,7 @@ MTS_DEBUG_GOT_HERE(); scsi_unregister_module(MODULE_SCSI_HA, &(to_remove->ctempl)); unlock_kernel(); - + kfree( to_remove ); } @@ -395,16 +368,16 @@ void mts_add_nolock( struct mts_desc* to_add ) { MTS_DEBUG( "adding 0x%x to list\n", (int)to_add ); - + to_add->prev = 0; to_add->next = mts_list; if ( mts_list ) { mts_list->prev = to_add; } - + mts_list = to_add; } - + @@ -415,20 +388,18 @@ static int mts_scsi_release(struct Scsi_Host *psh) { MTS_DEBUG_GOT_HERE(); - + return 0; } static int mts_scsi_abort (Scsi_Cmnd *srb) -/* interrupt context (!) */ /* FIXME this is about to become task context */ { struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]); MTS_DEBUG_GOT_HERE(); - - mts_request_abort(desc); + mts_urb_abort(desc); - + return SCSI_ABORT_PENDING; } @@ -450,10 +421,10 @@ static int mts_scsi_detect (struct SHT * sht) { /* Whole function stolen from usb-storage */ - + struct mts_desc * desc = (struct mts_desc *)sht->proc_dir; /* What a hideous hack! */ - + char local_name[48]; MTS_DEBUG_GOT_HERE(); @@ -467,15 +438,20 @@ MTS_ERROR( "unable to allocate memory for proc interface!!\n" ); return 0; } - + strcpy(sht->proc_name, local_name); sht->proc_dir = NULL; /* In host->hostdata we store a pointer to desc */ desc->host = scsi_register(sht, sizeof(desc)); + if (desc->host == NULL) { + MTS_ERROR("Cannot register due to low memory"); + kfree(sht->proc_name); + return 0; + } desc->host->hostdata[0] = (unsigned long)desc; -/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */ +/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */ return 1; } @@ -490,6 +466,7 @@ int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ); static void mts_transfer_cleanup( struct urb *transfer ); +static void mts_do_sg(struct urb * transfer); inline static @@ -503,10 +480,9 @@ /* Holding transfer->context->lock! */ { int res; - struct mts_transfer_context* context; - + MTS_INT_INIT(); - + FILL_BULK_URB(transfer, context->instance->usb_dev, pipe, @@ -516,16 +492,13 @@ context ); -/* transfer->transfer_flags = USB_DISABLE_SPD;*/ transfer->transfer_flags = USB_ASYNC_UNLINK; transfer->status = 0; - transfer->timeout = 100; res = usb_submit_urb( transfer ); if ( res ) { MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res ); context->srb->result = DID_ERROR << 16; - context->state = mts_con_error; mts_transfer_cleanup(transfer); } return; @@ -535,8 +508,8 @@ static void mts_transfer_cleanup( struct urb *transfer ) /* Interrupt context! */ { - struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context; - + MTS_INT_INIT(); + if ( context->final_callback ) context->final_callback(context->srb); up( &context->instance->lock ); @@ -545,8 +518,6 @@ static void mts_transfer_done( struct urb *transfer ) { - struct mts_transfer_context* context; - MTS_INT_INIT(); context->srb->result &= MTS_SCSI_ERR_MASK; @@ -561,34 +532,25 @@ static void mts_get_status( struct urb *transfer ) /* Interrupt context! */ { - struct mts_transfer_context* context; - MTS_INT_INIT(); - context->state = mts_con_status; - mts_int_submit_urb(transfer, usb_rcvbulkpipe(context->instance->usb_dev, context->instance->ep_response), &context->status, 1, mts_transfer_done ); - - - return; } static void mts_data_done( struct urb* transfer ) /* Interrupt context! */ { - struct mts_transfer_context* context; - MTS_INT_INIT(); if ( context->data_length != transfer->actual_length ) { context->srb->resid = context->data_length - transfer->actual_length; } else if ( transfer->status ) { - context->srb->result = DID_ERROR<<16; + context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; } mts_get_status(transfer); @@ -600,39 +562,65 @@ static void mts_command_done( struct urb *transfer ) /* Interrupt context! */ { - struct mts_transfer_context* context; - MTS_INT_INIT(); if ( transfer->status ) { - context->srb->result = DID_ERROR<<16; + if (transfer->status == -ENOENT) { + /* We are being killed */ + MTS_DEBUG_GOT_HERE(); + context->srb->result = DID_ABORT<<16; + } else { + /* A genuine error has occured */ + MTS_DEBUG_GOT_HERE(); + + context->srb->result = DID_ERROR<<16; + } mts_transfer_cleanup(transfer); - + return; } - + if ( context->data ) { - context->state = mts_con_data; mts_int_submit_urb(transfer, context->data_pipe, context->data, context->data_length, - mts_data_done); + context->srb->use_sg ? mts_do_sg : mts_data_done); } else mts_get_status(transfer); - + return; } +static void mts_do_sg (struct urb* transfer) +{ + struct scatterlist * sg; + MTS_INT_INIT(); + + MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg); + + if (transfer->status) { + context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; + mts_transfer_cleanup(transfer); + } + sg = context->srb->buffer; + context->fragment++; + mts_int_submit_urb(transfer, + context->data_pipe, + sg[context->fragment].address, + sg[context->fragment].length, + context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg); + return; +} - static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 }; - static const u8 mts_read_image_sig_len = 4; - static const unsigned char mts_direction[256/8] = { - 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, - 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; +static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 }; +static const u8 mts_read_image_sig_len = 4; +static const unsigned char mts_direction[256/8] = { + 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, + 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; #define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1) @@ -640,26 +628,34 @@ static void mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc ) { - int pipe; - - + struct scatterlist * sg; + MTS_DEBUG_GOT_HERE(); desc->context.instance = desc; desc->context.srb = srb; - desc->context.state = mts_con_command; - atomic_set(&desc->context.do_abort,0); - - if ( !srb->bufflen ){ - desc->context.data = 0; - desc->context.data_length = 0; - return; + desc->context.fragment = 0; + + if (!srb->use_sg) { + if ( !srb->bufflen ){ + desc->context.data = 0; + desc->context.data_length = 0; + return; + } else { + desc->context.data = srb->buffer; + desc->context.data_length = srb->bufflen; + MTS_DEBUG("length = %d or %d\n", + srb->request_bufflen, srb->bufflen); + } } else { - desc->context.data = srb->buffer; - desc->context.data_length = srb->bufflen; + MTS_DEBUG("Using scatter/gather\n"); + sg = srb->buffer; + desc->context.data = sg[0].address; + desc->context.data_length = sg[0].length; } - + + /* can't rely on srb->sc_data_direction */ /* Brutally ripped from usb-storage */ @@ -691,11 +687,11 @@ MTS_DEBUG_GOT_HERE(); mts_show_command(srb); mts_debug_dump(desc); - + if ( srb->device->lun || srb->device->id || srb->device->channel ) { MTS_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel ); - + MTS_DEBUG("this device doesn't exist\n"); srb->result = DID_BAD_TARGET << 16; @@ -704,14 +700,10 @@ callback(srb); goto out; - } + } down(&desc->lock); - - MTS_DEBUG_GOT_HERE(); - mts_show_command(srb); - FILL_BULK_URB(&desc->urb, desc->usb_dev, usb_sndbulkpipe(desc->usb_dev,desc->ep_out), @@ -720,31 +712,24 @@ mts_command_done, &desc->context ); - - + + mts_build_transfer_context( srb, desc ); desc->context.final_callback = callback; - desc->urb.timeout = 100; - desc->urb.transfer_flags = USB_ASYNC_UNLINK; -/* desc->urb.transfer_flags = USB_DISABLE_SPD;*/ - res=usb_submit_urb(&desc->urb); - + if(res){ MTS_ERROR("error %d submitting URB\n",(int)res); srb->result = DID_ERROR << 16; if(callback) callback(srb); - up(&desc->lock); /* no further cleanup is done */ + up(&desc->lock); - goto out; - } - - MTS_DEBUG_GOT_HERE(); + } - out: +out: return err; } /* @@ -755,23 +740,21 @@ static Scsi_Host_Template mts_scsi_host_template = { - name: "microtek", + name: "microtekX6", detect: mts_scsi_detect, release: mts_scsi_release, - command: 0, queuecommand: mts_scsi_queuecommand, eh_abort_handler: mts_scsi_abort, - eh_device_reset_handler:0, - eh_bus_reset_handler: 0, eh_host_reset_handler: mts_scsi_host_reset, + sg_tablesize: SG_ALL, can_queue: 1, this_id: -1, cmd_per_lun: 1, present: 0, unchecked_isa_dma: FALSE, - use_clustering: FALSE, + use_clustering: TRUE, use_new_eh_code: TRUE, emulated: TRUE }; @@ -782,7 +765,7 @@ static void mts_usb_disconnect (struct usb_device *dev, void *ptr) { struct mts_desc* to_remove = (struct mts_desc*)ptr; - + MTS_DEBUG_GOT_HERE(); /* leave the list - lock it */ @@ -847,7 +830,7 @@ int ep_in_set[3]; /* this will break if we have more than three endpoints which is why we check */ int *ep_in_current = ep_in_set; - + struct mts_desc * new_desc; struct vendor_product const* p; @@ -856,7 +839,7 @@ MTS_DEBUG_GOT_HERE(); MTS_DEBUG( "usb-device descriptor at %x\n", (int)dev ); - + MTS_DEBUG( "product id = 0x%x, vendor id = 0x%x\n", (int)dev->descriptor.idProduct, (int)dev->descriptor.idVendor ); @@ -871,12 +854,12 @@ if ( p->support_status != mts_sup_full ) MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n", p->name ); - + /* the altsettting 0 on the interface we're probing */ altsetting = - &(dev->actconfig->interface[interface].altsetting[0]); + &(dev->actconfig->interface[interface].altsetting[0]); + - /* Check if the config is sane */ if ( altsetting->bNumEndpoints != MTS_EP_TOTAL ) { @@ -886,13 +869,13 @@ } for( i = 0; i < altsetting->bNumEndpoints; i++ ) { - if ((altsetting->endpoint[i].bmAttributes & + if ((altsetting->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { - + MTS_WARNING( "can only deal with bulk endpoints; endpoint %d is not bulk.\n", (int)altsetting->endpoint[i].bEndpointAddress ); } else { - if (altsetting->endpoint[i].bEndpointAddress & + if (altsetting->endpoint[i].bEndpointAddress & USB_DIR_IN) *ep_in_current++ = altsetting->endpoint[i].bEndpointAddress & @@ -902,26 +885,26 @@ MTS_WARNING( "can only deal with one output endpoints. Bailing out." ); return NULL; } - + ep_out = altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; } } - + } - + if ( ep_out == -1 ) { MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); return NULL; } - - + + /* I don't understand the following fully (it's from usb-storage) -- John */ /* set the interface -- STALL is an acceptable response here */ result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0); - + MTS_DEBUG("usb_set_interface returned %d.\n",result); switch( result ) { @@ -970,7 +953,7 @@ new_desc->ep_out = ep_out; new_desc->ep_response = ep_in_set[0]; new_desc->ep_image = ep_in_set[1]; - + if ( new_desc->ep_out != MTS_EP_OUT ) MTS_WARNING( "will this work? Command EP is not usually %d\n", @@ -984,16 +967,16 @@ MTS_WARNING( "will this work? Image data EP is not usually %d\n", (int)new_desc->ep_image ); - + /* Initialize the host template based on the default one */ - memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template)); + memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template)); /* HACK from usb-storage - this is needed for scsi detection */ (struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */ - + MTS_DEBUG("registering SCSI module\n"); - + new_desc->ctempl.module = THIS_MODULE; - result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl)); + result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl)); /* Will get hit back in microtek_detect by this func */ if ( result ) { @@ -1011,12 +994,12 @@ down(&mts_list_semaphore); mts_add_nolock( new_desc ); - + up(&mts_list_semaphore); - - + + MTS_DEBUG("completed probe and exiting happily\n"); - + return (void *)new_desc; } @@ -1027,7 +1010,7 @@ int __init microtek_drv_init(void) { int result; - + MTS_DEBUG_GOT_HERE(); init_MUTEX(&mts_list_semaphore); @@ -1037,14 +1020,14 @@ } else { MTS_DEBUG("driver registered.\n"); } - + return 0; } void __exit microtek_drv_exit(void) { struct mts_desc* next; - + MTS_DEBUG_GOT_HERE(); usb_deregister(&mts_usb_driver); @@ -1060,7 +1043,7 @@ /* advance the list pointer */ mts_list = next; } - + up(&mts_list_semaphore); } diff -u --recursive --new-file v2.4.2/linux/drivers/usb/microtek.h linux/drivers/usb/microtek.h --- v2.4.2/linux/drivers/usb/microtek.h Wed Jun 28 19:49:00 2000 +++ linux/drivers/usb/microtek.h Fri Mar 23 11:50:01 2001 @@ -21,20 +21,8 @@ void* data; unsigned data_length; int data_pipe; + int fragment; - enum { - mts_con_none, - mts_con_command, - mts_con_data, - mts_con_status, - mts_con_error, - mts_con_done - } - state; - - atomic_t do_abort; /* when != 0 URB completion routines will - return straightaway */ - u8 status; /* status returned from ep_response after command completion */ }; @@ -44,18 +32,18 @@ struct mts_desc *prev; struct usb_device *usb_dev; - + int interface; /* Endpoint addresses */ u8 ep_out; u8 ep_response; u8 ep_image; - + struct Scsi_Host * host; Scsi_Host_Template ctempl; int host_number; - + struct semaphore lock; struct urb urb; @@ -68,5 +56,5 @@ #define MTS_EP_IMAGE 0x3 #define MTS_EP_TOTAL 0x3 -#define MTS_SCSI_ERR_MASK ~0x3fu +#define MTS_SCSI_ERR_MASK ~0x3fu diff -u --recursive --new-file v2.4.2/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- v2.4.2/linux/drivers/usb/ov511.c Thu Jan 4 13:15:32 2001 +++ linux/drivers/usb/ov511.c Sun Mar 25 18:24:31 2001 @@ -149,8 +149,6 @@ MODULE_AUTHOR("Mark McClelland & Bret Wallach & Orion Sky Lawlor & Kevin Moore & Charl P. Botha & Claudio Matsuoka "); MODULE_DESCRIPTION("OV511 USB Camera Driver"); -char kernel_version[] = UTS_RELEASE; - static struct usb_driver ov511_driver; /* I know, I know, global variables suck. This is only a temporary hack */ diff -u --recursive --new-file v2.4.2/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c --- v2.4.2/linux/drivers/usb/pegasus.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/pegasus.c Sun Mar 18 19:54:52 2001 @@ -54,7 +54,7 @@ #define PEGASUS_USE_INTR #define PEGASUS_WRITE_EEPROM -static const char *version = __FILE__ ": v0.4.17 2000/11/13 (C) 1999-2000 Petko Manolov (petkan@dce.bg)"; +static const char *version = __FILE__ ": v0.4.18 2001/03/18 (C) 1999-2000 Petko Manolov (petkan@dce.bg)"; static int loopback = 0; @@ -124,6 +124,7 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) { int ret; + DECLARE_WAITQUEUE(wait, current); while ( pegasus->flags & ETH_REGS_CHANGED ) { pegasus->flags |= CTRL_URB_SLEEP; @@ -131,22 +132,27 @@ } pegasus->dr.requesttype = PEGASUS_REQT_READ; pegasus->dr.request = PEGASUS_REQ_GET_REGS; - pegasus->dr.value = 0; + pegasus->dr.value = cpu_to_le16 (0); pegasus->dr.index = cpu_to_le16p(&indx); - pegasus->dr.length = - pegasus->ctrl_urb.transfer_buffer_length = cpu_to_le16p(&size); + pegasus->dr.length = cpu_to_le16p(&size); + pegasus->ctrl_urb.transfer_buffer_length = size; FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, usb_rcvctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, data, size, ctrl_callback, pegasus ); + add_wait_queue( &pegasus->ctrl_wait, &wait ); + set_current_state( TASK_INTERRUPTIBLE ); + pegasus->flags |= CTRL_URB_SLEEP; + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { err( __FUNCTION__ " BAD CTRLs %d", ret); goto out; } - pegasus->flags |= CTRL_URB_SLEEP; - interruptible_sleep_on( &pegasus->ctrl_wait ); + + schedule(); + remove_wait_queue( &pegasus->ctrl_wait, &wait ); out: return ret; } @@ -155,6 +161,7 @@ static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) { int ret; + DECLARE_WAITQUEUE(wait, current); while ( pegasus->flags & ETH_REGS_CHANGED ) { pegasus->flags |= CTRL_URB_SLEEP ; @@ -162,22 +169,27 @@ } pegasus->dr.requesttype = PEGASUS_REQT_WRITE; pegasus->dr.request = PEGASUS_REQ_SET_REGS; - pegasus->dr.value = 0; + pegasus->dr.value = cpu_to_le16 (0); pegasus->dr.index = cpu_to_le16p( &indx ); - pegasus->dr.length = - pegasus->ctrl_urb.transfer_buffer_length = cpu_to_le16p( &size ); + pegasus->dr.length = cpu_to_le16p( &size ); + pegasus->ctrl_urb.transfer_buffer_length = size; FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, data, size, ctrl_callback, pegasus ); + + add_wait_queue( &pegasus->ctrl_wait, &wait ); + set_current_state( TASK_INTERRUPTIBLE ); + pegasus->flags |= CTRL_URB_SLEEP; if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { err( __FUNCTION__ " BAD CTRL %d", ret); return ret; } - pegasus->flags |= CTRL_URB_SLEEP; - interruptible_sleep_on( &pegasus->ctrl_wait ); + + schedule(); + remove_wait_queue( &pegasus->ctrl_wait, &wait ); return ret; } @@ -186,29 +198,37 @@ static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data ) { int ret; - + __u16 dat = data; + DECLARE_WAITQUEUE(wait, current); + while ( pegasus->flags & ETH_REGS_CHANGED ) { pegasus->flags |= CTRL_URB_SLEEP; interruptible_sleep_on( &pegasus->ctrl_wait ); } pegasus->dr.requesttype = PEGASUS_REQT_WRITE; pegasus->dr.request = PEGASUS_REQ_SET_REG; - pegasus->dr.value = data; + pegasus->dr.value = cpu_to_le16p( &dat); pegasus->dr.index = cpu_to_le16p( &indx ); - pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = 1; + pegasus->dr.length = cpu_to_le16( 1 ); + pegasus->ctrl_urb.transfer_buffer_length = 1; FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr, &data, 1, ctrl_callback, pegasus ); + add_wait_queue( &pegasus->ctrl_wait, &wait ); + set_current_state( TASK_INTERRUPTIBLE ); + pegasus->flags |= CTRL_URB_SLEEP; + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { err( __FUNCTION__ " BAD CTRL %d", ret); return ret; } - pegasus->flags |= CTRL_URB_SLEEP; - interruptible_sleep_on( &pegasus->ctrl_wait ); - + + schedule(); + remove_wait_queue( &pegasus->ctrl_wait, &wait ); + return ret; } @@ -220,8 +240,8 @@ pegasus->dr.requesttype = PEGASUS_REQT_WRITE; pegasus->dr.request = PEGASUS_REQ_SET_REGS; pegasus->dr.value = 0; - pegasus->dr.index = EthCtrl0; - pegasus->dr.length = + pegasus->dr.index = cpu_to_le16(EthCtrl0); + pegasus->dr.length = cpu_to_le16(3); pegasus->ctrl_urb.transfer_buffer_length = 3; FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, @@ -240,7 +260,8 @@ { int i; __u8 data[4] = { phy, 0, 0, indx }; - + __u16 regdi; + set_register( pegasus, PhyCtrl, 0 ); set_registers( pegasus, PhyAddr, sizeof(data), data ); set_register( pegasus, PhyCtrl, (indx | PHY_READ) ); @@ -250,7 +271,8 @@ break; } if ( i < REG_TIMEOUT ) { - get_registers( pegasus, PhyData, 2, regd ); + get_registers( pegasus, PhyData, 2, ®di ); + *regd = le16_to_cpu(regdi); return 0; } warn( __FUNCTION__ " failed" ); @@ -283,18 +305,22 @@ static int read_eprom_word( pegasus_t *pegasus, __u8 index, __u16 *retdata ) { - int i, tmp; - + int i; + __u8 tmp; + __u16 retdatai; + set_register( pegasus, EpromCtrl, 0 ); set_register( pegasus, EpromOffset, index ); set_register( pegasus, EpromCtrl, EPROM_READ); + for ( i=0; i < REG_TIMEOUT; i++ ) { get_registers( pegasus, EpromCtrl, 1, &tmp ); if ( tmp & EPROM_DONE ) break; } if ( i < REG_TIMEOUT ) { - get_registers( pegasus, EpromData, 2, retdata ); + get_registers( pegasus, EpromData, 2, &retdatai ); + *retdata = le16_to_cpu (retdatai); return 0; } warn( __FUNCTION__ " failed" ); @@ -349,9 +375,12 @@ static inline void get_node_id( pegasus_t *pegasus, __u8 *id ) { int i; - - for (i = 0; i < 3; i++) - read_eprom_word( pegasus, i, (__u16 *)&id[i*2]); + __u16 w16; + + for (i = 0; i < 3; i++) { + read_eprom_word( pegasus, i, &w16); + ((__u16 *) id)[i] = cpu_to_le16p (&w16); + } } @@ -473,7 +502,7 @@ if ( !count ) goto goon; - rx_status = *(int *)(pegasus->rx_buff + count - 4); + rx_status = le32_to_cpu(*(int *)(pegasus->rx_buff + count - 4)); if ( rx_status & 0x000e0000 ) { dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000); pegasus->stats.rx_errors++; @@ -585,10 +614,11 @@ pegasus_t *pegasus = net->priv; int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3; int res; - + __u16 l16 = skb->len; + netif_stop_queue( net ); - ((__u16 *)pegasus->tx_buff)[0] = skb->len; + ((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 ); memcpy(pegasus->tx_buff+2, skb->data, skb->len); FILL_BULK_URB( &pegasus->tx_urb, pegasus->usb, usb_sndbulkpipe(pegasus->usb, 2), diff -u --recursive --new-file v2.4.2/linux/drivers/usb/plusb.c linux/drivers/usb/plusb.c --- v2.4.2/linux/drivers/usb/plusb.c Tue Nov 28 21:50:07 2000 +++ linux/drivers/usb/plusb.c Sun Mar 25 18:14:21 2001 @@ -887,7 +887,7 @@ /* --------------------------------------------------------------------- */ -static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum) +static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum, const struct usb_device_id *id) { plusb_t *s; 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 Sun Mar 25 18:14:21 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 (%Zd).", 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/Config.in linux/drivers/usb/serial/Config.in --- v2.4.2/linux/drivers/usb/serial/Config.in Sat Feb 3 19:51:30 2001 +++ linux/drivers/usb/serial/Config.in Mon Mar 19 17:21:54 2001 @@ -14,6 +14,7 @@ dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL + dep_tristate ' USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL dep_tristate ' USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile --- v2.4.2/linux/drivers/usb/serial/Makefile Fri Dec 29 14:07:23 2000 +++ linux/drivers/usb/serial/Makefile Mon Mar 19 17:21:54 2001 @@ -17,6 +17,7 @@ obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o # Objects that export symbols. export-objs := usbserial.o diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c --- v2.4.2/linux/drivers/usb/serial/belkin_sa.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/belkin_sa.c Fri Mar 23 11:50:01 2001 @@ -24,7 +24,11 @@ * -- Add support for flush commands * -- Add everything that is missing :) * - * (11/06/2000) gkh + * 12-Mar-2001 gkh + * - Added support for the GoHubs GO-COM232 device which is the same as the + * Peracom device. + * + * 06-Nov-2000 gkh * - Added support for the old Belkin and Peracom devices. * - Made the port able to be opened multiple times. * - Added some defaults incase the line settings are things these devices @@ -90,6 +94,7 @@ { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) }, { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, { USB_DEVICE(PERACOM_VID, PERACOM_PID) }, + { USB_DEVICE(GOHUBS_VID, GOHUBS_PID) }, { } /* Terminating entry */ }; @@ -108,6 +113,11 @@ { } /* Terminating entry */ }; +static __devinitdata struct usb_device_id gocom232_table [] = { + { USB_DEVICE(GOHUBS_VID, GOHUBS_PID) }, + { } /* Terminating entry */ +}; + MODULE_DEVICE_TABLE (usb, id_table_combined); /* All of the device info needed for the Belkin serial converter */ @@ -174,6 +184,27 @@ shutdown: belkin_sa_shutdown, }; +/* the GoHubs Go-COM232 device is the same as the Peracom single port adapter */ +struct usb_serial_device_type gocom232_device = { + name: "GO-COM232 USB Serial Converter", + id_table: gocom232_table, /* the GO-COM232 device */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: belkin_sa_open, + close: belkin_sa_close, + read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ + ioctl: belkin_sa_ioctl, + set_termios: belkin_sa_set_termios, + break_ctl: belkin_sa_break_ctl, + startup: belkin_sa_startup, + shutdown: belkin_sa_shutdown, +}; + struct belkin_sa_private { unsigned long control_state; @@ -233,8 +264,8 @@ belkin_sa_close (&serial->port[i], NULL); } /* My special items, the standard routines free my urbs */ - if (serial->port->private) - kfree(serial->port->private); + if (serial->port[i].private) + kfree(serial->port[i].private); } } @@ -558,6 +589,7 @@ usb_serial_register (&belkin_sa_device); usb_serial_register (&belkin_old_device); usb_serial_register (&peracom_device); + usb_serial_register (&gocom232_device); return 0; } @@ -567,6 +599,7 @@ usb_serial_deregister (&belkin_sa_device); usb_serial_deregister (&belkin_old_device); usb_serial_deregister (&peracom_device); + usb_serial_deregister (&gocom232_device); } diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/belkin_sa.h linux/drivers/usb/serial/belkin_sa.h --- v2.4.2/linux/drivers/usb/serial/belkin_sa.h Sat Nov 11 18:51:18 2000 +++ linux/drivers/usb/serial/belkin_sa.h Tue Mar 20 14:02:46 2001 @@ -15,7 +15,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * - * (11/06/2000) gkh + * 12-Mar-2001 gkh + * Added GoHubs GO-COM232 device id. + * + * 06-Nov-2000 gkh * Added old Belkin and Peracom device ids, which this driver supports * * 12-Oct-2000 William Greathouse @@ -38,6 +41,9 @@ #define PERACOM_VID 0x0565 /* Peracom's vendor id */ #define PERACOM_PID 0x0001 /* Peracom's single port serial converter's id */ + +#define GOHUBS_VID 0x0921 /* GoHubs vendor id */ +#define GOHUBS_PID 0x0100 /* GoHubs single port serial converter's id (identical to the Peracom device) */ /* Vendor Request Interface */ #define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */ diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c --- v2.4.2/linux/drivers/usb/serial/digi_acceleport.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/digi_acceleport.c Tue Mar 20 14:02:46 2001 @@ -1282,12 +1282,10 @@ || priv->dp_write_urb_in_use ) { /* buffer data if count is 1 (probably put_char) if possible */ - if( count == 1 ) { - new_len = MIN( count, - DIGI_OUT_BUF_SIZE-priv->dp_out_buf_len ); - memcpy( priv->dp_out_buf+priv->dp_out_buf_len, buf, - new_len ); - priv->dp_out_buf_len += new_len; + if( count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE ) { + priv->dp_out_buf[priv->dp_out_buf_len++] + = *(from_user ? user_buf : buf); + new_len = 1; } else { new_len = 0; } diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c --- v2.4.2/linux/drivers/usb/serial/ftdi_sio.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/ftdi_sio.c Sun Mar 25 18:14:21 2001 @@ -228,7 +228,7 @@ priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ - err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private)); + err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private)); return -ENOMEM; } @@ -246,7 +246,7 @@ priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ - err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private)); + err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private)); return -ENOMEM; } diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_16654.h linux/drivers/usb/serial/io_16654.h --- v2.4.2/linux/drivers/usb/serial/io_16654.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_16654.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,195 @@ +/************************************************************************ + * + * 16654.H Definitions for 16C654 UART used on EdgePorts + * + * Copyright (c) 1998 Inside Out Networks, 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. + * + ************************************************************************/ + +#if !defined(_16654_H) +#define _16654_H + +/************************************************************************ + * + * D e f i n e s / T y p e d e f s + * + ************************************************************************/ + + // + // UART register numbers + // Numbers 0-7 are passed to the Edgeport directly. Numbers 8 and + // above are used internally to indicate that we must enable access + // to them via LCR bit 0x80 or LCR = 0xBF. + // The register number sent to the Edgeport is then (x & 0x7). + // + // Driver must not access registers that affect operation of the + // the EdgePort firmware -- that includes THR, RHR, IER, FCR. + + +#define THR 0 // ! Transmit Holding Register (Write) +#define RDR 0 // ! Receive Holding Register (Read) +#define IER 1 // ! Interrupt Enable Register +#define FCR 2 // ! Fifo Control Register (Write) +#define ISR 2 // Interrupt Status Register (Read) +#define LCR 3 // Line Control Register +#define MCR 4 // Modem Control Register +#define LSR 5 // Line Status Register +#define MSR 6 // Modem Status Register +#define SPR 7 // ScratchPad Register +#define DLL 8 // Bank2[ 0 ] Divisor Latch LSB +#define DLM 9 // Bank2[ 1 ] Divisor Latch MSB +#define EFR 10 // Bank2[ 2 ] Extended Function Register +//efine unused 11 // Bank2[ 3 ] +#define XON1 12 // Bank2[ 4 ] Xon-1 +#define XON2 13 // Bank2[ 5 ] Xon-2 +#define XOFF1 14 // Bank2[ 6 ] Xoff-1 +#define XOFF2 15 // Bank2[ 7 ] Xoff-2 + +#define NUM_16654_REGS 16 + +#define IS_REG_2ND_BANK(x) ((x) >= 8) + + // + // Bit definitions for each register + // + +#define IER_RX 0x01 // Enable receive interrupt +#define IER_TX 0x02 // Enable transmit interrupt +#define IER_RXS 0x04 // Enable receive status interrupt +#define IER_MDM 0x08 // Enable modem status interrupt +#define IER_SLEEP 0x10 // Enable sleep mode +#define IER_XOFF 0x20 // Enable s/w flow control (XOFF) interrupt +#define IER_RTS 0x40 // Enable RTS interrupt +#define IER_CTS 0x80 // Enable CTS interrupt +#define IER_ENABLE_ALL 0xFF // Enable all ints + + +#define FCR_FIFO_EN 0x01 // Enable FIFOs +#define FCR_RXCLR 0x02 // Reset Rx FIFO +#define FCR_TXCLR 0x04 // Reset Tx FIFO +#define FCR_DMA_BLK 0x08 // Enable DMA block mode +#define FCR_TX_LEVEL_MASK 0x30 // Mask for Tx FIFO Level +#define FCR_TX_LEVEL_8 0x00 // Tx FIFO Level = 8 bytes +#define FCR_TX_LEVEL_16 0x10 // Tx FIFO Level = 16 bytes +#define FCR_TX_LEVEL_32 0x20 // Tx FIFO Level = 32 bytes +#define FCR_TX_LEVEL_56 0x30 // Tx FIFO Level = 56 bytes +#define FCR_RX_LEVEL_MASK 0xC0 // Mask for Rx FIFO Level +#define FCR_RX_LEVEL_8 0x00 // Rx FIFO Level = 8 bytes +#define FCR_RX_LEVEL_16 0x40 // Rx FIFO Level = 16 bytes +#define FCR_RX_LEVEL_56 0x80 // Rx FIFO Level = 56 bytes +#define FCR_RX_LEVEL_60 0xC0 // Rx FIFO Level = 60 bytes + + +#define ISR_INT_MDM_STATUS 0x00 // Modem status int pending +#define ISR_INT_NONE 0x01 // No interrupt pending +#define ISR_INT_TXRDY 0x02 // Tx ready int pending +#define ISR_INT_RXRDY 0x04 // Rx ready int pending +#define ISR_INT_LINE_STATUS 0x06 // Line status int pending +#define ISR_INT_RX_TIMEOUT 0x0C // Rx timeout int pending +#define ISR_INT_RX_XOFF 0x10 // Rx Xoff int pending +#define ISR_INT_RTS_CTS 0x20 // RTS/CTS change int pending +#define ISR_FIFO_ENABLED 0xC0 // Bits set if FIFOs enabled +#define ISR_INT_BITS_MASK 0x3E // Mask to isolate valid int causes + + +#define LCR_BITS_5 0x00 // 5 bits/char +#define LCR_BITS_6 0x01 // 6 bits/char +#define LCR_BITS_7 0x02 // 7 bits/char +#define LCR_BITS_8 0x03 // 8 bits/char +#define LCR_BITS_MASK 0x03 // Mask for bits/char field + +#define LCR_STOP_1 0x00 // 1 stop bit +#define LCR_STOP_1_5 0x04 // 1.5 stop bits (if 5 bits/char) +#define LCR_STOP_2 0x04 // 2 stop bits (if 6-8 bits/char) +#define LCR_STOP_MASK 0x04 // Mask for stop bits field + +#define LCR_PAR_NONE 0x00 // No parity +#define LCR_PAR_ODD 0x08 // Odd parity +#define LCR_PAR_EVEN 0x18 // Even parity +#define LCR_PAR_MARK 0x28 // Force parity bit to 1 +#define LCR_PAR_SPACE 0x38 // Force parity bit to 0 +#define LCR_PAR_MASK 0x38 // Mask for parity field + +#define LCR_SET_BREAK 0x40 // Set Break condition +#define LCR_DL_ENABLE 0x80 // Enable access to divisor latch + +#define LCR_ACCESS_EFR 0xBF // Load this value to access DLL,DLM, + // and also the '654-only registers + // EFR, XON1, XON2, XOFF1, XOFF2 + + +#define MCR_DTR 0x01 // Assert DTR +#define MCR_RTS 0x02 // Assert RTS +#define MCR_OUT1 0x04 // Loopback only: Sets state of RI +#define MCR_MASTER_IE 0x08 // Enable interrupt outputs +#define MCR_LOOPBACK 0x10 // Set internal (digital) loopback mode +#define MCR_XON_ANY 0x20 // Enable any char to exit XOFF mode +#define MCR_IR_ENABLE 0x40 // Enable IrDA functions +#define MCR_BRG_DIV_4 0x80 // Divide baud rate clk by /4 instead of /1 + + +#define LSR_RX_AVAIL 0x01 // Rx data available +#define LSR_OVER_ERR 0x02 // Rx overrun +#define LSR_PAR_ERR 0x04 // Rx parity error +#define LSR_FRM_ERR 0x08 // Rx framing error +#define LSR_BREAK 0x10 // Rx break condition detected +#define LSR_TX_EMPTY 0x20 // Tx Fifo empty +#define LSR_TX_ALL_EMPTY 0x40 // Tx Fifo and shift register empty +#define LSR_FIFO_ERR 0x80 // Rx Fifo contains at least 1 erred char + + +#define MSR_DELTA_CTS 0x01 // CTS changed from last read +#define MSR_DELTA_DSR 0x02 // DSR changed from last read +#define MSR_DELTA_RI 0x04 // RI changed from 0 -> 1 +#define MSR_DELTA_CD 0x08 // CD changed from last read +#define MSR_CTS 0x10 // Current state of CTS +#define MSR_DSR 0x20 // Current state of DSR +#define MSR_RI 0x40 // Current state of RI +#define MSR_CD 0x80 // Current state of CD + + + + // Tx Rx + //------------------------------- +#define EFR_SWFC_NONE 0x00 // None None +#define EFR_SWFC_RX1 0x02 // None XOFF1 +#define EFR_SWFC_RX2 0x01 // None XOFF2 +#define EFR_SWFC_RX12 0x03 // None XOFF1 & XOFF2 +#define EFR_SWFC_TX1 0x08 // XOFF1 None +#define EFR_SWFC_TX1_RX1 0x0a // XOFF1 XOFF1 +#define EFR_SWFC_TX1_RX2 0x09 // XOFF1 XOFF2 +#define EFR_SWFC_TX1_RX12 0x0b // XOFF1 XOFF1 & XOFF2 +#define EFR_SWFC_TX2 0x04 // XOFF2 None +#define EFR_SWFC_TX2_RX1 0x06 // XOFF2 XOFF1 +#define EFR_SWFC_TX2_RX2 0x05 // XOFF2 XOFF2 +#define EFR_SWFC_TX2_RX12 0x07 // XOFF2 XOFF1 & XOFF2 +#define EFR_SWFC_TX12 0x0c // XOFF1 & XOFF2 None +#define EFR_SWFC_TX12_RX1 0x0e // XOFF1 & XOFF2 XOFF1 +#define EFR_SWFC_TX12_RX2 0x0d // XOFF1 & XOFF2 XOFF2 +#define EFR_SWFC_TX12_RX12 0x0f // XOFF1 & XOFF2 XOFF1 & XOFF2 + +#define EFR_TX_FC_MASK 0x0c // Mask to isolate Rx flow control +#define EFR_TX_FC_NONE 0x00 // No Tx Xon/Xoff flow control +#define EFR_TX_FC_X1 0x08 // Transmit Xon1/Xoff1 +#define EFR_TX_FC_X2 0x04 // Transmit Xon2/Xoff2 +#define EFR_TX_FC_X1_2 0x0c // Transmit Xon1&2/Xoff1&2 + +#define EFR_RX_FC_MASK 0x03 // Mask to isolate Rx flow control +#define EFR_RX_FC_NONE 0x00 // No Rx Xon/Xoff flow control +#define EFR_RX_FC_X1 0x02 // Receiver compares Xon1/Xoff1 +#define EFR_RX_FC_X2 0x01 // Receiver compares Xon2/Xoff2 +#define EFR_RX_FC_X1_2 0x03 // Receiver compares Xon1&2/Xoff1&2 + + +#define EFR_SWFC_MASK 0x0F // Mask for software flow control field +#define EFR_ENABLE_16654 0x10 // Enable 16C654 features +#define EFR_SPEC_DETECT 0x20 // Enable special character detect interrupt +#define EFR_AUTO_RTS 0x40 // Use RTS for Rx flow control +#define EFR_AUTO_CTS 0x80 // Use CTS for Tx flow control + +#endif // if !defined(_16654_H) + diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c --- v2.4.2/linux/drivers/usb/serial/io_edgeport.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_edgeport.c Sun Mar 25 18:24:31 2001 @@ -0,0 +1,3143 @@ +/* + * Edgeport USB Serial Converter driver + * + * Copyright(c) 2000 Inside Out Networks, All rights reserved. + * Copyright(c) 2001 Greg Kroah-Hartman + * + * 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. + * + * Supports the following devices: + * Edgeport/4 + * Edgeport/4t + * Edgeport/2 + * Edgeport/4i + * Edgeport/2i + * Edgeport/421 + * Edgeport/21 + * Rapidport/4 + * Edgeport/8 + * Edgeport/2D8 + * Edgeport/4D8 + * Edgeport/8i + * + * Version history: + * + * 2.0 2001_03_05 greg kroah-hartman + * - reworked entire driver to fit properly in with the other usb-serial + * drivers. Occasional oopses still happen, but it's a good start. + * + * 1.2.3 (02/23/2001) greg kroah-hartman + * - changed device table to work properly for 2.4.x final format. + * - fixed problem with dropping data at high data rates. + * + * 1.2.2 (11/27/2000) greg kroah-hartman + * - cleaned up more NTisms. + * - Added device table for 2.4.0-test11 + * + * 1.2.1 (11/08/2000) greg kroah-hartman + * - Started to clean up NTisms. + * - Fixed problem with dev field of urb for kernels >= 2.4.0-test9 + * + * 1.2 (10/17/2000) David Iacovelli + * Remove all EPIC code and GPL source + * Fix RELEVANT_IFLAG macro to include flow control + * changes port configuration changes. + * Fix redefinition of SERIAL_MAGIC + * Change all timeout values to 5 seconds + * Tried to fix the UHCI multiple urb submission, but failed miserably. + * it seems to work fine with OHCI. + * ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must + * find a way to work arount this UHCI bug ) + * + * 1.1 (10/11/2000) David Iacovelli + * Fix XON/XOFF flow control to support both IXON and IXOFF + * + * 0.9.27 (06/30/2000) David Iacovelli + * Added transmit queue and now allocate urb for command writes. + * + * 0.9.26 (06/29/2000) David Iacovelli + * Add support for 80251 based edgeport + * + * 0.9.25 (06/27/2000) David Iacovelli + * Do not close the port if it has multiple opens. + * + * 0.9.24 (05/26/2000) David Iacovelli + * Add IOCTLs to support RXTX and JAVA POS + * and first cut at running BlackBox Demo + * + * 0.9.23 (05/24/2000) David Iacovelli + * Add IOCTLs to support RXTX and JAVA POS + * + * 0.9.22 (05/23/2000) David Iacovelli + * fixed bug in enumeration. If epconfig turns on mapping by + * path after a device is already plugged in, we now update + * the mapping correctly + * + * 0.9.21 (05/16/2000) David Iacovelli + * Added BlockUntilChaseResp() to also wait for txcredits + * Updated the way we allocate and handle write URBs + * Add debug code to dump buffers + * + * 0.9.20 (05/01/2000) David Iacovelli + * change driver to use usb/tts/ + * + * 0.9.19 (05/01/2000) David Iacovelli + * Update code to compile if DEBUG is off + * + * 0.9.18 (04/28/2000) David Iacovelli + * cleanup and test tty_register with devfs + * + * 0.9.17 (04/27/2000) greg kroah-hartman + * changed tty_register around to be like the way it + * was before, but now it works properly with devfs. + * + * 0.9.16 (04/26/2000) david iacovelli + * Fixed bug in GetProductInfo() + * + * 0.9.15 (04/25/2000) david iacovelli + * Updated enumeration + * + * 0.9.14 (04/24/2000) david iacovelli + * Removed all config/status IOCTLS and + * converted to using /proc/edgeport + * still playing with devfs + * + * 0.9.13 (04/24/2000) david iacovelli + * Removed configuration based on ttyUSB0 + * Added support for configuration using /prod/edgeport + * first attempt at using devfs (not working yet!) + * Added IOCTL to GetProductInfo() + * Added support for custom baud rates + * Add support for random port numbers + * + * 0.9.12 (04/18/2000) david iacovelli + * added additional configuration IOCTLs + * use ttyUSB0 for configuration + * + * 0.9.11 (04/17/2000) greg kroah-hartman + * fixed module initialization race conditions. + * made all urbs dynamically allocated. + * made driver devfs compatible. now it only registers the tty device + * when the device is actually plugged in. + * + * 0.9.10 (04/13/2000) greg kroah-hartman + * added proc interface framework. + * + * 0.9.9 (04/13/2000) david iacovelli + * added enumeration code and ioctls to configure the device + * + * 0.9.8 (04/12/2000) david iacovelli + * Change interrupt read start when device is plugged in + * and stop when device is removed + * process interrupt reads when all ports are closed + * (keep value of rxBytesAvail consistent with the edgeport) + * set the USB_BULK_QUEUE flag so that we can shove a bunch + * of urbs at once down the pipe + * + * 0.9.7 (04/10/2000) david iacovelli + * start to add enumeration code. + * generate serial number for epic devices + * add support for kdb + * + * 0.9.6 (03/30/2000) david iacovelli + * add IOCTL to get string, manufacture, and boot descriptors + * + * 0.9.5 (03/14/2000) greg kroah-hartman + * more error checking added to SerialOpen to try to fix UHCI open problem + * + * 0.9.4 (03/09/2000) greg kroah-hartman + * added more error checking to handle oops when data is hanging + * around and tty is abruptly closed. + * + * 0.9.3 (03/09/2000) david iacovelli + * Add epic support for xon/xoff chars + * play with performance + * + * 0.9.2 (03/08/2000) greg kroah-hartman + * changed most "info" calls to "dbg" + * implemented flow control properly in the termios call + * + * 0.9.1 (03/08/2000) david iacovelli + * added EPIC support + * enabled bootloader update + * + * 0.9 (03/08/2000) greg kroah-hartman + * Release to IO networks. + * Integrated changes that David made + * made getting urbs for writing SMP safe + * + * 0.8 (03/07/2000) greg kroah-hartman + * Release to IO networks. + * Fixed problems that were seen in code by David. + * Now both Edgeport/4 and Edgeport/2 works properly. + * Changed most of the functions to use port instead of serial. + * + * 0.7 (02/27/2000) greg kroah-hartman + * Milestone 3 release. + * Release to IO Networks + * ioctl for waiting on line change implemented. + * ioctl for getting statistics implemented. + * multiport support working. + * lsr and msr registers are now handled properly. + * change break now hooked up and working. + * support for all known Edgeport devices. + * + * 0.6 (02/22/2000) greg kroah-hartman + * Release to IO networks. + * CHASE is implemented correctly when port is closed. + * SerialOpen now blocks correctly until port is fully opened. + * + * 0.5 (02/20/2000) greg kroah-hartman + * Release to IO networks. + * Known problems: + * modem status register changes are not sent on to the user + * CHASE is not implemented when the port is closed. + * + * 0.4 (02/16/2000) greg kroah-hartman + * Second cut at the CeBit demo. + * Doesn't leak memory on every write to the port + * Still small leaks on startup. + * Added support for Edgeport/2 and Edgeport/8 + * + * 0.3 (02/15/2000) greg kroah-hartman + * CeBit demo release. + * Force the line settings to 4800, 8, 1, e for the demo. + * Warning! This version leaks memory like crazy! + * + * 0.2 (01/30/2000) greg kroah-hartman + * Milestone 1 release. + * Device is found by USB subsystem, enumerated, fimware is downloaded + * and the descriptors are printed to the debug log, config is set, and + * green light starts to blink. Open port works, and data can be sent + * and received at the default settings of the UART. Loopback connector + * and debug log confirms this. + * + * 0.1 (01/23/2000) greg kroah-hartman + * Initial release to help IO Networks try to set up their test system. + * Edgeport4 is recognized, firmware is downloaded, config is set so + * device blinks green light every 3 sec. Port is bound, but opening, + * closing, and sending data do not work properly. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_USB_SERIAL_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif + +#include + +#include "usb-serial.h" + +#include "io_edgeport.h" +#include "io_ionsp.h" /* info for the iosp messages */ +#include "io_16654.h" /* 16654 UART defines */ + +/* First, the latest boot code - for first generation edgeports */ +#define IMAGE_ARRAY_NAME BootCodeImage_GEN1 +#define IMAGE_VERSION_NAME BootCodeImageVersion_GEN1 +#include "io_fw_boot.h" /* the bootloader firmware to download to a device, if it needs it */ + +/* for second generation edgeports */ +#define IMAGE_ARRAY_NAME BootCodeImage_GEN2 +#define IMAGE_VERSION_NAME BootCodeImageVersion_GEN2 +#include "io_fw_boot2.h" /* the bootloader firmware to download to a device, if it needs it */ + +/* Then finally the main run-time operational code - for first generation edgeports */ +#define IMAGE_ARRAY_NAME OperationalCodeImage_GEN1 +#define IMAGE_VERSION_NAME OperationalCodeImageVersion_GEN1 +#include "io_fw_down.h" /* Define array OperationalCodeImage[] */ + +/* for second generation edgeports */ +#define IMAGE_ARRAY_NAME OperationalCodeImage_GEN2 +#define IMAGE_VERSION_NAME OperationalCodeImageVersion_GEN2 +#include "io_fw_down2.h" /* Define array OperationalCodeImage[] */ + + +/* Module information */ +MODULE_AUTHOR("Greg Kroah-Hartman and David Iacovelli"); +MODULE_DESCRIPTION("Edgeport USB Serial Driver"); + +#define MAX_NAME_LEN 64 + + +#define CHASE_TIMEOUT (5*HZ) /* 5 seconds */ +#define OPEN_TIMEOUT (5*HZ) /* 5 seconds */ +#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */ + +#ifndef SERIAL_MAGIC + #define SERIAL_MAGIC 0x6702 +#endif +#define PORT_MAGIC 0x7301 + + +/* receive port state */ +enum RXSTATE { + EXPECT_HDR1 = 0, /* Expect header byte 1 */ + EXPECT_HDR2 = 1, /* Expect header byte 2 */ + EXPECT_DATA = 2, /* Expect 'RxBytesRemaining' data */ + EXPECT_HDR3 = 3, /* Expect header byte 3 (for status hdrs only) */ +}; + + +/* the info for all of the devices that this driver supports */ +int EdgeportDevices[] = EDGEPORT_DEVICE_IDS; +#define NUM_EDGEPORT_DEVICES (sizeof(EdgeportDevices) / sizeof(int)) + + +/* Transmit Fifo + * This Transmit queue is an extension of the edgeport Rx buffer. + * The maximum amount of data buffered in both the edgeport + * Rx buffer (maxTxCredits) and this buffer will never exceed maxTxCredits. + */ +struct TxFifo { + unsigned int head; /* index to head pointer (write) */ + unsigned int tail; /* index to tail pointer (read) */ + unsigned int count; /* Bytes in queue */ + unsigned int size; /* Max size of queue (equal to Max number of TxCredits) */ + unsigned char *fifo; /* allocated Buffer */ +}; + +/* This structure holds all of the local port information */ +struct edgeport_port { + __u16 txCredits; /* our current credits for this port */ + __u16 maxTxCredits; /* the max size of the port */ + + struct TxFifo txfifo; /* transmit fifo -- size will be maxTxCredits */ + struct urb *write_urb; /* write URB for this port */ + char write_in_progress; /* TRUE while a write URB is outstanding */ + + __u8 shadowLCR; /* last LCR value received */ + __u8 shadowMCR; /* last MCR value received */ + __u8 shadowMSR; /* last MSR value received */ + __u8 shadowLSR; /* last LSR value received */ + __u8 shadowXonChar; /* last value set as XON char in Edgeport */ + __u8 shadowXoffChar; /* last value set as XOFF char in Edgeport */ + __u8 validDataMask; + __u32 baudRate; + + char open; + char openPending; + char commandPending; + char closePending; + char chaseResponsePending; + + wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ + wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */ + wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */ + wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ + + struct async_icount icount; + struct usb_serial_port *port; /* loop back to the owner of this object */ +}; + + +/* This structure holds all of the individual device information */ +struct edgeport_serial { + char name[MAX_NAME_LEN+1]; /* string name of this device */ + + EDGE_MANUF_DESCRIPTOR manuf_descriptor; /* the manufacturer descriptor */ + EDGE_BOOT_DESCRIPTOR boot_descriptor; /* the boot firmware descriptor */ + struct edgeport_product_info product_info; /* Product Info */ + + __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */ + unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */ + struct urb * interrupt_read_urb; /* our interrupt urb */ + + __u8 bulk_in_endpoint; /* the bulk in endpoint handle */ + unsigned char * bulk_in_buffer; /* the buffer we use for the bulk in endpoint */ + struct urb * read_urb; /* our bulk read urb */ + + __u8 bulk_out_endpoint; /* the bulk out endpoint handle */ + + __s16 rxBytesAvail; /* the number of bytes that we need to read from this device */ + + enum RXSTATE rxState; /* the current state of the bulk receive processor */ + __u8 rxHeader1; /* receive header byte 1 */ + __u8 rxHeader2; /* receive header byte 2 */ + __u8 rxHeader3; /* receive header byte 3 */ + __u8 rxPort; /* the port that we are currently receiving data for */ + __u8 rxStatusCode; /* the receive status code */ + __u8 rxStatusParam; /* the receive status paramater */ + __s16 rxBytesRemaining; /* the number of port bytes left to read */ + struct usb_serial *serial; /* loop back to the owner of this object */ +}; + +/* baud rate information */ +typedef struct _DIVISOR_TABLE_ENTRY { + __u32 BaudRate; + __u16 Divisor; +} DIVISOR_TABLE_ENTRY, *PDIVISOR_TABLE_ENTRY; + +// +// Define table of divisors for Rev A EdgePort/4 hardware +// These assume a 3.6864MHz crystal, the standard /16, and +// MCR.7 = 0. +// +static DIVISOR_TABLE_ENTRY DivisorTable[] = { + { 75, 3072}, + { 110, 2095}, /* 2094.545455 => 230450 => .0217 % over */ + { 134, 1713}, /* 1713.011152 => 230398.5 => .00065% under */ + { 150, 1536}, + { 300, 768}, + { 600, 384}, + { 1200, 192}, + { 1800, 128}, + { 2400, 96}, + { 4800, 48}, + { 7200, 32}, + { 9600, 24}, + { 14400, 16}, + { 19200, 12}, + { 38400, 6}, + { 57600, 4}, + { 115200, 2}, + { 230400, 1}, +}; + +/* local variables */ +static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */ + + +/* local function prototypes */ + +/* function prototypes for all URB callbacks */ +static void edge_interrupt_callback (struct urb *urb); +static void edge_bulk_in_callback (struct urb *urb); +static void edge_bulk_out_data_callback (struct urb *urb); +static void edge_bulk_out_cmd_callback (struct urb *urb); + +/* function prototypes for the usbserial callbacks */ +static int edge_open (struct usb_serial_port *port, struct file *filp); +static void edge_close (struct usb_serial_port *port, struct file *filp); +static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +static int edge_write_room (struct usb_serial_port *port); +static int edge_chars_in_buffer (struct usb_serial_port *port); +static void edge_throttle (struct usb_serial_port *port); +static void edge_unthrottle (struct usb_serial_port *port); +static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); +static void edge_break (struct usb_serial_port *port, int break_state); +static int edge_startup (struct usb_serial *serial); +static void edge_shutdown (struct usb_serial *serial); + + +#include "io_tables.h" /* all of the devices that this driver supports */ + + +/* function prototypes for all of our local functions */ +static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); +static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3); +static void handle_new_msr (struct edgeport_port *edge_port, __u8 newMsr); +static void handle_new_lsr (struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data); +static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param); +static int calc_baud_rate_divisor (int baud_rate, int *divisor); +static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate); +static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios); +static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue); +static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int writeLength); +static void send_more_port_data (struct edgeport_serial *edge_serial, struct edgeport_port *edge_port); + +static int sram_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data); +static int rom_read (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data); +static int rom_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data); +static void get_manufacturing_desc (struct edgeport_serial *edge_serial); +static void get_boot_desc (struct edgeport_serial *edge_serial); +static void load_application_firmware (struct edgeport_serial *edge_serial); + + +static void unicode_to_ascii (char *string, short *unicode, int unicode_size); + +static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_descriptor **pRetDesc); + + + + + +#ifdef DEBUG + +/* Dump a buffer in HEX and Ascii */ +void DbgDisplayBuffer( void *pBuffer, __u32 Len ) +{ + char DisplayBuf[80]; + char * pStr = DisplayBuf; + __u8 *pBuf = pBuffer; + __u32 i; + __u8 d; + + while (Len) { + // Init for new line + memset( DisplayBuf, ' ', sizeof( DisplayBuf )); + DisplayBuf[79]=0; + pStr = DisplayBuf; + pStr[54] = '['; + pStr[71] = ']'; + + for ( i = 0; i < MIN(16, Len) ; i++ ) { + d = (__u8)(*pBuf >> 4); + pStr[(i*3)+0] = (char)((d < 10) ? d+'0' : d -10 + 'A'); + d = (__u8)(*pBuf & 0xf); + pStr[(i*3)+1] = (char)((d < 10) ? d+'0' : d -10 + 'A'); + + if (*pBuf > 31 && *pBuf < 127) + pStr[i+55]=*pBuf; + else + pStr[i+55]='.'; + + pBuf++; + } + Len -= i; + dbg("%s", DisplayBuf ); + } +} +#endif + + + +// ************************************************************************ +// ************************************************************************ +// ************************************************************************ +// ************************************************************************ + +// These functions should be in firmware.c + +/************************************************************************ + * * + * update_edgeport_E2PROM() Compare current versions of * + * Boot ROM and Manufacture * + * Descriptors with versions * + * embedded in this driver * + * * + ************************************************************************/ +void update_edgeport_E2PROM (struct edgeport_serial *edge_serial) +{ + __u32 BootCurVer; + __u32 BootNewVer; + __u8 BootMajorVersion; + __u8 BootMinorVersion; + __u16 BootBuildNumber; + __u8 *BootImage; + __u32 BootSize; + PEDGE_FIRMWARE_IMAGE_RECORD record; + unsigned char *firmware; + int response; + + + switch (edge_serial->product_info.iDownloadFile) { + case EDGE_DOWNLOAD_FILE_I930: + BootMajorVersion = BootCodeImageVersion_GEN1.MajorVersion; + BootMinorVersion = BootCodeImageVersion_GEN1.MinorVersion; + BootBuildNumber = BootCodeImageVersion_GEN1.BuildNumber; + BootImage = &BootCodeImage_GEN1[0]; + BootSize = sizeof( BootCodeImage_GEN1 ); + break; + + case EDGE_DOWNLOAD_FILE_80251: + BootMajorVersion = BootCodeImageVersion_GEN2.MajorVersion; + BootMinorVersion = BootCodeImageVersion_GEN2.MinorVersion; + BootBuildNumber = BootCodeImageVersion_GEN2.BuildNumber; + BootImage = &BootCodeImage_GEN2[0]; + BootSize = sizeof( BootCodeImage_GEN2 ); + break; + + default: + return; + } + + // Check Boot Image Version + BootCurVer = (edge_serial->boot_descriptor.MajorVersion << 24) + + (edge_serial->boot_descriptor.MinorVersion << 16) + + edge_serial->boot_descriptor.BuildNumber; + + BootNewVer = (BootMajorVersion << 24) + + (BootMinorVersion << 16) + + BootBuildNumber; + + dbg("Current Boot Image version %d.%d.%d", + edge_serial->boot_descriptor.MajorVersion, + edge_serial->boot_descriptor.MinorVersion, + edge_serial->boot_descriptor.BuildNumber); + + + if (BootNewVer > BootCurVer) { + dbg("**Update Boot Image from %d.%d.%d to %d.%d.%d", + edge_serial->boot_descriptor.MajorVersion, + edge_serial->boot_descriptor.MinorVersion, + edge_serial->boot_descriptor.BuildNumber, + BootMajorVersion, + BootMinorVersion, + BootBuildNumber); + + + dbg("Downloading new Boot Image"); + + firmware = BootImage; + + for (;;) { + record = (PEDGE_FIRMWARE_IMAGE_RECORD)firmware; + response = rom_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]); + if (response < 0) { + err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len); + break; + } + firmware += sizeof (EDGE_FIRMWARE_IMAGE_RECORD) + record->Len; + if (firmware >= &BootImage[BootSize]) { + break; + } + } + } else { + dbg("Boot Image -- already up to date"); + } +} + + +/************************************************************************ + * * + * Get string descriptor from device * + * * + ************************************************************************/ +static int get_string (struct usb_device *dev, int Id, char *string) +{ + struct usb_string_descriptor StringDesc; + struct usb_string_descriptor *pStringDesc; + + dbg(__FUNCTION__ " - USB String ID = %d", Id ); + + if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) { + return 0; + } + + pStringDesc = kmalloc (StringDesc.bLength, GFP_KERNEL); + + if (!pStringDesc) { + return 0; + } + + if (!usb_get_descriptor(dev, USB_DT_STRING, Id, pStringDesc, StringDesc.bLength )) { + kfree(pStringDesc); + return 0; + } + + unicode_to_ascii(string, pStringDesc->wData, pStringDesc->bLength/2-1); + + kfree(pStringDesc); + return strlen(string); +} + + +/************************************************************************ + * + * Get string descriptor from device + * + ************************************************************************/ +static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_descriptor **pRetDesc) +{ + struct usb_string_descriptor StringDesc; + struct usb_string_descriptor *pStringDesc; + + dbg(__FUNCTION__ " - USB String ID = %d", Id ); + + if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) { + return 0; + } + + pStringDesc = kmalloc (StringDesc.bLength, GFP_KERNEL); + + if (!pStringDesc) { + return -1; + } + + if (!usb_get_descriptor(dev, USB_DT_STRING, Id, pStringDesc, StringDesc.bLength )) { + kfree(pStringDesc); + return -1; + } + + *pRetDesc = pStringDesc; + return 0; +} + + + + +/************************************************************************ + * * + * * + ************************************************************************/ +static void get_product_info(struct edgeport_serial *edge_serial) +{ + struct edgeport_product_info *product_info = &edge_serial->product_info; + + memset (product_info, 0, sizeof(struct edgeport_product_info)); + + product_info->ProductId = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_GENERATION_2); + product_info->NumPorts = edge_serial->manuf_descriptor.NumPorts; + product_info->ProdInfoVer = 0; + + product_info->RomSize = edge_serial->manuf_descriptor.RomSize; + product_info->RamSize = edge_serial->manuf_descriptor.RamSize; + product_info->CpuRev = edge_serial->manuf_descriptor.CpuRev; + product_info->BoardRev = edge_serial->manuf_descriptor.BoardRev; + + product_info->BootMajorVersion = edge_serial->boot_descriptor.MajorVersion; + product_info->BootMinorVersion = edge_serial->boot_descriptor.MinorVersion; + product_info->BootBuildNumber = edge_serial->boot_descriptor.BuildNumber; + + memcpy(product_info->ManufactureDescDate, edge_serial->manuf_descriptor.DescDate, sizeof(edge_serial->manuf_descriptor.DescDate)); + + // check if this is 2nd generation hardware + if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_GENERATION_2) { + product_info->FirmwareMajorVersion = OperationalCodeImageVersion_GEN2.MajorVersion; + product_info->FirmwareMinorVersion = OperationalCodeImageVersion_GEN2.MinorVersion; + product_info->FirmwareBuildNumber = OperationalCodeImageVersion_GEN2.BuildNumber; + product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_80251; + } else { + product_info->FirmwareMajorVersion = OperationalCodeImageVersion_GEN1.MajorVersion; + product_info->FirmwareMinorVersion = OperationalCodeImageVersion_GEN1.MinorVersion; + product_info->FirmwareBuildNumber = OperationalCodeImageVersion_GEN1.BuildNumber; + product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_I930; + } + + // Determine Product type and set appropriate flags + switch (DEVICE_ID_FROM_USB_PRODUCT_ID(product_info->ProductId)) { + case ION_DEVICE_ID_EDGEPORT_COMPATIBLE: + case ION_DEVICE_ID_EDGEPORT_4T: + case ION_DEVICE_ID_EDGEPORT_4: + case ION_DEVICE_ID_EDGEPORT_2: + case ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU: + case ION_DEVICE_ID_EDGEPORT_8: + case ION_DEVICE_ID_EDGEPORT_421: + case ION_DEVICE_ID_EDGEPORT_21: + case ION_DEVICE_ID_EDGEPORT_2_DIN: + case ION_DEVICE_ID_EDGEPORT_4_DIN: + case ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU: + product_info->IsRS232 = 1; + break; + + case ION_DEVICE_ID_EDGEPORT_2I: // Edgeport/2 RS422/RS485 + product_info->IsRS422 = 1; + product_info->IsRS485 = 1; + break; + + case ION_DEVICE_ID_EDGEPORT_8I: // Edgeport/4 RS422 + case ION_DEVICE_ID_EDGEPORT_4I: // Edgeport/4 RS422 + product_info->IsRS422 = 1; + break; + } + +#ifdef DEBUG + // Dump Product Info structure + dbg("**Product Information:"); + dbg(" ProductId %x", product_info->ProductId ); + dbg(" NumPorts %d", product_info->NumPorts ); + dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); + dbg(" IsServer %d", product_info->IsServer); + dbg(" IsRS232 %d", product_info->IsRS232 ); + dbg(" IsRS422 %d", product_info->IsRS422 ); + dbg(" IsRS485 %d", product_info->IsRS485 ); + dbg(" RomSize %d", product_info->RomSize ); + dbg(" RamSize %d", product_info->RamSize ); + dbg(" CpuRev %x", product_info->CpuRev ); + dbg(" BoardRev %x", product_info->BoardRev); + dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, + product_info->BootMinorVersion, + product_info->BootBuildNumber); + dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, + product_info->FirmwareMinorVersion, + product_info->FirmwareBuildNumber); + dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], + product_info->ManufactureDescDate[1], + product_info->ManufactureDescDate[2]+1900); + dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + +#endif +} + + +/************************************************************************/ +/************************************************************************/ +/* U S B C A L L B A C K F U N C T I O N S */ +/* U S B C A L L B A C K F U N C T I O N S */ +/************************************************************************/ +/************************************************************************/ + +/***************************************************************************** + * edge_interrupt_callback + * this is the callback function for when we have received data on the + * interrupt endpoint. + *****************************************************************************/ +static void edge_interrupt_callback (struct urb *urb) +{ + struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context; + struct edgeport_port *edge_port; + struct usb_serial_port *port; + unsigned char *data = urb->transfer_buffer; + int length = urb->actual_length; + int bytes_avail; + int position; + int txCredits; + int portNumber; + int result; + + dbg(__FUNCTION__); + + if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) { + return; + } + + if (urb->status) { + dbg(__FUNCTION__" - nonzero control read status received: %d", urb->status); + return; + } + + // process this interrupt-read even if there are no ports open + if (length) { +#ifdef DEBUG + int i; + printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, data = ", length); + for (i = 0; i < length; ++i) { + printk ("%.2x ", data[i]); + } + printk ("\n"); +#endif + + if (length > 1) { + bytes_avail = data[0] | (data[1] << 8); + if (bytes_avail) { + edge_serial->rxBytesAvail += bytes_avail; + dbg(__FUNCTION__" - bytes_avail = %d, rxBytesAvail %d", bytes_avail, edge_serial->rxBytesAvail); + + if ((edge_serial->rxBytesAvail > 0) && + (edge_serial->read_urb->status != -EINPROGRESS)) { + dbg(" --- Posting a read"); + + /* we have pending bytes on the bulk in pipe, send a request */ + edge_serial->read_urb->dev = edge_serial->serial->dev; + result = usb_submit_urb(edge_serial->read_urb); + if (result) { + dbg(__FUNCTION__" - usb_submit_urb(read bulk) failed with result = %d", result); + } + } + } + } + /* grab the txcredits for the ports if available */ + position = 2; + portNumber = 0; + while ((position < length) && (portNumber < edge_serial->serial->num_ports)) { + txCredits = data[position] | (data[position+1] << 8); + if (txCredits) { + port = &edge_serial->serial->port[portNumber]; + if (port_paranoia_check (port, __FUNCTION__) == 0) { + edge_port = (struct edgeport_port *)port->private; + if (edge_port->open) { + edge_port->txCredits += txCredits; + dbg(__FUNCTION__" - txcredits for port%d = %d", portNumber, edge_port->txCredits); + + /* tell the tty driver that something has changed */ + wake_up_interruptible(&edge_port->port->tty->write_wait); + + // Since we have more credit, check if more data can be sent + send_more_port_data(edge_serial, edge_port); + } + } + } + position += 2; + ++portNumber; + } + } +} + + +/***************************************************************************** + * edge_bulk_in_callback + * this is the callback function for when we have received data on the + * bulk in endpoint. + *****************************************************************************/ +static void edge_bulk_in_callback (struct urb *urb) +{ + struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context; + unsigned char *data = urb->transfer_buffer; + int status; + __u16 raw_data_length; + + dbg(__FUNCTION__); + + if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) { + return; + } + + if (urb->status) { + dbg(__FUNCTION__" - nonzero read bulk status received: %d", urb->status); + return; + } + + if (urb->actual_length) { + raw_data_length = urb->actual_length; + +#ifdef DEBUG + { +// int i; + dbg (__FUNCTION__" - length = %d, data = ", raw_data_length); +// DbgDisplayBuffer((void *)data, raw_data_length); + } +#endif + + /* decrement our rxBytes available by the number that we just got */ + edge_serial->rxBytesAvail -= raw_data_length; + + dbg(__FUNCTION__" - Received = %d, rxBytesAvail %d", raw_data_length, edge_serial->rxBytesAvail); + + process_rcvd_data (edge_serial, data, urb->actual_length); + + /* check to see if there's any more data for us to read */ + if ((edge_serial->rxBytesAvail > 0) && + (edge_serial->read_urb->status != -EINPROGRESS)) { + dbg(" --- Posting a read"); + + /* there is, so resubmit our urb */ + edge_serial->read_urb->dev = edge_serial->serial->dev; + status = usb_submit_urb(edge_serial->read_urb); + if (status) { + err(__FUNCTION__" - usb_submit_urb(read bulk) failed, status = %d", status); + } + } + } +} + + +/***************************************************************************** + * edge_bulk_out_data_callback + * this is the callback function for when we have finished sending serial data + * on the bulk out endpoint. + *****************************************************************************/ +static void edge_bulk_out_data_callback (struct urb *urb) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; + struct tty_struct *tty; + + dbg(__FUNCTION__); + + if (port_paranoia_check (edge_port->port, __FUNCTION__)) { + return; + } + + if (urb->status) { + dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status); + } + + tty = edge_port->port->tty; + + /* let the tty driver wakeup if it has a special write_wakeup function */ + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { + (tty->ldisc.write_wakeup)(tty); + } + + /* tell the tty driver that something has changed */ + wake_up_interruptible(&tty->write_wait); + + // Release the Write URB + edge_port->write_in_progress = FALSE; + + // Check if more data needs to be sent + send_more_port_data((struct edgeport_serial *)(edge_port->port->serial->private), edge_port); +} + + +/***************************************************************************** + * BulkOutCmdCallback + * this is the callback function for when we have finished sending a command + * on the bulk out endpoint. + *****************************************************************************/ +static void edge_bulk_out_cmd_callback (struct urb *urb) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; + struct tty_struct *tty; + int status = urb->status; + + dbg(__FUNCTION__); + +#ifdef DEBUG + CmdUrbs--; + dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs); +#endif + + + /* if this urb had a transfer buffer already (old transfer) free it */ + if (urb->transfer_buffer != NULL) { + kfree(urb->transfer_buffer); + } + + // Free the command urb + usb_unlink_urb (urb); + usb_free_urb (urb); + + if (port_paranoia_check (edge_port->port, __FUNCTION__)) { + return; + } + + if (status) { + dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status); + return; + } + + /* Get pointer to tty */ + tty = edge_port->port->tty; + + /* tell the tty driver that something has changed */ + wake_up_interruptible(&tty->write_wait); + + + /* we have completed the command */ + edge_port->commandPending = FALSE; + wake_up_interruptible(&edge_port->wait_command); +} + + +/***************************************************************************** + * Driver tty interface functions + *****************************************************************************/ + +/***************************************************************************** + * SerialOpen + * this function is called by the tty driver when a port is opened + * If successful, we return 0 + * Otherwise we return a negative error number. + *****************************************************************************/ +static int edge_open (struct usb_serial_port *port, struct file * filp) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)port->private; + struct usb_serial *serial; + struct edgeport_serial *edge_serial; + int response; + int timeout; + + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; + + dbg(__FUNCTION__ " - port %d", port->number); + + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + port->active = 1; + + /* force low_latency on so that our tty_push actually forces the data through, + otherwise it is scheduled, and with high data rates (like with OHCI) data + can get lost. */ + port->tty->low_latency = 1; + + /* see if we've set up our endpoint info yet (can't set it up in edge_startup + as the structures were not set up at that time.) */ + serial = port->serial; + edge_serial = (struct edgeport_serial *)serial->private; + if (edge_serial->interrupt_in_buffer == NULL) { + struct usb_serial_port *port0 = &serial->port[0]; + + /* not set up yet, so do it now */ + edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer; + edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress; + edge_serial->interrupt_read_urb = port0->interrupt_in_urb; + edge_serial->bulk_in_buffer = port0->bulk_in_buffer; + edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress; + edge_serial->read_urb = port0->read_urb; + edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress; + + /* set up our interrupt urb */ + /* Like to use FILL_INT_URB, but we don't know wMaxPacketSize or bInterval, something to change for 2.5... */ + edge_serial->interrupt_read_urb->complete = edge_interrupt_callback; + edge_serial->interrupt_read_urb->context = edge_serial; + /* FILL_INT_URB(edge_serial->interrupt_read_urb, serial->dev, + usb_rcvintpipe (serial->dev, edge_serial->interrupt_in_endpoint), + edge_serial->interrupt_in_buffer, edge_serial->interrupt_in_endpoint.wMaxPacketSize, + edge_interrupt_callback, edge_serial, edge_serial->interrupt_in_endpoint.bInterval); + */ + + /* set up our bulk in urb */ + /* Like to use FILL_BULK_URB, but we don't know wMaxPacketSize or bInterval, something to change for 2.5... */ + edge_serial->read_urb->complete = edge_bulk_in_callback; + edge_serial->read_urb->context = edge_serial; + /* FILL_BULK_URB(edge_serial->read_urb, serial->dev, + usb_rcvbulkpipe (serial->dev, edge_serial->bulk_in_endpoint), + edge_serial->bulk_in_buffer, edge_serial->bulk_in_endpoint->wMaxPacketSize, + edge_bulk_in_callback, edge_serial); + */ + + /* start interrupt read for this edgeport + * this interrupt will continue as long as the edgeport is connected */ + response = usb_submit_urb (edge_serial->interrupt_read_urb); + if (response) { + err(__FUNCTION__" - Error %d submitting control urb", response); + } + } + + /* initialize our wait queues */ + init_waitqueue_head(&edge_port->wait_open); + init_waitqueue_head(&edge_port->wait_chase); + init_waitqueue_head(&edge_port->delta_msr_wait); + init_waitqueue_head(&edge_port->wait_command); + + /* initialize our icount structure */ + memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount)); + + /* initialize our port settings */ + edge_port->txCredits = 0; /* Can't send any data yet */ + edge_port->shadowMCR = MCR_MASTER_IE; /* Must always set this bit to enable ints! */ + edge_port->chaseResponsePending = FALSE; + + /* send a open port command */ + edge_port->openPending = TRUE; + edge_port->open = FALSE; + response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0); + + if (response < 0) { + err(__FUNCTION__" - error sending open port command"); + edge_port->openPending = FALSE; + port->active = 0; + port->open_count = 0; + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + /* now wait for the port to be completly opened */ + timeout = OPEN_TIMEOUT; + while (timeout && edge_port->openPending == TRUE) { + timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout); + } + + if (edge_port->open == FALSE) { + /* open timed out */ + dbg(__FUNCTION__" - open timedout"); + edge_port->openPending = FALSE; + port->active = 0; + port->open_count = 0; + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + /* create the txfifo */ + edge_port->txfifo.head = 0; + edge_port->txfifo.tail = 0; + edge_port->txfifo.count = 0; + edge_port->txfifo.size = edge_port->maxTxCredits; + edge_port->txfifo.fifo = kmalloc (edge_port->maxTxCredits, GFP_KERNEL); + + if (!edge_port->txfifo.fifo) { + dbg(__FUNCTION__" - no memory"); + edge_close (port, filp); + return -ENOMEM; + } + + /* Allocate a URB for the write */ + edge_port->write_urb = usb_alloc_urb (0); + + if (!edge_port->write_urb) { + dbg(__FUNCTION__" - no memory"); + edge_close (port, filp); + return -ENOMEM; + } + + dbg(__FUNCTION__"(%d) - Initialize TX fifo to %d bytes", port->number, edge_port->maxTxCredits); + } + + dbg(__FUNCTION__" exited"); + + return 0; +} + + +/************************************************************************ + * + * block_until_chase_response + * + * This function will block the close until one of the following: + * 1. Response to our Chase comes from Edgeport + * 2. A timout of 10 seconds without activity has expired + * (1K of Edgeport data @ 2400 baud ==> 4 sec to empty) + * + ************************************************************************/ +static void block_until_chase_response(struct edgeport_port *edge_port) +{ + __u16 lastCredits; + int timeout = 1*HZ; + int wait = 10; + + while (1) { + // Save Last credits + lastCredits = edge_port->txCredits; + + // Did we get our Chase response + if (edge_port->chaseResponsePending == FALSE) { + dbg(__FUNCTION__" - Got Chase Response"); + + // did we get all of our credit back? + if (edge_port->txCredits == edge_port->maxTxCredits ) { + dbg(__FUNCTION__" - Got all credits"); + return; + } + } + + // Block the thread for a while + interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout); + + if (lastCredits == edge_port->txCredits) { + // No activity.. count down. + wait--; + if (wait == 0) { + edge_port->chaseResponsePending = FALSE; + dbg(__FUNCTION__" - Chase TIMEOUT"); + return; + } + } else { + // Reset timout value back to 10 seconds + dbg(__FUNCTION__" - Last %d, Current %d", lastCredits, edge_port->txCredits); + wait = 10; + } + } +} + + +/************************************************************************ + * + * block_until_tx_empty + * + * This function will block the close until one of the following: + * 1. TX count are 0 + * 2. The edgeport has stopped + * 3. A timout of 3 seconds without activity has expired + * + ************************************************************************/ +static void block_until_tx_empty (struct edgeport_port *edge_port) +{ + struct TxFifo *fifo = &edge_port->txfifo; + __u32 lastCount; + int timeout = HZ/10; + int wait = 30; + + while (1) { + // Save Last count + lastCount = fifo->count; + + // Is the Edgeport Buffer empty? + if (lastCount == 0) { + dbg(__FUNCTION__" - TX Buffer Empty"); + return; + } + + // Block the thread for a while + interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout); + + dbg(__FUNCTION__ " wait"); + + if (lastCount == fifo->count) { + // No activity.. count down. + wait--; + if (wait == 0) { + dbg(__FUNCTION__" - TIMEOUT"); + return; + } + } else { + // Reset timout value back to seconds + wait = 30; + } + } +} + + +/***************************************************************************** + * edge_close + * this function is called by the tty driver when a port is closed + *****************************************************************************/ +static void edge_close (struct usb_serial_port *port, struct file * filp) +{ + struct usb_serial *serial; + struct edgeport_serial *edge_serial; + struct edgeport_port *edge_port; + int status; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return; + + edge_serial = (struct edgeport_serial *)serial->private; + edge_port = (struct edgeport_port *)port->private; + + --port->open_count; + + if (port->open_count <= 0) { + // block until tx is empty + block_until_tx_empty(edge_port); + + edge_port->closePending = TRUE; + + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; + + dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT"); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } + + /* close the port */ + dbg(__FUNCTION__" - Sending IOSP_CMD_CLOSE_PORT"); + send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + + //port->close = TRUE; + edge_port->closePending = FALSE; + edge_port->open = FALSE; + edge_port->openPending = FALSE; + + if (edge_port->write_urb) { + /* if this urb had a transfer buffer already (old transfer) free it */ + if (edge_port->write_urb->transfer_buffer != NULL) { + kfree(edge_port->write_urb->transfer_buffer); + } + + usb_unlink_urb (edge_port->write_urb); + usb_free_urb (edge_port->write_urb); + } + + if (edge_port->txfifo.fifo) { + kfree(edge_port->txfifo.fifo); + } + } + + MOD_DEC_USE_COUNT; + dbg(__FUNCTION__" exited"); +} + + + + +/***************************************************************************** + * SerialWrite + * this function is called by the tty driver when data should be written to + * the port. + * If successful, we return the number of bytes written, otherwise we return + * a negative error number. + *****************************************************************************/ +static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)port->private; + struct TxFifo *fifo; + int copySize; + int bytesleft; + int firsthalf; + int secondhalf; + + dbg(__FUNCTION__ " - port %d", port->number); + + // get a pointer to the Tx fifo + fifo = &edge_port->txfifo; + + // calculate number of bytes to put in fifo + copySize = MIN(count, (edge_port->txCredits - fifo->count)); + + dbg(__FUNCTION__"(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", + port->number, count, edge_port->txCredits - fifo->count, copySize); + + /* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */ + if (copySize == 0) { + dbg (__FUNCTION__" - copySize = Zero"); + return 0; + } + + // queue the data + // since we can never overflow the buffer we do not have to check for full condition + + // the copy is done is two parts -- first fill to the end of the buffer + // then copy the reset from the start of the buffer + + bytesleft = fifo->size - fifo->head; + firsthalf = MIN(bytesleft,copySize); + dbg (__FUNCTION__" - copy %d bytes of %d into fifo ", firsthalf, bytesleft); + + /* now copy our data */ + if (from_user) { + copy_from_user(&fifo->fifo[fifo->head], data, firsthalf); + } else { + memcpy(&fifo->fifo[fifo->head], data, firsthalf); + } + + // update the index and size + fifo->head += firsthalf; + fifo->count += firsthalf; + + // wrap the index + if (fifo->head == fifo->size) { + fifo->head = 0; + } + + secondhalf = copySize-firsthalf; + + if (secondhalf) { + dbg (__FUNCTION__" - copy rest of data %d", secondhalf); + if (from_user) { + copy_from_user(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf); + } else { + memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf); + } + // update the index and size + fifo->count += secondhalf; + fifo->head += secondhalf; + // No need to check for wrap since we can not get to end of fifo in this part + } + +#ifdef DEBUG + if (copySize) { + dbg (__FUNCTION__" - length = %d, data = ", copySize); + DbgDisplayBuffer((void *)data, copySize); + } +#endif + + send_more_port_data((struct edgeport_serial *)port->serial->private, edge_port); + + dbg(__FUNCTION__" wrote %d byte(s) TxCredits %d, Fifo %d", copySize, edge_port->txCredits, fifo->count); + + return copySize; +} + + +/************************************************************************ + * + * send_more_port_data() + * + * This routine attempts to write additional UART transmit data + * to a port over the USB bulk pipe. It is called (1) when new + * data has been written to a port's TxBuffer from higher layers + * (2) when the peripheral sends us additional TxCredits indicating + * that it can accept more Tx data for a given port; and (3) when + * a bulk write completes successfully and we want to see if we + * can transmit more. + * + ************************************************************************/ +static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port) +{ + struct TxFifo *fifo = &edge_port->txfifo; + struct urb *urb; + unsigned char *buffer; + int status; + unsigned long flags; + int count; + int bytesleft; + int firsthalf; + int secondhalf; + + dbg(__FUNCTION__"(%d)", edge_port->port->number); + + /* find our next free urb */ // ICK!!! FIXME!!! + save_flags(flags); cli(); + + if (edge_port->write_in_progress || + !edge_port->open || + (fifo->count == 0)) { + restore_flags(flags); + dbg(__FUNCTION__"(%d) EXIT - fifo %d, PendingWrite = %d", edge_port->port->number, fifo->count, edge_port->write_in_progress); + return; + } + + // since the amount of data in the fifo will always fit into the + // edgeport buffer we do not need to check the write length + + // Do we have enough credits for this port to make it worthwhile + // to bother queueing a write. If it's too small, say a few bytes, + // it's better to wait for more credits so we can do a larger + // write. + if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) { + restore_flags(flags); + dbg(__FUNCTION__"(%d) Not enough credit - fifo %d TxCredit %d", edge_port->port->number, fifo->count, edge_port->txCredits ); + return; + } + + // lock this write + edge_port->write_in_progress = TRUE; + restore_flags(flags); + + // get a pointer to the write_urb + urb = edge_port->write_urb; + + /* if this urb had a transfer buffer already (old transfer) free it */ + if (urb->transfer_buffer != NULL) { + kfree(urb->transfer_buffer); + urb->transfer_buffer = NULL; + } + + /* build the data header for the buffer and port that we are about to send out */ + count = fifo->count; + buffer = kmalloc (count+2, GFP_KERNEL); + if (buffer == NULL) { + err(__FUNCTION__" - no more kernel memory..."); + edge_port->write_in_progress = FALSE; + return; + } + buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number, count); + buffer[1] = IOSP_BUILD_DATA_HDR2 (edge_port->port->number, count); + + /* now copy our data */ + bytesleft = fifo->size - fifo->tail; + firsthalf = MIN(bytesleft,count); + memcpy(&buffer[2], &fifo->fifo[fifo->tail], firsthalf); + fifo->tail += firsthalf; + fifo->count -= firsthalf; + if (fifo->tail == fifo->size) { + fifo->tail = 0; + } + + secondhalf = count-firsthalf; + if (secondhalf) { + memcpy(&buffer[2+firsthalf], &fifo->fifo[fifo->tail], secondhalf); + fifo->tail += secondhalf; + fifo->count -= secondhalf; + } + +#ifdef DEBUG + if (count) { + dbg (__FUNCTION__" - length = %d, data = ", count); + DbgDisplayBuffer((void *)&buffer[2], count); + } +#endif + + /* fill up the urb with all of our data and submit it */ + FILL_BULK_URB (urb, edge_serial->serial->dev, + usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint), + buffer, count+2, edge_bulk_out_data_callback, edge_port); + + /* set the USB_BULK_QUEUE flag so that we can shove a bunch of urbs at once down the pipe */ + urb->transfer_flags |= USB_QUEUE_BULK; + + urb->dev = edge_serial->serial->dev; + status = usb_submit_urb(urb); + if (status) { + /* something went wrong */ + dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed"); + edge_port->write_in_progress = FALSE; + } else { + /* decrement the number of credits we have by the number we just sent */ + edge_port->txCredits -= count; + edge_port->icount.tx += count; + } + dbg(__FUNCTION__" wrote %d byte(s) TxCredit %d, Fifo %d", count, edge_port->txCredits, fifo->count); +} + + +/***************************************************************************** + * edge_write_room + * this function is called by the tty driver when it wants to know how many + * bytes of data we can accept for a specific port. + * If successful, we return the amount of room that we have for this port + * (the txCredits), + * Otherwise we return a negative error number. + *****************************************************************************/ +static int edge_write_room (struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + int room; + + dbg(__FUNCTION__); + + if (edge_port->closePending == TRUE) { + return -ENODEV; + } + + dbg(__FUNCTION__" - port %d", port->number); + + if (!edge_port->open) { + dbg (__FUNCTION__" - port not opened"); + return -EINVAL; + } + + // total of both buffers is still txCredit + room = edge_port->txCredits - edge_port->txfifo.count; + + dbg(__FUNCTION__" - returns %d", room); + return room; +} + + +/***************************************************************************** + * edge_chars_in_buffer + * this function is called by the tty driver when it wants to know how many + * bytes of data we currently have outstanding in the port (data that has + * been written, but hasn't made it out the port yet) + * If successful, we return the number of bytes left to be written in the + * system, + * Otherwise we return a negative error number. + *****************************************************************************/ +static int edge_chars_in_buffer (struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + int num_chars; + + dbg(__FUNCTION__); + + if (!edge_port->open) { + dbg (__FUNCTION__" - port not opened"); + return -EINVAL; + } + + num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count; + if (num_chars) { + dbg(__FUNCTION__"(port %d) - returns %d", port->number, num_chars); + } + + return num_chars; +} + + +/***************************************************************************** + * SerialThrottle + * this function is called by the tty driver when it wants to stop the data + * being read from the port. + *****************************************************************************/ +static void edge_throttle (struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + struct tty_struct *tty; + int status; + + dbg(__FUNCTION__" - port %d", port->number); + + if (!edge_port->open) { + dbg (__FUNCTION__" - port not opened"); + return; + } + + tty = port->tty; + + /* if we are implementing XON/XOFF, send the stop character */ + if (I_IXOFF(tty)) { + unsigned char stop_char = STOP_CHAR(tty); + status = edge_write (port, 0, &stop_char, 1); + if (status <= 0) { + return; + } + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + edge_port->shadowMCR &= ~MCR_RTS; + status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); + if (status != 0) { + return; + } + } + + return; +} + + +/***************************************************************************** + * edge_unthrottle + * this function is called by the tty driver when it wants to resume the data + * being read from the port (called after SerialThrottle is called) + *****************************************************************************/ +static void edge_unthrottle (struct usb_serial_port *port) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + struct tty_struct *tty; + int status; + + dbg(__FUNCTION__" - port %d", port->number); + + if (!edge_port->open) { + dbg (__FUNCTION__" - port not opened"); + return; + } + + tty = port->tty; + + /* if we are implementing XON/XOFF, send the start character */ + if (I_IXOFF(tty)) { + unsigned char start_char = START_CHAR(tty); + status = edge_write (port, 0, &start_char, 1); + if (status <= 0) { + return; + } + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + edge_port->shadowMCR |= MCR_RTS; + status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); + if (status != 0) { + return; + } + } + + return; +} + + +/***************************************************************************** + * SerialSetTermios + * this function is called by the tty driver when it wants to change the termios structure + *****************************************************************************/ +static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + struct tty_struct *tty = port->tty; + unsigned int cflag = tty->termios->c_cflag; + + dbg(__FUNCTION__" - clfag %08x %08x iflag %08x %08x", + tty->termios->c_cflag, + old_termios->c_cflag, + RELEVANT_IFLAG(tty->termios->c_iflag), + RELEVANT_IFLAG(old_termios->c_iflag) + ); + + /* check that they really want us to change something */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg(__FUNCTION__" - nothing to change"); + return; + } + } + + dbg(__FUNCTION__" - port %d", port->number); + + if (!edge_port->open) { + dbg (__FUNCTION__" - port not opened"); + return; + } + + /* change the port settings to the new ones specified */ + change_port_settings (edge_port, old_termios); + + return; +} + + +/***************************************************************************** + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + *****************************************************************************/ +static int get_lsr_info(struct edgeport_port *edge_port, unsigned int *value) +{ + unsigned int result = 0; + + if (edge_port->maxTxCredits == edge_port->txCredits && + edge_port->txfifo.count == 0) { + dbg(__FUNCTION__" -- Empty"); + result = TIOCSER_TEMT; + } + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +static int get_number_bytes_avail(struct edgeport_port *edge_port, unsigned int *value) +{ + unsigned int result = 0; + struct tty_struct *tty = edge_port->port->tty; + + result = tty->read_cnt; + + dbg(__FUNCTION__"(%d) = %d", edge_port->port->number, result); + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + //return 0; + return -ENOIOCTLCMD; +} + +static int set_modem_info(struct edgeport_port *edge_port, unsigned int *value) +{ + unsigned int mcr = edge_port->shadowMCR; + unsigned int arg; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + // turn off the RTS and DTR + mcr &= ~(MCR_RTS | MCR_DTR); + + mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0); + mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0); + + edge_port->shadowMCR = mcr; + + send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); + + return 0; +} + +static int get_modem_info(struct edgeport_port *edge_port, unsigned int *value) +{ + unsigned int result = 0; + unsigned int msr = edge_port->shadowMSR; + unsigned int mcr = edge_port->shadowMCR; + + result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ + | ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ + | ((msr & MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ + | ((msr & MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ + | ((msr & MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ + | ((msr & MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ + + + dbg(__FUNCTION__" -- %x", result); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + + + +static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + tmp.type = PORT_16550A; + tmp.line = edge_port->port->serial->minor; + tmp.port = edge_port->port->number; + tmp.irq = 0; + tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; + tmp.xmit_fifo_size = edge_port->maxTxCredits; + tmp.baud_base = 9600; + tmp.close_delay = 5*HZ; + tmp.closing_wait = 30*HZ; +// tmp.custom_divisor = state->custom_divisor; +// tmp.hub6 = state->hub6; +// tmp.io_type = state->io_type; + + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + + + +/***************************************************************************** + * SerialIoctl + * this function handles any ioctl calls to the driver + *****************************************************************************/ +static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + struct async_icount cnow; + struct async_icount cprev; + struct serial_icounter_struct icount; + unsigned long flags; + + + dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd); + + switch (cmd) { + // return number of bytes available + case TIOCINQ: + dbg(__FUNCTION__" (%d) TIOCINQ", port->number); + return get_number_bytes_avail(edge_port, (unsigned int *) arg); + break; + +// case TCGETS: +// dbg(__FUNCTION__" (%d) TCGETS", port->number); +// break; + +// case TCSETS: +// dbg(__FUNCTION__" (%d) TCSETS", port->number); +// break; + + case TIOCSERGETLSR: + dbg(__FUNCTION__" (%d) TIOCSERGETLSR", port->number); + return get_lsr_info(edge_port, (unsigned int *) arg); + return 0; + + case TIOCMSET: + dbg(__FUNCTION__" (%d) TIOCMSET", port->number); + return set_modem_info(edge_port, (unsigned int *) arg); + + case TIOCMGET: + dbg(__FUNCTION__" (%d) TIOCMGET", port->number); + return get_modem_info(edge_port, (unsigned int *) arg); + + case TIOCGSERIAL: + dbg(__FUNCTION__" (%d) TIOCGSERIAL", port->number); + return get_serial_info(edge_port, (struct serial_struct *) arg); + + case TIOCSSERIAL: + dbg(__FUNCTION__" (%d) TIOCSSERIAL", port->number); + break; + + case TIOCMIWAIT: + dbg(__FUNCTION__" (%d) TIOCMIWAIT", port->number); + save_flags(flags); cli(); + cprev = edge_port->icount; + restore_flags(flags); + while (1) { + interruptible_sleep_on(&edge_port->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + save_flags(flags); cli(); + cnow = edge_port->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + break; + + case TIOCGICOUNT: + save_flags(flags); cli(); + cnow = edge_port->icount; + restore_flags(flags); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + dbg(__FUNCTION__" (%d) TIOCGICOUNT RX=%d, TX=%d", port->number, icount.rx, icount.tx ); + if (copy_to_user((void *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + } + + return -ENOIOCTLCMD; +} + + +/***************************************************************************** + * SerialBreak + * this function sends a break to the port + *****************************************************************************/ +static void edge_break (struct usb_serial_port *port, int break_state) +{ + struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); + int status; + + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; + + dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT"); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } + + if (break_state == -1) { + dbg(__FUNCTION__" - Sending IOSP_CMD_SET_BREAK"); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); + } else { + dbg(__FUNCTION__" - Sending IOSP_CMD_CLEAR_BREAK"); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); + } + if (status) { + dbg(__FUNCTION__" - error sending break set/clear command."); + } + + return; +} + + +/***************************************************************************** + * process_rcvd_data + * this function handles the data received on the bulk in pipe. + *****************************************************************************/ +static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char * buffer, __u16 bufferLength) +{ + struct usb_serial_port *port; + struct edgeport_port *edge_port; + struct tty_struct *tty; + __u16 lastBufferLength; + __u16 rxLen; + int i; + + dbg(__FUNCTION__); + + lastBufferLength = bufferLength + 1; + + while (bufferLength > 0) { + /* failsafe incase we get a message that we don't understand */ + if (lastBufferLength == bufferLength) { + dbg(__FUNCTION__" - stuck in loop, exiting it."); + break; + } + lastBufferLength = bufferLength; + + switch (edge_serial->rxState) { + case EXPECT_HDR1: + edge_serial->rxHeader1 = *buffer; + ++buffer; + --bufferLength; + + if (bufferLength == 0) { + edge_serial->rxState = EXPECT_HDR2; + break; + } + /* otherwise, drop on through */ + + case EXPECT_HDR2: + edge_serial->rxHeader2 = *buffer; + ++buffer; + --bufferLength; + + dbg(__FUNCTION__" - Hdr1=%02X Hdr2=%02X", edge_serial->rxHeader1, edge_serial->rxHeader2); + + // Process depending on whether this header is + // data or status + + if (IS_CMD_STAT_HDR(edge_serial->rxHeader1)) { + // Decode this status header and goto EXPECT_HDR1 (if we + // can process the status with only 2 bytes), or goto + // EXPECT_HDR3 to get the third byte. + + edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1); + edge_serial->rxStatusCode = IOSP_GET_STATUS_CODE(edge_serial->rxHeader1); + + if (!IOSP_STATUS_IS_2BYTE(edge_serial->rxStatusCode)) { + // This status needs additional bytes. Save what we have + // and then wait for more data. + edge_serial->rxStatusParam = edge_serial->rxHeader2; + + edge_serial->rxState = EXPECT_HDR3; + break; + } + + // We have all the header bytes, process the status now + process_rcvd_status (edge_serial, edge_serial->rxHeader2, 0); + + edge_serial->rxState = EXPECT_HDR1; + break; + } else { + edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1); + edge_serial->rxBytesRemaining = IOSP_GET_HDR_DATA_LEN(edge_serial->rxHeader1, edge_serial->rxHeader2); + + dbg(__FUNCTION__" - Data for Port %u Len %u", edge_serial->rxPort, edge_serial->rxBytesRemaining); + + //ASSERT( DevExt->RxPort < DevExt->NumPorts ); + //ASSERT( DevExt->RxBytesRemaining < IOSP_MAX_DATA_LENGTH ); + + if (bufferLength == 0 ) { + edge_serial->rxState = EXPECT_DATA; + break; + } + // Else, drop through + } + + case EXPECT_DATA: // Expect data + + if (bufferLength < edge_serial->rxBytesRemaining) { + rxLen = bufferLength; + edge_serial->rxState = EXPECT_DATA; // Expect data to start next buffer + } else { + // BufLen >= RxBytesRemaining + rxLen = edge_serial->rxBytesRemaining; + edge_serial->rxState = EXPECT_HDR1; // Start another header next time + } + + bufferLength -= rxLen; + edge_serial->rxBytesRemaining -= rxLen; + + /* spit this data back into the tty driver if this port is open */ + if (rxLen) { + port = &edge_serial->serial->port[edge_serial->rxPort]; + if (port_paranoia_check (port, __FUNCTION__) == 0) { + edge_port = (struct edgeport_port *)port->private; + if (edge_port->open) { + tty = edge_port->port->tty; + if (tty) { + dbg (__FUNCTION__" - Sending %d bytes to TTY for port %d", rxLen, edge_serial->rxPort); + for (i = 0; i < rxLen ; ++i) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* this doesn't actually push the data through unless tty->low_latency is set */ + tty_insert_flip_char(tty, buffer[i], 0); + } + tty_flip_buffer_push(tty); + } + edge_port->icount.rx += rxLen; + } + } + buffer += rxLen; + } + + break; + + case EXPECT_HDR3: // Expect 3rd byte of status header + edge_serial->rxHeader3 = *buffer; + ++buffer; + --bufferLength; + + // We have all the header bytes, process the status now + process_rcvd_status (edge_serial, edge_serial->rxStatusParam, edge_serial->rxHeader3); + edge_serial->rxState = EXPECT_HDR1; + break; + + } + } + + return 0; +} + + +/***************************************************************************** + * process_rcvd_status + * this function handles the any status messages received on the bulk in pipe. + *****************************************************************************/ +static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3) +{ + struct usb_serial_port *port; + struct edgeport_port *edge_port; + __u8 code = edge_serial->rxStatusCode; + + /* switch the port pointer to the one being currently talked about */ + port = &edge_serial->serial->port[edge_serial->rxPort]; + if (port_paranoia_check (port, __FUNCTION__)) { + return; + } + edge_port = (struct edgeport_port *)port->private; + if (edge_port == NULL) { + err (__FUNCTION__ " - edge_port == NULL for port %d", edge_serial->rxPort); + return; + } + + dbg(__FUNCTION__" - port %d", edge_serial->rxPort); + + if (code == IOSP_EXT_STATUS) { + switch (byte2) { + case IOSP_EXT_STATUS_CHASE_RSP: + // we want to do EXT status regardless of port open/closed + dbg(__FUNCTION__" - Port %u EXT CHASE_RSP Data = %02x", edge_serial->rxPort, byte3 ); + // Currently, the only EXT_STATUS is Chase, so process here instead of one more call + // to one more subroutine. If/when more EXT_STATUS, there'll be more work to do. + // Also, we currently clear flag and close the port regardless of content of above's Byte3. + // We could choose to do something else when Byte3 says Timeout on Chase from Edgeport, + // like wait longer in block_until_chase_response, but for now we don't. + edge_port->chaseResponsePending = FALSE; + wake_up_interruptible (&edge_port->wait_chase); + return; + + case IOSP_EXT_STATUS_RX_CHECK_RSP: + dbg( __FUNCTION__" ========== Port %u CHECK_RSP Sequence = %02x =============\n", edge_serial->rxPort, byte3 ); + //Port->RxCheckRsp = TRUE; + return; + } + } + + if (code == IOSP_STATUS_OPEN_RSP) { + edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3); + edge_port->maxTxCredits = edge_port->txCredits; + dbg (__FUNCTION__" - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", edge_serial->rxPort, byte2, edge_port->txCredits); + handle_new_msr (edge_port, byte2); + + /* send the current line settings to the port so we are in sync with any further termios calls */ + change_port_settings (edge_port, edge_port->port->tty->termios); + + /* we have completed the open */ + edge_port->openPending = FALSE; + edge_port->open = TRUE; + wake_up_interruptible(&edge_port->wait_open); + return; + } + + // If port is closed, silently discard all rcvd status. We can + // have cases where buffered status is received AFTER the close + // port command is sent to the Edgeport. + if ((!edge_port->open ) || (edge_port->closePending)) { + return; + } + + switch (code) { + // Not currently sent by Edgeport + case IOSP_STATUS_LSR: + dbg(__FUNCTION__" - Port %u LSR Status = %02x", edge_serial->rxPort, byte2); + handle_new_lsr (edge_port, FALSE, byte2, 0); + break; + + case IOSP_STATUS_LSR_DATA: + dbg(__FUNCTION__" - Port %u LSR Status = %02x, Data = %02x", edge_serial->rxPort, byte2, byte3); + // byte2 is LSR Register + // byte3 is broken data byte + handle_new_lsr (edge_port, TRUE, byte2, byte3); + break; + // + // case IOSP_EXT_4_STATUS: + // dbg(__FUNCTION__" - Port %u LSR Status = %02x Data = %02x", edge_serial->rxPort, byte2, byte3); + // break; + // + case IOSP_STATUS_MSR: + dbg(__FUNCTION__" - Port %u MSR Status = %02x", edge_serial->rxPort, byte2); + + // Process this new modem status and generate appropriate + // events, etc, based on the new status. This routine + // also saves the MSR in Port->ShadowMsr. + handle_new_msr(edge_port, byte2); + break; + + default: + dbg(__FUNCTION__" - Unrecognized IOSP status code %u\n", code); + break; + } + + return; +} + + +/***************************************************************************** + * handle_new_msr + * this function handles any change to the msr register for a port. + *****************************************************************************/ +static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) +{ + struct async_icount *icount; + + dbg(__FUNCTION__" %02x", newMsr); + + if (newMsr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) { + icount = &edge_port->icount; + + /* update input line counters */ + if (newMsr & MSR_DELTA_CTS) { + icount->cts++; + } + if (newMsr & MSR_DELTA_DSR) { + icount->dsr++; + } + if (newMsr & MSR_DELTA_CD) { + icount->dcd++; + } + if (newMsr & MSR_DELTA_RI) { + icount->rng++; + } + wake_up_interruptible(&edge_port->delta_msr_wait); + } + + /* Save the new modem status */ + edge_port->shadowMSR = newMsr & 0xf0; + + return; +} + + +/***************************************************************************** + * handle_new_lsr + * this function handles any change to the lsr register for a port. + *****************************************************************************/ +static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data) +{ + __u8 newLsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); + struct async_icount *icount; + + dbg(__FUNCTION__" - %02x", newLsr); + + edge_port->shadowLSR = lsr; + + if (newLsr & LSR_BREAK) { + // + // Parity and Framing errors only count if they + // occur exclusive of a break being + // received. + // + newLsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); + } + + /* Place LSR data byte into Rx buffer */ + if (lsrData) { + tty_insert_flip_char(edge_port->port->tty, data, 0); + tty_flip_buffer_push(edge_port->port->tty); + } + + /* update input line counters */ + icount = &edge_port->icount; + if (newLsr & LSR_BREAK) { + icount->brk++; + } + if (newLsr & LSR_OVER_ERR) { + icount->overrun++; + } + if (newLsr & LSR_PAR_ERR) { + icount->parity++; + } + if (newLsr & LSR_FRM_ERR) { + icount->frame++; + } + + return; +} + + +/**************************************************************************** + * sram_write + * writes a number of bytes to the Edgeport device's sram starting at the + * given address. + * If successful returns the number of bytes written, otherwise it returns + * a negative error number of the problem. + ****************************************************************************/ +static int sram_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data) +{ + int result; + __u16 current_length; + unsigned char *transfer_buffer; + +// dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length); + + transfer_buffer = kmalloc (64, GFP_KERNEL); + if (!transfer_buffer) { + err(__FUNCTION__" - kmalloc(%d) failed.\n", 64); + return -ENOMEM; + } + + /* need to split these writes up into 64 byte chunks */ + result = 0; + while (length > 0) { + if (length > 64) { + current_length = 64; + } else { + current_length = length; + } +// dbg (__FUNCTION__" - writing %x, %x, %d", extAddr, addr, current_length); + memcpy (transfer_buffer, data, current_length); + result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_RAM, + 0x40, addr, extAddr, transfer_buffer, current_length, 300); + if (result < 0) + break; + length -= current_length; + addr += current_length; + data += current_length; + } + + kfree (transfer_buffer); + return result; +} + + +/**************************************************************************** + * rom_write + * writes a number of bytes to the Edgeport device's ROM starting at the + * given address. + * If successful returns the number of bytes written, otherwise it returns + * a negative error number of the problem. + ****************************************************************************/ +static int rom_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data) +{ + int result; + __u16 current_length; + unsigned char *transfer_buffer; + +// dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length); + + transfer_buffer = kmalloc (64, GFP_KERNEL); + if (!transfer_buffer) { + err(__FUNCTION__" - kmalloc(%d) failed.\n", 64); + return -ENOMEM; + } + + /* need to split these writes up into 64 byte chunks */ + result = 0; + while (length > 0) { + if (length > 64) { + current_length = 64; + } else { + current_length = length; + } +// dbg (__FUNCTION__" - writing %x, %x, %d", extAddr, addr, current_length); + memcpy (transfer_buffer, data, current_length); + result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_ROM, + 0x40, addr, extAddr, transfer_buffer, current_length, 300); + if (result < 0) + break; + length -= current_length; + addr += current_length; + data += current_length; + } + + kfree (transfer_buffer); + return result; +} + + +/**************************************************************************** + * rom_read + * reads a number of bytes from the Edgeport device starting at the given + * address. + * If successful returns the number of bytes read, otherwise it returns + * a negative error number of the problem. + ****************************************************************************/ +static int rom_read (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data) +{ + int result; + __u16 current_length; + unsigned char *transfer_buffer; + + dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length); + + transfer_buffer = kmalloc (64, GFP_KERNEL); + if (!transfer_buffer) { + err(__FUNCTION__" - kmalloc(%d) failed.\n", 64); + return -ENOMEM; + } + + /* need to split these reads up into 64 byte chunks */ + result = 0; + while (length > 0) { + if (length > 64) { + current_length = 64; + } else { + current_length = length; + } +// dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, current_length); + result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_READ_ROM, + 0xC0, addr, extAddr, transfer_buffer, current_length, 300); + if (result < 0) + break; + memcpy (data, transfer_buffer, current_length); + length -= current_length; + addr += current_length; + data += current_length; + } + + kfree (transfer_buffer); + return result; +} + + +/**************************************************************************** + * send_iosp_ext_cmd + * Is used to send a IOSP message to the Edgeport device + ****************************************************************************/ +static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param) +{ + unsigned char *buffer; + unsigned char *currentCommand; + int length = 0; + int status = 0; + + dbg(__FUNCTION__" - %d, %d", command, param); + + buffer = kmalloc (10, GFP_KERNEL); + if (!buffer) { + err(__FUNCTION__" - kmalloc(%d) failed.\n", 10); + return -ENOMEM; + } + + currentCommand = buffer; + + MAKE_CMD_EXT_CMD( ¤tCommand, &length, edge_port->port->number, command, param); + + status = write_cmd_usb (edge_port, buffer, length); + if (status) { + /* something bad happened, let's free up the memory */ + kfree(buffer); + } + + return status; +} + + +/***************************************************************************** + * write_cmd_usb + * this function writes the given buffer out to the bulk write endpoint. + *****************************************************************************/ +static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int length) +{ + struct edgeport_serial *edge_serial = (struct edgeport_serial *)edge_port->port->serial->private; + int status = 0; + urb_t *urb; + int timeout; + +#ifdef DEBUG + if (length) { + int i; + printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, buffer = ", length); + for (i = 0; i < length; ++i) { + printk ("%.2x ", buffer[i]); + } + printk ("\n"); + } +#endif + + /* Allocate our next urb */ + urb = usb_alloc_urb (0); + + CmdUrbs++; + + dbg(__FUNCTION__" - ALLOCATE URB %p (outstanding %d)", urb, CmdUrbs); + + if (!urb) { + return -ENOMEM; + } + + FILL_BULK_URB (urb, edge_serial->serial->dev, + usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint), + buffer, length, edge_bulk_out_cmd_callback, edge_port); + + /* set the USB_BULK_QUEUE flag so that we can shove a bunch of urbs at once down the pipe */ + urb->transfer_flags |= USB_QUEUE_BULK; + + edge_port->commandPending = TRUE; + urb->dev = edge_serial->serial->dev; + status = usb_submit_urb(urb); + + if (status) { + /* something went wrong */ + dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed"); + + /* if this urb had a transfer buffer already (old transfer) free it */ + if (urb->transfer_buffer != NULL) { + kfree(urb->transfer_buffer); + } + usb_unlink_urb (urb); + usb_free_urb (urb); + return status; + } + + // wait for command to finish + timeout = COMMAND_TIMEOUT; +#if 0 + while (timeout && edge_port->commandPending == TRUE) { + timeout = interruptible_sleep_on_timeout (&edge_port->wait_command, timeout); + } + + if (edge_port->commandPending == TRUE) { + /* command timed out */ + dbg(__FUNCTION__" - command timed out"); + status = -EINVAL; + } +#endif + return status; +} + + +/***************************************************************************** + * send_cmd_write_baud_rate + * this function sends the proper command to change the baud rate of the + * specified port. + *****************************************************************************/ +static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate) +{ + unsigned char *cmdBuffer; + unsigned char *currCmd; + int cmdLen = 0; + int divisor; + int status; + unsigned char number = edge_port->port->number; + + dbg(__FUNCTION__" - port = %d, baud = %d", number, baudRate); + + status = calc_baud_rate_divisor (baudRate, &divisor); + if (status) { + err(__FUNCTION__" - bad baud rate"); + return status; + } + + // Alloc memory for the string of commands. + cmdBuffer = kmalloc (0x100, GFP_KERNEL); + if (!cmdBuffer) { + err(__FUNCTION__" - kmalloc(%d) failed.\n", 0x100); + return -ENOMEM; + } + currCmd = cmdBuffer; + + // Enable access to divisor latch + MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, LCR, LCR_DL_ENABLE ); + + // Write the divisor itself + MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, DLL, LOW8 (divisor) ); + MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, DLM, HIGH8(divisor) ); + + // Restore original value to disable access to divisor latch + MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, LCR, edge_port->shadowLCR); + + status = write_cmd_usb(edge_port, cmdBuffer, cmdLen ); + + return status; +} + + +/***************************************************************************** + * calc_baud_rate_divisor + * this function calculates the proper baud rate divisor for the specified + * baud rate. + *****************************************************************************/ +static int calc_baud_rate_divisor (int baudrate, int *divisor) +{ + int i; + __u16 custom; + __u16 round1; + __u16 round; + + + dbg(__FUNCTION__" - %d", baudrate); + + for (i = 0; i < NUM_ENTRIES(DivisorTable); i++) { + if ( DivisorTable[i].BaudRate == baudrate ) { + *divisor = DivisorTable[i].Divisor; + return 0; + } + } + + // We have tried all of the standard baud rates + // lets try to calculate the divisor for this baud rate + // Make sure the baud rate is reasonable + if (baudrate > 75 && baudrate < 230400) { + // get divisor + custom = (__u16)(230400L / baudrate); + + // Check for round off + round1 = (__u16)(2304000L / baudrate); + round = (__u16)(round1 - (custom * 10)); + if (round > 4) { + custom++; + } + *divisor = custom; + + dbg(__FUNCTION__" - Baud %d = %d\n", baudrate, custom); + return 0; + } + + return -1; +} + + +/***************************************************************************** + * send_cmd_write_uart_register + * this function builds up a uart register message and sends to to the device. + *****************************************************************************/ +static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue) +{ + unsigned char *cmdBuffer; + unsigned char *currCmd; + unsigned long cmdLen = 0; + int status; + + dbg (__FUNCTION__" - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", regValue); + + // Alloc memory for the string of commands. + cmdBuffer = kmalloc (0x10, GFP_KERNEL); + if (cmdBuffer == NULL ) { + return -ENOMEM; + } + + currCmd = cmdBuffer; + + // Build a cmd in the buffer to write the given register + MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, edge_port->port->number, regNum, regValue); + + status = write_cmd_usb(edge_port, cmdBuffer, cmdLen); + + return status; +} + + +/***************************************************************************** + * change_port_settings + * This routine is called to set the UART on the device to match the specified + * new settings. + *****************************************************************************/ +static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) +{ + struct tty_struct *tty; + int baud; + unsigned cflag; + __u8 mask = 0xff; + __u8 lData; + __u8 lParity; + __u8 lStop; + __u8 rxFlow; + __u8 txFlow; + int status; + + dbg(__FUNCTION__" - port %d", edge_port->port->number); + + if ((!edge_port->open) && + (!edge_port->openPending)) { + dbg(__FUNCTION__" - port not opened"); + return; + } + + tty = edge_port->port->tty; + if ((!tty) || + (!tty->termios)) { + dbg(__FUNCTION__" - no tty structures"); + return; + } + + cflag = tty->termios->c_cflag; + + switch (cflag & CSIZE) { + case CS5: lData = LCR_BITS_5; mask = 0x1f; dbg(__FUNCTION__" - data bits = 5"); break; + case CS6: lData = LCR_BITS_6; mask = 0x3f; dbg(__FUNCTION__" - data bits = 6"); break; + case CS7: lData = LCR_BITS_7; mask = 0x7f; dbg(__FUNCTION__" - data bits = 7"); break; + default: + case CS8: lData = LCR_BITS_8; dbg(__FUNCTION__" - data bits = 8"); break; + } + + lParity = LCR_PAR_NONE; + if (cflag & PARENB) { + if (cflag & PARODD) { + lParity = LCR_PAR_ODD; + dbg(__FUNCTION__" - parity = odd"); + } else { + lParity = LCR_PAR_EVEN; + dbg(__FUNCTION__" - parity = even"); + } + } else { + dbg(__FUNCTION__" - parity = none"); + } + + if (cflag & CSTOPB) { + lStop = LCR_STOP_2; + dbg(__FUNCTION__" - stop bits = 2"); + } else { + lStop = LCR_STOP_1; + dbg(__FUNCTION__" - stop bits = 1"); + } + + /* figure out the flow control settings */ + rxFlow = txFlow = 0x00; + if (cflag & CRTSCTS) { + rxFlow |= IOSP_RX_FLOW_RTS; + txFlow |= IOSP_TX_FLOW_CTS; + dbg(__FUNCTION__" - RTS/CTS is enabled"); + } else { + dbg(__FUNCTION__" - RTS/CTS is disabled"); + } + + /* if we are implementing XON/XOFF, set the start and stop character in the device */ + if (I_IXOFF(tty) || I_IXON(tty)) { + unsigned char stop_char = STOP_CHAR(tty); + unsigned char start_char = START_CHAR(tty); + + { + send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char); + send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + } + + /* if we are implementing INBOUND XON/XOFF */ + if (I_IXOFF(tty)) { + rxFlow |= IOSP_RX_FLOW_XON_XOFF; + dbg(__FUNCTION__" - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", start_char, stop_char); + } else { + dbg(__FUNCTION__" - INBOUND XON/XOFF is disabled"); + } + + /* if we are implementing OUTBOUND XON/XOFF */ + if (I_IXON(tty)) { + txFlow |= IOSP_TX_FLOW_XON_XOFF; + dbg(__FUNCTION__" - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", start_char, stop_char); + } else { + dbg(__FUNCTION__" - OUTBOUND XON/XOFF is disabled"); + } + } + + /* Set flow control to the configured value */ + send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); + send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); + + + edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); + edge_port->shadowLCR |= (lData | lParity | lStop); + + edge_port->validDataMask = mask; + + /* Send the updated LCR value to the EdgePort */ + status = send_cmd_write_uart_register(edge_port, LCR, edge_port->shadowLCR); + if (status != 0) { + return; + } + + /* set up the MCR register and send it to the EdgePort */ + edge_port->shadowMCR = MCR_MASTER_IE; + if (cflag & CBAUD) { + edge_port->shadowMCR |= (MCR_DTR | MCR_RTS); + } + status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); + if (status != 0) { + return; + } + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(tty); + if (!baud) { + /* pick a default, any default... */ + baud = 9600; + } + + dbg(__FUNCTION__ " - baud rate = %d", baud); + status = send_cmd_write_baud_rate (edge_port, baud); + + return; +} + + +/**************************************************************************** + * unicode_to_ascii + * Turns a string from Unicode into ASCII. + * Doesn't do a good job with any characters that are outside the normal + * ASCII range, but it's only for debugging... + ****************************************************************************/ +static void unicode_to_ascii (char *string, short *unicode, int unicode_size) +{ + int i; + for (i = 0; i < unicode_size; ++i) { + string[i] = (char)(unicode[i]); + } + string[unicode_size] = 0x00; +} + + +/**************************************************************************** + * get_manufacturing_desc + * reads in the manufacturing descriptor and stores it into the serial + * structure. + ****************************************************************************/ +static void get_manufacturing_desc (struct edgeport_serial *edge_serial) +{ + int response; + + dbg("getting manufacturer descriptor"); + + response = rom_read (edge_serial->serial, (EDGE_MANUF_DESC_ADDR & 0xffff0000) >> 16, + (__u16)(EDGE_MANUF_DESC_ADDR & 0x0000ffff), EDGE_MANUF_DESC_LEN, + (__u8 *)(&edge_serial->manuf_descriptor)); + + if (response < 1) { + err("error in getting manufacturer descriptor"); + } else { +#ifdef DEBUG + char string[30]; + dbg("**Manufacturer Descriptor"); + dbg(" RomSize: %dK", edge_serial->manuf_descriptor.RomSize); + dbg(" RamSize: %dK", edge_serial->manuf_descriptor.RamSize); + dbg(" CpuRev: %d", edge_serial->manuf_descriptor.CpuRev); + dbg(" BoardRev: %d", edge_serial->manuf_descriptor.BoardRev); + dbg(" NumPorts: %d", edge_serial->manuf_descriptor.NumPorts); + dbg(" DescDate: %d/%d/%d", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900); + unicode_to_ascii (string, edge_serial->manuf_descriptor.SerialNumber, edge_serial->manuf_descriptor.SerNumLength/2-1); + dbg(" SerialNumber: %s", string); + unicode_to_ascii (string, edge_serial->manuf_descriptor.AssemblyNumber, edge_serial->manuf_descriptor.AssemblyNumLength/2-1); + dbg(" AssemblyNumber: %s", string); + unicode_to_ascii (string, edge_serial->manuf_descriptor.OemAssyNumber, edge_serial->manuf_descriptor.OemAssyNumLength/2-1); + dbg(" OemAssyNumber: %s", string); + dbg(" UartType: %d", edge_serial->manuf_descriptor.UartType); + dbg(" IonPid: %d", edge_serial->manuf_descriptor.IonPid); + dbg(" IonConfig: %d", edge_serial->manuf_descriptor.IonConfig); +#endif + } +} + + +/**************************************************************************** + * get_boot_desc + * reads in the bootloader descriptor and stores it into the serial + * structure. + ****************************************************************************/ +static void get_boot_desc (struct edgeport_serial *edge_serial) +{ + int response; + + dbg("getting boot descriptor"); + + response = rom_read (edge_serial->serial, (EDGE_BOOT_DESC_ADDR & 0xffff0000) >> 16, + (__u16)(EDGE_BOOT_DESC_ADDR & 0x0000ffff), EDGE_BOOT_DESC_LEN, + (__u8 *)(&edge_serial->boot_descriptor)); + + if (response < 1) { + err("error in getting boot descriptor"); + } else { + dbg("**Boot Descriptor:"); + dbg(" BootCodeLength: %d", edge_serial->boot_descriptor.BootCodeLength); + dbg(" MajorVersion: %d", edge_serial->boot_descriptor.MajorVersion); + dbg(" MinorVersion: %d", edge_serial->boot_descriptor.MinorVersion); + dbg(" BuildNumber: %d", edge_serial->boot_descriptor.BuildNumber); + dbg(" Capabilities: 0x%x", edge_serial->boot_descriptor.Capabilities); + dbg(" UConfig0: %d", edge_serial->boot_descriptor.UConfig0); + dbg(" UConfig1: %d", edge_serial->boot_descriptor.UConfig1); + } +} + + +/**************************************************************************** + * load_application_firmware + * This is called to load the application firmware to the device + ****************************************************************************/ +static void load_application_firmware (struct edgeport_serial *edge_serial) +{ + PEDGE_FIRMWARE_IMAGE_RECORD record; + unsigned char *firmware; + unsigned char *FirmwareImage; + int ImageSize; + int response; + + + switch (edge_serial->product_info.iDownloadFile) { + case EDGE_DOWNLOAD_FILE_I930: + dbg("downloading firmware version (930) %d.%d.%d", + OperationalCodeImageVersion_GEN1.MajorVersion, + OperationalCodeImageVersion_GEN1.MinorVersion, + OperationalCodeImageVersion_GEN1.BuildNumber); + firmware = &OperationalCodeImage_GEN1[0]; + FirmwareImage = &OperationalCodeImage_GEN1[0]; + ImageSize = sizeof(OperationalCodeImage_GEN1); + break; + + case EDGE_DOWNLOAD_FILE_80251: + dbg("downloading firmware version (80251) %d.%d.%d", + OperationalCodeImageVersion_GEN2.MajorVersion, + OperationalCodeImageVersion_GEN2.MinorVersion, + OperationalCodeImageVersion_GEN2.BuildNumber); + firmware = &OperationalCodeImage_GEN2[0]; + FirmwareImage = &OperationalCodeImage_GEN2[0]; + ImageSize = sizeof(OperationalCodeImage_GEN2); + break; + + case EDGE_DOWNLOAD_FILE_NONE: + dbg ("No download file specified, skipping download\n"); + return; + + default: + return; + } + + + for (;;) { + record = (PEDGE_FIRMWARE_IMAGE_RECORD)firmware; + response = sram_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]); + if (response < 0) { + err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len); + break; + } + firmware += sizeof (EDGE_FIRMWARE_IMAGE_RECORD) + record->Len; + if (firmware >= &FirmwareImage[ImageSize]) { + break; + } + } + + dbg("sending exec_dl_code"); + response = usb_control_msg (edge_serial->serial->dev, + usb_sndctrlpipe(edge_serial->serial->dev, 0), + USB_REQUEST_ION_EXEC_DL_CODE, + 0x40, 0x4000, 0x0001, NULL, 0, 3000); + + return; +} + + + + +/**************************************************************************** + * edge_startup + ****************************************************************************/ +static int edge_startup (struct usb_serial *serial) +{ + struct edgeport_serial *edge_serial; + struct edgeport_port *edge_port; + struct usb_device *dev; + int i; + + dev = serial->dev; + + /* create our private serial structure */ + edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL); + if (edge_serial == NULL) { + err(__FUNCTION__" - Out of memory"); + return -ENOMEM; + } + memset (edge_serial, 0, sizeof(struct edgeport_serial)); + edge_serial->serial = serial; + serial->private = edge_serial; + + /* get the name for the device from the device */ + if ( (i = get_string(dev, dev->descriptor.iManufacturer, &edge_serial->name[0])) != 0) { + edge_serial->name[i-1] = ' '; + } + + get_string(dev, dev->descriptor.iProduct, &edge_serial->name[i]); + + info("%s detected", edge_serial->name); + + /* get the manufacturing descriptor for this device */ + get_manufacturing_desc (edge_serial); + + /* get the boot descriptor */ + get_boot_desc (edge_serial); + + get_product_info(edge_serial); + + /* set the number of ports from the manufacturing description */ + // FIXME should we override this??? + //serial->num_ports = serial->product_info.NumPorts; + if (edge_serial->product_info.NumPorts != serial->num_ports) { + warn(__FUNCTION__ " - Device Reported %d serial ports vs core thinking we have %d ports, email greg@kroah.com this info.", edge_serial->product_info.NumPorts, serial->num_ports); + } + + dbg(__FUNCTION__ " - time 1 %ld", jiffies); + + /* now load the application firmware into this device */ + load_application_firmware (edge_serial); + + dbg(__FUNCTION__ " - time 2 %ld", jiffies); + + /* Check current Edgeport EEPROM and update if necessary */ + update_edgeport_E2PROM (edge_serial); + + dbg(__FUNCTION__ " - time 3 %ld", jiffies); + + /* set the configuration to use #1 */ +// dbg("set_configuration 1"); +// usb_set_configuration (dev, 1); + + /* we set up the pointers to the endpoints in the edge_open function, + * as the structures aren't created yet. */ + + /* set up our port private structures */ + for (i = 0; i < serial->num_ports; ++i) { + edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); + if (edge_port == NULL) { + err(__FUNCTION__" - Out of memory"); + return -ENOMEM; + } + memset (edge_port, 0, sizeof(struct edgeport_port)); + edge_port->port = &serial->port[i]; + serial->port[i].private = edge_port; + } + + return 0; +} + + + +/**************************************************************************** + * usb_edgeport_disconnect + * This function is called whenever the device is removed from the usb bus. + ****************************************************************************/ +//static void usb_edgeport_disconnect (struct usb_device *dev, void *ptr) +static void edge_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + edge_close (&serial->port[i], NULL); + } + } + + /* free up any memory that we allocated */ + // FIXME + +} + + +/**************************************************************************** + * edgeport_init + * This is called by the module subsystem, or on startup to initialize us + ****************************************************************************/ +int __init edgeport_init(void) +{ + usb_serial_register (&edgeport_4_device); + usb_serial_register (&rapidport_4_device); + usb_serial_register (&edgeport_4t_device); + usb_serial_register (&edgeport_2_device); + usb_serial_register (&edgeport_4i_device); + usb_serial_register (&edgeport_2i_device); + usb_serial_register (&edgeport_prl_device); + usb_serial_register (&edgeport_421_device); + usb_serial_register (&edgeport_21_device); + usb_serial_register (&edgeport_8dual_device); + usb_serial_register (&edgeport_8_device); + usb_serial_register (&edgeport_2din_device); + usb_serial_register (&edgeport_4din_device); + usb_serial_register (&edgeport_16dual_device); + usb_serial_register (&edgeport_compat_id_device); + usb_serial_register (&edgeport_8i_device); + + return 0; +} + + + +/**************************************************************************** + * edgeport_exit + * Called when the driver is about to be unloaded. + ****************************************************************************/ +void __exit edgeport_exit (void) +{ + usb_serial_deregister (&edgeport_4_device); + usb_serial_deregister (&rapidport_4_device); + usb_serial_deregister (&edgeport_4t_device); + usb_serial_deregister (&edgeport_2_device); + usb_serial_deregister (&edgeport_4i_device); + usb_serial_deregister (&edgeport_2i_device); + usb_serial_deregister (&edgeport_prl_device); + usb_serial_deregister (&edgeport_421_device); + usb_serial_deregister (&edgeport_21_device); + usb_serial_deregister (&edgeport_8dual_device); + usb_serial_deregister (&edgeport_8_device); + usb_serial_deregister (&edgeport_2din_device); + usb_serial_deregister (&edgeport_4din_device); + usb_serial_deregister (&edgeport_16dual_device); + usb_serial_deregister (&edgeport_compat_id_device); + usb_serial_deregister (&edgeport_8i_device); +} + +module_init(edgeport_init); +module_exit(edgeport_exit); + + + diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_edgeport.h linux/drivers/usb/serial/io_edgeport.h --- v2.4.2/linux/drivers/usb/serial/io_edgeport.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_edgeport.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,152 @@ +/************************************************************************ + * + * io_edgeport.h Edgeport Linux Interface definitions + * + * Copyright (c) 2000 Inside Out Networks, 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. + * + * + ************************************************************************/ + +#if !defined(_IO_EDGEPORT_H_) +#define _IO_EDGEPORT_H_ + + +#define MAX_RS232_PORTS 8 /* Max # of RS-232 ports per device */ + +/* typedefs that the insideout headers need */ +#ifndef TRUE + #define TRUE (1) +#endif +#ifndef FALSE + #define FALSE (0) +#endif +#ifndef MIN + #define MIN(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef MAX + #define MAX(a,b) (((a)>(b))?(a):(b)) +#endif +#ifndef max + #define max MAX +#endif + +#ifndef LOW8 + #define LOW8(a) ((unsigned char)(a & 0xff)) +#endif +#ifndef HIGH8 + #define HIGH8(a) ((unsigned char)((a & 0xff00) >> 8)) +#endif +#ifndef NUM_ENTRIES + #define NUM_ENTRIES(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include "io_usbvend.h" + + + +/* The following table is used to map the USBx port number to + * the device serial number (or physical USB path), */ +#define MAX_EDGEPORTS 64 + +struct comMapper { + char SerialNumber[MAX_SERIALNUMBER_LEN+1]; /* Serial number/usb path */ + int numPorts; /* Number of ports */ + int Original[MAX_RS232_PORTS]; /* Port numbers set by IOCTL */ + int Port[MAX_RS232_PORTS]; /* Actual used port numbers */ +}; + + +#define EDGEPORT_CONFIG_DEVICE "/proc/edgeport" + +/* /proc/edgeport Interface + * This interface uses read/write/lseek interface to talk to the edgeport driver + * the following read functions are supported: */ +#define PROC_GET_MAPPING_TO_PATH 1 +#define PROC_GET_COM_ENTRY 2 +#define PROC_GET_EDGE_MANUF_DESCRIPTOR 3 +#define PROC_GET_BOOT_DESCRIPTOR 4 +#define PROC_GET_PRODUCT_INFO 5 +#define PROC_GET_STRINGS 6 +#define PROC_GET_CURRENT_COM_MAPPING 7 + +/* The parameters to the lseek() for the read is: */ +#define PROC_READ_SETUP(Command, Argument) ((Command) + ((Argument)<<8)) + + +/* the following write functions are supported: */ +#define PROC_SET_COM_MAPPING 1 +#define PROC_SET_COM_ENTRY 2 + + +/* The following sturcture is passed to the write */ +struct procWrite { + int Command; + union { + struct comMapper Entry; + int ComMappingBasedOnUSBPort; /* Boolean value */ + } u; +}; + +/* + * Product information read from the Edgeport + */ +struct edgeport_product_info { + __u16 ProductId; /* Product Identifier */ + __u8 NumPorts; /* Number of ports on edgeport */ + __u8 ProdInfoVer; /* What version of structure is this? */ + + __u32 IsServer :1; /* Set if Server */ + __u32 IsRS232 :1; /* Set if RS-232 ports exist */ + __u32 IsRS422 :1; /* Set if RS-422 ports exist */ + __u32 IsRS485 :1; /* Set if RS-485 ports exist */ + __u32 IsReserved :28; /* Reserved for later expansion */ + + __u8 RomSize; /* Size of ROM/E2PROM in K */ + __u8 RamSize; /* Size of external RAM in K */ + __u8 CpuRev; /* CPU revision level (chg only if s/w visible) */ + __u8 BoardRev; /* PCB revision level (chg only if s/w visible) */ + + __u8 BootMajorVersion; /* Boot Firmware version: xx. */ + __u8 BootMinorVersion; /* yy. */ + __u16 BootBuildNumber; /* zzzz (LE format) */ + + __u8 FirmwareMajorVersion; /* Operational Firmware version:xx. */ + __u8 FirmwareMinorVersion; /* yy. */ + __u16 FirmwareBuildNumber; /* zzzz (LE format) */ + + __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */ + __u8 Unused1[1]; /* Available */ + + __u8 iDownloadFile; /* What to download to EPiC device */ + __u8 Unused2[2]; /* Available */ +}; + +/* + * Edgeport Stringblock String locations + */ +#define EDGESTRING_MANUFNAME 1 /* Manufacture Name */ +#define EDGESTRING_PRODNAME 2 /* Product Name */ +#define EDGESTRING_SERIALNUM 3 /* Serial Number */ +#define EDGESTRING_ASSEMNUM 4 /* Assembly Number */ +#define EDGESTRING_OEMASSEMNUM 5 /* OEM Assembly Number */ +#define EDGESTRING_MANUFDATE 6 /* Manufacture Date */ +#define EDGESTRING_ORIGSERIALNUM 7 /* Serial Number */ + +struct string_block { + __u16 NumStrings; /* Number of strings in block */ + __u16 Strings[1]; /* Start of string block */ +}; + +typedef struct string_block STRING_BLOCK, *PSTRING_BLOCK; + + +#endif diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_fw_boot.h linux/drivers/usb/serial/io_fw_boot.h --- v2.4.2/linux/drivers/usb/serial/io_fw_boot.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_fw_boot.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,558 @@ +//************************************************************** +//* Edgeport/4 Binary Image +//* Generated by HEX2C v1.06 +//* Copyright(c) 1998 Inside Out Networks, All rights reserved. +//* 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. +//************************************************************** + + +//Image structure definition +#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD) +#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD + typedef struct _EDGE_FIRMWARE_IMAGE_RECORD + { + unsigned short ExtAddr; + unsigned short Addr; + unsigned short Len; + unsigned char Data[0]; + } EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD; + + typedef struct _EDGE_FIRMWARE_VERSION_INFO + { + unsigned char MajorVersion; + unsigned char MinorVersion; + unsigned short BuildNumber; + } EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO; + +#endif + +#if !defined(IMAGE_ARRAY_NAME) +#define IMAGE_ARRAY_NAME FirmwareImage +#define IMAGE_VERSION_NAME FirmwareImageVersion +#endif + +static unsigned char IMAGE_ARRAY_NAME[] = { + +// Segment #1, Start Address 00ff0000, Length 6 +0xff,0x00,0x00,0x00,0x06,0x00, + 0x02, 0x00, 0x80, 0x02, 0x00, 0x03, + +// Segment #2, Start Address 00ff000b, Length 3 +0xff,0x00,0x0b,0x00,0x03,0x00, + 0x02, 0x00, 0x0b, + +// Segment #3, Start Address 00ff0013, Length 3 +0xff,0x00,0x13,0x00,0x03,0x00, + 0x02, 0x01, 0xb8, + +// Segment #4, Start Address 00ff001b, Length 3 +0xff,0x00,0x1b,0x00,0x03,0x00, + 0x02, 0x00, 0x1b, + +// Segment #5, Start Address 00ff0023, Length 3 +0xff,0x00,0x23,0x00,0x03,0x00, + 0x02, 0x00, 0x23, + +// Segment #6, Start Address 00ff002b, Length 3 +0xff,0x00,0x2b,0x00,0x03,0x00, + 0x02, 0x00, 0x2b, + +// Segment #7, Start Address 00ff0033, Length 3 +0xff,0x00,0x33,0x00,0x03,0x00, + 0x02, 0x00, 0x33, + +// Segment #8, Start Address 00ff003b, Length 3 +0xff,0x00,0x3b,0x00,0x03,0x00, + 0x02, 0x00, 0x3b, + +// Segment #9, Start Address 00ff0043, Length 3 +0xff,0x00,0x43,0x00,0x03,0x00, + 0x02, 0x01, 0xbd, + +// Segment #10, Start Address 00ff004b, Length 3 +0xff,0x00,0x4b,0x00,0x03,0x00, + 0x02, 0x01, 0xd0, + +// Segment #11, Start Address 00ff0053, Length 3 +0xff,0x00,0x53,0x00,0x03,0x00, + 0x02, 0x01, 0x21, + +// Segment #12, Start Address 00ff007b, Length 3 +0xff,0x00,0x7b,0x00,0x03,0x00, + 0x02, 0x00, 0x7b, + +// Segment #13, Start Address 00ff0080, Length 358 +0xff,0x00,0x80,0x00,0x66,0x01, + 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x3f, 0xf2, 0x7e, 0xf8, 0x00, 0x23, 0x7e, 0x00, 0x01, 0x7e, 0x10, + 0x00, 0x12, 0x07, 0x5f, 0x69, 0x20, 0x00, 0x0a, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x05, 0x75, 0x90, + 0x0d, 0x80, 0x03, 0x75, 0x90, 0x1d, 0xd2, 0xb5, 0x7e, 0x00, 0x00, 0xa5, 0xd8, 0xfd, 0x75, 0xa8, + 0x00, 0x75, 0xb1, 0x00, 0xa9, 0xd5, 0x87, 0xca, 0x29, 0x12, 0x09, 0xcc, 0x12, 0x09, 0xa0, 0xf5, + 0x09, 0x7a, 0xa1, 0x20, 0x12, 0x01, 0xe6, 0xda, 0x29, 0xa9, 0xd0, 0xc7, 0x7e, 0x00, 0x05, 0x7a, + 0x01, 0xf1, 0x75, 0xe1, 0x10, 0xa9, 0xd7, 0xf4, 0xa9, 0xd7, 0xe4, 0xa5, 0xd8, 0xf1, 0x75, 0xf1, + 0x00, 0x75, 0xe1, 0x3f, 0x75, 0xa2, 0x03, 0x75, 0xa3, 0x00, 0x75, 0xc0, 0x00, 0x75, 0xc1, 0x00, + 0xa9, 0xd1, 0xb1, 0xa9, 0xd0, 0xb1, 0xa9, 0xd5, 0xd3, 0xd2, 0xaf, 0xe4, 0x7e, 0x04, 0x28, 0x00, + 0x8d, 0xef, 0x1b, 0x04, 0x78, 0xfa, 0x04, 0xa9, 0x34, 0xd3, 0x03, 0x30, 0xe0, 0xee, 0xbe, 0x24, + 0x00, 0x00, 0x78, 0x05, 0x63, 0x90, 0x30, 0x80, 0xe3, 0xb2, 0x95, 0x80, 0xdf, 0xbe, 0xb0, 0x02, + 0x22, 0xc0, 0xd0, 0xa9, 0x20, 0xdf, 0x0f, 0xa9, 0x31, 0xdf, 0x03, 0x02, 0x01, 0xb5, 0x75, 0x08, + 0x01, 0x12, 0x08, 0x33, 0x80, 0xfe, 0x75, 0x08, 0xfe, 0x12, 0x08, 0x33, 0x75, 0xa8, 0x00, 0x7e, + 0xb3, 0x3f, 0xf2, 0x30, 0xe0, 0x4b, 0x30, 0x01, 0x46, 0xc2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x7e, + 0x11, 0x09, 0x74, 0x08, 0x19, 0xb2, 0x00, 0x10, 0x74, 0x0e, 0x19, 0xb2, 0x00, 0x04, 0x2e, 0x24, + 0x01, 0x00, 0xa5, 0xd9, 0xed, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0xe4, 0xd5, 0xe0, 0xfd, + 0x09, 0xb2, 0x00, 0x08, 0x20, 0xe0, 0x0a, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x18, 0x80, + 0xeb, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xe4, 0x43, 0x90, 0x30, 0xd2, 0xaa, 0x80, 0x05, 0xd2, + 0xaa, 0x43, 0x90, 0x34, 0xd2, 0xaf, 0xa9, 0xd1, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x11, + 0xdf, 0x03, 0xa9, 0xd2, 0xdf, 0x75, 0x08, 0xff, 0x12, 0x08, 0x33, 0xc0, 0xd1, 0xca, 0x02, 0xff, + 0xca, 0x06, 0x83, 0x00, 0x32, 0xd0, 0xd0, 0x32, 0xc2, 0x8b, 0xc2, 0xaa, 0x32, 0x75, 0x08, 0x08, + 0x12, 0x08, 0x33, 0xa9, 0xc0, 0xb1, 0xa9, 0xc5, 0xd3, 0xa9, 0xc6, 0xd3, 0xa9, 0xd2, 0xb1, 0x32, + 0xca, 0xb8, 0x75, 0x08, 0x02, 0x12, 0x08, 0x33, 0xe5, 0xc0, 0x54, 0x03, 0x68, 0x05, 0x12, 0x01, + 0xee, 0x80, 0xf5, 0xda, 0xb8, 0x32, + +// Segment #14, Start Address 00ff1bca, Length 1 +0xff,0x00,0xca,0x1b,0x01,0x00, + 0x00, + +// Segment #15, Start Address 00ff01e6, Length 1613 +0xff,0x00,0xe6,0x01,0x4d,0x06, + 0xe4, 0x7a, 0xb3, 0x3f, 0xf1, 0x02, 0x02, 0x63, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xca, 0x3b, + 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0xc0, 0xf1, 0x7e, 0xb3, 0x01, 0x2b, + 0xb4, 0x00, 0x02, 0x80, 0x19, 0xb4, 0x01, 0x16, 0x30, 0xc0, 0x08, 0x75, 0xf1, 0x00, 0x12, 0x02, + 0x4d, 0x80, 0x1f, 0x30, 0xc1, 0x1c, 0x75, 0xf1, 0x00, 0x12, 0x02, 0xde, 0x80, 0x14, 0x30, 0xc1, + 0x08, 0x75, 0xf1, 0x00, 0x12, 0x02, 0xde, 0x80, 0x09, 0x30, 0xc0, 0x06, 0x75, 0xf1, 0x00, 0x12, + 0x02, 0x4d, 0xd0, 0xf1, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, 0x5b, 0xda, 0x4b, 0xda, 0x3b, + 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0xc2, 0xc0, 0x7e, 0xb3, 0x01, 0x2b, 0xb4, 0x02, 0x07, + 0x12, 0x02, 0x6f, 0x02, 0x02, 0x63, 0x22, 0xb4, 0x01, 0xfc, 0x02, 0x02, 0xa9, 0x7e, 0x00, 0x00, + 0x7a, 0x03, 0x01, 0x2b, 0x7a, 0x03, 0x01, 0x2c, 0x22, 0x7e, 0xb3, 0x01, 0x23, 0x54, 0x60, 0x60, + 0x05, 0xb4, 0x40, 0x15, 0x80, 0x13, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x05, 0x0c, 0x75, 0x08, 0x71, + 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x26, 0xf5, 0x8f, 0x22, 0x75, 0xf6, 0x00, 0x22, 0xbe, 0x57, + 0x01, 0x29, 0x28, 0x04, 0x7e, 0x57, 0x01, 0x29, 0x7a, 0x0f, 0x01, 0x2e, 0x7a, 0x57, 0x01, 0x32, + 0x02, 0x02, 0xa9, 0x7e, 0xef, 0x01, 0x2e, 0x7e, 0xf7, 0x01, 0x32, 0x7e, 0x07, 0x01, 0x32, 0x4d, + 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0x7e, 0xeb, 0xb0, 0xf5, 0xf3, 0xa3, 0xa5, 0x08, 0x1b, 0xf4, + 0x68, 0x04, 0xa5, 0xb8, 0x08, 0xf0, 0x7a, 0xef, 0x01, 0x2e, 0x7a, 0xf7, 0x01, 0x32, 0x75, 0x08, + 0x06, 0x12, 0x08, 0x33, 0x7a, 0x01, 0xf6, 0x22, 0xc2, 0xc1, 0x75, 0x08, 0x03, 0x12, 0x08, 0x33, + 0xa9, 0x36, 0xe2, 0x16, 0xe5, 0xf5, 0x54, 0xc0, 0x68, 0x07, 0xa9, 0xd7, 0xf4, 0xa9, 0x27, 0xf4, + 0xfc, 0x53, 0xe1, 0x3f, 0x43, 0xf2, 0x88, 0x02, 0x03, 0x55, 0x7e, 0xb3, 0x01, 0x2c, 0xb4, 0x02, + 0x0f, 0xa9, 0xd4, 0xe4, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x01, 0x2c, 0x7a, 0xb3, 0x01, 0x2b, 0x22, + 0xb4, 0x01, 0x39, 0x7e, 0x21, 0xe6, 0x7c, 0x32, 0x7e, 0x13, 0x01, 0x2d, 0x2c, 0x21, 0x7a, 0x23, + 0x01, 0x2d, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x01, 0x34, 0xe5, 0xe3, 0x7a, 0x09, 0xb0, 0x0b, 0x04, + 0xa5, 0xdb, 0xf6, 0xa9, 0xd4, 0xe4, 0x75, 0x08, 0x70, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x2d, + 0x7e, 0xa3, 0x01, 0x2a, 0xbc, 0xab, 0x78, 0x03, 0x12, 0x03, 0xec, 0x22, 0x02, 0x07, 0x55, 0xe5, + 0xe6, 0xb4, 0x08, 0x65, 0xa9, 0xc4, 0xe2, 0x7e, 0x01, 0xe3, 0x7e, 0x11, 0xe3, 0x7e, 0x31, 0xe3, + 0x7e, 0x21, 0xe3, 0x7e, 0x51, 0xe3, 0x7e, 0x41, 0xe3, 0x7e, 0x71, 0xe3, 0x7e, 0x61, 0xe3, 0x7a, + 0x0f, 0x01, 0x23, 0x7a, 0x1f, 0x01, 0x27, 0x75, 0x08, 0x04, 0x12, 0x08, 0x33, 0x7a, 0x01, 0x08, + 0x12, 0x08, 0x33, 0x7a, 0x11, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x21, 0x08, 0x12, 0x08, 0x33, 0x7a, + 0x31, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x41, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x51, 0x08, 0x12, 0x08, + 0x33, 0x7a, 0x61, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x71, 0x08, 0x12, 0x08, 0x33, 0xa9, 0xd4, 0xe4, + 0xa9, 0xd7, 0xf4, 0xa9, 0xc6, 0xe2, 0x12, 0x03, 0xc0, 0x22, 0x6d, 0x00, 0x7e, 0x14, 0x01, 0x02, + 0x7a, 0x07, 0x01, 0x32, 0x7a, 0x03, 0x01, 0x2d, 0x7e, 0xb3, 0x01, 0x23, 0x20, 0xe7, 0x0f, 0x7a, + 0x23, 0x01, 0x2c, 0x7a, 0x33, 0x01, 0x2b, 0xbe, 0x07, 0x01, 0x29, 0x68, 0x09, 0x22, 0x7a, 0x33, + 0x01, 0x2c, 0x7a, 0x23, 0x01, 0x2b, 0x7e, 0xb3, 0x01, 0x23, 0x54, 0xe3, 0x23, 0x23, 0x30, 0xe0, + 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 0x06, 0x30, 0xe4, 0x03, 0x02, 0x07, + 0x55, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 0xf0, 0x90, 0x04, 0x18, 0x75, 0x84, + 0xff, 0x73, 0x02, 0x05, 0x6c, 0x02, 0x04, 0x60, 0x02, 0x06, 0x09, 0x02, 0x06, 0x24, 0x02, 0x05, + 0x05, 0x02, 0x04, 0xc6, 0x02, 0x06, 0x3d, 0x02, 0x06, 0x3d, 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, + 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 0x02, + 0x06, 0x40, 0x02, 0x06, 0x46, 0x02, 0x06, 0xfa, 0x02, 0x06, 0x43, 0x02, 0x06, 0x43, 0x02, 0x06, + 0x43, 0x02, 0x06, 0x43, 0x02, 0x06, 0x43, 0x02, 0x06, 0x43, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x06, + 0x2a, 0x7e, 0xb3, 0x01, 0x25, 0x60, 0x56, 0x7c, 0x0b, 0x7e, 0x13, 0x01, 0x26, 0x7e, 0x17, 0x01, + 0x27, 0x75, 0x08, 0x72, 0x12, 0x08, 0x33, 0x7a, 0x01, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x11, 0x08, + 0x12, 0x08, 0x33, 0x12, 0x07, 0x5f, 0x40, 0x35, 0x02, 0x02, 0x94, 0xb4, 0x08, 0x10, 0x75, 0x08, + 0x74, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x3f, 0xf1, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0xb4, 0x00, + 0x1c, 0x75, 0x08, 0x75, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x3f, 0xf2, 0x30, 0xe0, 0x05, 0x75, 0xf3, + 0x02, 0x80, 0x03, 0x75, 0xf3, 0x00, 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, 0x22, 0x02, 0x07, 0x55, + 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x00, 0x35, 0x75, 0x08, 0x76, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, + 0x28, 0x54, 0x0f, 0xf5, 0xf1, 0x7e, 0xb3, 0x01, 0x28, 0x20, 0xe7, 0x09, 0xe5, 0xe1, 0x30, 0xe7, + 0x0d, 0x74, 0x01, 0x80, 0x0b, 0xe5, 0xe1, 0x30, 0xe6, 0x04, 0x74, 0x01, 0x80, 0x02, 0x74, 0x00, + 0x53, 0xf1, 0x80, 0xf5, 0xf3, 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, 0x22, 0x02, 0x07, 0x55, 0xc0, + 0xf1, 0x7e, 0xb3, 0x01, 0x28, 0x54, 0x0f, 0x42, 0xf1, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x00, 0x45, + 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x01, 0x24, 0x75, 0x08, 0x77, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, + 0x28, 0x54, 0x0f, 0x78, 0x05, 0x53, 0xe1, 0x3f, 0x80, 0x37, 0x7e, 0xb3, 0x01, 0x28, 0x20, 0xe7, + 0x05, 0x53, 0xe1, 0x7f, 0x80, 0x2b, 0x53, 0xe1, 0xbf, 0x80, 0x26, 0xb4, 0x03, 0x17, 0x75, 0x08, + 0x78, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x28, 0x20, 0xe7, 0x05, 0x43, 0xe1, 0x80, 0x80, 0x11, + 0x43, 0xe1, 0x40, 0x80, 0x0c, 0x43, 0xe1, 0xc0, 0xd0, 0xf1, 0x75, 0x08, 0x07, 0x12, 0x08, 0x33, + 0x22, 0xd0, 0xf1, 0x02, 0x02, 0x90, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x09, 0x23, 0x75, 0x08, 0x79, + 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x26, 0xbe, 0xb3, 0x3f, 0xf1, 0x68, 0x11, 0xca, 0xb8, 0xc0, + 0xf1, 0x12, 0x01, 0x1d, 0xd0, 0xf1, 0xda, 0xb8, 0x50, 0x76, 0x7a, 0xb3, 0x3f, 0xf1, 0x80, 0x6d, + 0xb4, 0x05, 0x08, 0x75, 0x08, 0x7a, 0x12, 0x08, 0x33, 0x80, 0x62, 0xb4, 0x03, 0x19, 0x75, 0x08, + 0x7b, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x01, 0x55, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, + 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 0xb4, 0x01, 0x19, 0x75, 0x08, 0x7c, 0x12, 0x08, 0x33, + 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x01, 0x39, 0x7e, 0xb3, 0x3f, 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, + 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 0xb3, 0x01, 0x25, 0x60, 0x24, 0x7c, 0x0b, 0x7e, 0x13, + 0x01, 0x26, 0x7e, 0x17, 0x01, 0x27, 0x75, 0x08, 0x73, 0x12, 0x08, 0x33, 0x7a, 0x01, 0x08, 0x12, + 0x08, 0x33, 0x7a, 0x11, 0x08, 0x12, 0x08, 0x33, 0x12, 0x07, 0x8b, 0x40, 0x03, 0x02, 0x02, 0x90, + 0x02, 0x07, 0x55, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x0b, 0xf6, 0x75, 0x08, 0x7d, 0x12, 0x08, 0x33, + 0x7e, 0xb3, 0x01, 0x26, 0x7e, 0xa3, 0x01, 0x28, 0x4c, 0xab, 0x78, 0xe4, 0x80, 0xdf, 0x7e, 0xb3, + 0x01, 0x24, 0xb4, 0x0a, 0xdb, 0x75, 0x08, 0x7e, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x26, 0x70, + 0xcf, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0x02, 0x07, 0x55, 0x02, 0x07, 0x55, 0x02, 0x07, 0x55, + 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x04, 0x20, 0x75, 0x08, 0xc3, 0x12, 0x08, 0x33, 0x7e, 0x04, 0x00, + 0x01, 0x7e, 0x17, 0x01, 0x25, 0x7e, 0x18, 0x01, 0x34, 0x7a, 0x1c, 0x00, 0x00, 0x7e, 0x47, 0x01, + 0x29, 0x12, 0x08, 0x3f, 0x02, 0x06, 0xf4, 0xb4, 0x06, 0x3a, 0x75, 0x08, 0xc1, 0x12, 0x08, 0x33, + 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, 0xd7, 0x01, 0x25, 0x7e, 0x78, + 0x01, 0x34, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x01, 0x29, 0x75, 0x08, 0xc1, 0x12, 0x08, 0x33, + 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x08, 0xd6, 0xd0, 0x87, 0xd0, 0xa8, + 0x40, 0x4f, 0x80, 0x4a, 0xb4, 0x00, 0x1c, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x02, 0x90, 0xe4, + 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 0xca, 0x02, 0xff, 0xca, 0x06, + 0x00, 0x00, 0x32, 0xb4, 0x09, 0x12, 0x7e, 0x57, 0x01, 0x25, 0x4d, 0x55, 0x68, 0x05, 0xa9, 0xd2, + 0xb1, 0x80, 0x03, 0xa9, 0xc2, 0xb1, 0x80, 0x16, 0xb4, 0x07, 0x16, 0xc2, 0xaf, 0x7e, 0x07, 0x01, + 0x27, 0x7e, 0x17, 0x01, 0x25, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, 0xca, 0x28, 0x32, 0x02, 0x02, + 0x90, 0x02, 0x07, 0x55, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x03, 0x15, 0x75, 0x08, 0xc2, 0x12, 0x08, + 0x33, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x01, 0x25, 0x7e, 0x57, 0x01, 0x29, 0x02, 0x02, 0x94, + 0xb4, 0x05, 0x39, 0x75, 0x08, 0xc0, 0x12, 0x08, 0x33, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, + 0xd5, 0x87, 0x7e, 0x08, 0x01, 0x34, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x37, + 0x01, 0x25, 0x7e, 0x47, 0x01, 0x29, 0x12, 0x08, 0x3f, 0xd0, 0x87, 0xd0, 0xa8, 0x7e, 0x08, 0x01, + 0x34, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x01, 0x29, 0x02, 0x02, 0x94, 0x02, 0x07, 0x55, 0x75, + 0x08, 0x07, 0x12, 0x08, 0x33, 0x43, 0xe1, 0xc0, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, + 0xd5, 0x87, 0x12, 0x07, 0xca, 0x40, 0x19, 0x7e, 0x08, 0x01, 0x34, 0x7a, 0x0c, 0x00, 0x00, 0xca, + 0x0b, 0xca, 0x49, 0x12, 0x08, 0x3f, 0xda, 0x59, 0xda, 0x0b, 0xd0, 0x87, 0xd0, 0xa8, 0xc3, 0x22, + 0xd0, 0x87, 0xd0, 0xa8, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x07, + 0xca, 0x40, 0x2b, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7f, 0x61, 0x7e, 0x78, 0x01, + 0x34, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x01, 0x29, 0xbd, 0x74, 0x78, 0x11, 0x75, 0x08, 0xc1, + 0x12, 0x08, 0x33, 0x12, 0x08, 0xd6, 0x40, 0x06, 0xd0, 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, + 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x34, 0x7f, 0xca, 0x0b, 0x1a, 0x50, 0xc5, + 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, 0x87, 0x7e, 0x34, 0x7f, 0x03, 0x7e, 0x1b, 0xb0, 0xbc, 0x0b, + 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, 0x2d, 0x75, 0x0b, 0x3a, 0x30, 0x69, 0x53, 0x00, + 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, 0x1b, 0x50, 0x30, 0x3e, 0x10, 0x3e, 0x10, 0x0a, + 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, 0x1a, 0x30, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, + 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, 0x90, 0x0a, 0x49, 0x4d, 0x44, 0x68, 0x0c, 0xbe, + 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, 0xff, 0xc3, 0x22, 0xd3, 0x22, + +// Segment #16, EXCLUDED Start Address 00ff7c00, Length 199 + + +// Segment #17, EXCLUDED Start Address 00ff7f00, Length 192 + + +// Segment #17, Start Address 00ff7fc0, Length 64 +0xff,0x00,0xc0,0x7f,0x40,0x00, + 0x40, 0x01, 0x02, 0x00, 0xca, 0x1b, 0x01, 0x0c, 0x02, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +// Segment #18, Start Address 00ff0833, Length 5015 +0xff,0x00,0x33,0x08,0x97,0x13, + 0xca, 0x08, 0x7e, 0x01, 0x08, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x80, 0x50, 0x0b, 0x1a, + 0x60, 0x0b, 0x35, 0x0b, 0x1a, 0x70, 0x0b, 0x35, 0x0b, 0x1a, 0x80, 0x0b, 0x35, 0x0b, 0x1a, 0x90, + 0x0b, 0x35, 0x0b, 0x1a, 0xa0, 0x0b, 0x35, 0x0b, 0x1a, 0xb0, 0x0b, 0x35, 0x0b, 0x1a, 0xc0, 0x0b, + 0x35, 0x0b, 0x1a, 0xd0, 0x0b, 0x35, 0x1b, 0x0a, 0x60, 0x0b, 0x15, 0x1b, 0x0a, 0x70, 0x0b, 0x15, + 0x1b, 0x0a, 0x80, 0x0b, 0x15, 0x1b, 0x0a, 0x90, 0x0b, 0x15, 0x1b, 0x0a, 0xa0, 0x0b, 0x15, 0x1b, + 0x0a, 0xb0, 0x0b, 0x15, 0x1b, 0x0a, 0xc0, 0x0b, 0x15, 0x1b, 0x0a, 0xd0, 0x0b, 0x15, 0x9e, 0x44, + 0x00, 0x10, 0x50, 0xaa, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x0e, 0x7e, 0x1b, 0xc0, 0x7a, 0x0b, 0xc0, + 0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, 0xfc, 0x7c, + 0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, 0x44, 0x00, + 0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, 0xfa, 0x7f, + 0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, 0x40, 0x9d, + 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x09, 0x00, 0xda, 0x79, + 0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x43, 0x90, 0x30, + 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb5, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb5, + 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 0x70, 0x50, 0x06, 0x2d, 0x70, 0x7d, 0x07, 0x6d, 0x77, + 0x7c, 0x31, 0x7e, 0x7b, 0x00, 0x7a, 0x6b, 0x00, 0x0b, 0x7c, 0x0b, 0x6c, 0xa5, 0xd9, 0xf3, 0x7f, + 0x16, 0x1b, 0x1c, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x1b, 0x10, 0xbc, 0x10, 0x68, 0x06, 0x1b, 0x54, + 0x78, 0xf5, 0x80, 0x2c, 0x6d, 0x00, 0x7c, 0x20, 0x7f, 0x16, 0x9f, 0x10, 0x7f, 0x27, 0x9f, 0x20, + 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 0x01, 0x78, 0x16, 0x0b, 0x2c, 0x0b, 0x1c, 0xa5, 0xdb, + 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x03, 0x63, 0x90, 0x30, 0x4d, 0x77, 0x78, 0x93, 0xc2, 0xd7, 0x22, + 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, + 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x04, 0x00, 0x08, 0x10, 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, 0x18, 0x7f, + 0xbd, 0x7a, 0x1c, 0x00, 0xff, 0x0b, 0x1a, 0x00, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, 0x51, 0x23, + 0x7e, 0x18, 0x09, 0x76, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 0x08, 0xa5, + 0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, 0x7e, 0xe8, 0x7f, 0xbf, 0x7a, 0xec, 0x00, + 0xff, 0xe0, 0xf5, 0x22, 0x54, 0xc0, 0x68, 0x16, 0x7e, 0xe8, 0x7f, 0xbe, 0x7a, 0xec, 0x00, 0xff, + 0xe0, 0x60, 0x0c, 0x12, 0x09, 0xa0, 0xf5, 0x09, 0x7a, 0xa1, 0x20, 0x02, 0x0f, 0x0a, 0x22, 0xc2, + 0x95, 0xd2, 0x94, 0x12, 0x19, 0xfb, 0x53, 0x90, 0xcf, 0x12, 0x19, 0xfb, 0x80, 0xf1, 0x0d, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x45, 0x64, 0x67, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x34, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x72, + 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, + 0x73, 0x2c, 0x20, 0x52, 0x65, 0x76, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x3b, 0x20, 0x43, 0x6f, 0x70, + 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x31, 0x39, 0x39, 0x38, 0x20, 0x49, 0x6e, 0x73, 0x69, + 0x64, 0x65, 0x20, 0x4f, 0x75, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x0d, + 0x0a, 0x00, 0x50, 0x61, 0x73, 0x73, 0x00, 0x46, 0x41, 0x49, 0x4c, 0x20, 0x21, 0x21, 0x00, 0x50, + 0x61, 0x73, 0x73, 0x20, 0x20, 0x20, 0x20, 0x00, 0x46, 0x41, 0x49, 0x4c, 0x20, 0x21, 0x21, 0x20, + 0x00, 0x0d, 0x0a, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x20, 0x52, 0x61, 0x6d, 0x3a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x61, 0x6d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x3a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x62, + 0x69, 0x74, 0x20, 0x30, 0x2d, 0x31, 0x34, 0x20, 0x74, 0x65, 0x73, 0x74, 0x3a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x57, 0x72, 0x6f, 0x74, 0x65, 0x20, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x20, 0x30, 0x30, 0x3a, 0x00, 0x20, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x20, 0x00, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, + 0x72, 0x65, 0x61, 0x64, 0x3a, 0x20, 0x00, 0x0d, 0x0a, 0x4f, 0x6e, 0x65, 0x20, 0x6f, 0x72, 0x20, + 0x62, 0x6f, 0x74, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, + 0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x62, 0x69, + 0x74, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x68, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x0d, 0x0a, 0x74, 0x6f, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3a, 0x20, 0x00, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x00, 0x0d, 0x0a, 0x44, 0x65, + 0x74, 0x65, 0x63, 0x74, 0x20, 0x55, 0x61, 0x72, 0x74, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, + 0x53, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x50, 0x61, 0x64, 0x2c, 0x46, 0x69, 0x46, 0x6f, + 0x20, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x26, 0x20, 0x52, 0x53, 0x54, 0x3a, 0x20, 0x00, + 0x0d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x55, 0x61, 0x72, 0x74, 0x20, 0x54, 0x65, 0x73, 0x74, 0x73, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x50, 0x6f, 0x72, 0x74, 0x31, 0x20, 0x20, 0x20, 0x50, 0x6f, 0x72, 0x74, + 0x32, 0x20, 0x20, 0x20, 0x50, 0x6f, 0x72, 0x74, 0x33, 0x20, 0x20, 0x20, 0x50, 0x6f, 0x72, 0x74, + 0x34, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x00, 0x0d, 0x0a, 0x50, 0x6f, 0x72, 0x74, 0x20, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, + 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x41, 0x6e, 0x61, 0x6c, + 0x6f, 0x67, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, + 0x52, 0x58, 0x44, 0x2c, 0x54, 0x58, 0x44, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x54, 0x53, 0x2c, 0x43, + 0x54, 0x53, 0x2c, 0x52, 0x49, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x58, 0x44, 0x2c, 0x54, 0x58, 0x44, 0x20, 0x74, 0x6f, 0x20, 0x44, + 0x54, 0x52, 0x2c, 0x44, 0x53, 0x52, 0x2c, 0x43, 0x44, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x54, 0x53, 0x5b, 0x43, 0x54, 0x53, 0x2c, + 0x52, 0x49, 0x5d, 0x20, 0x74, 0x6f, 0x20, 0x44, 0x54, 0x52, 0x2c, 0x44, 0x53, 0x52, 0x2c, 0x43, + 0x44, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x54, 0x53, 0x5b, + 0x43, 0x54, 0x53, 0x2c, 0x43, 0x44, 0x5d, 0x20, 0x74, 0x6f, 0x20, 0x44, 0x53, 0x52, 0x2c, 0x52, + 0x49, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, + 0x44, 0x54, 0x52, 0x5b, 0x44, 0x53, 0x52, 0x2c, 0x43, 0x44, 0x5d, 0x20, 0x74, 0x6f, 0x20, 0x52, + 0x54, 0x53, 0x2c, 0x43, 0x54, 0x53, 0x2c, 0x52, 0x49, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, + 0x20, 0x00, 0x0d, 0x0a, 0x44, 0x54, 0x52, 0x20, 0x74, 0x6f, 0x20, 0x43, 0x54, 0x53, 0x2c, 0x43, + 0x44, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x54, 0x53, 0x20, 0x74, 0x6f, 0x20, 0x43, + 0x54, 0x53, 0x2c, 0x52, 0x49, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x54, 0x53, 0x20, + 0x74, 0x6f, 0x20, 0x43, 0x54, 0x53, 0x2c, 0x43, 0x44, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, + 0x63, 0x6b, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, + 0x44, 0x54, 0x52, 0x20, 0x74, 0x6f, 0x20, 0x44, 0x53, 0x52, 0x2c, 0x43, 0x44, 0x20, 0x4c, 0x6f, + 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x00, 0x0d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x45, 0x20, 0x52, 0x20, 0x52, 0x20, 0x4f, 0x20, + 0x52, 0x20, 0x21, 0x21, 0x21, 0x2c, 0x20, 0x45, 0x20, 0x52, 0x20, 0x52, 0x20, 0x4f, 0x20, 0x52, + 0x20, 0x21, 0x21, 0x21, 0x20, 0x2c, 0x20, 0x45, 0x20, 0x52, 0x20, 0x52, 0x20, 0x4f, 0x20, 0x52, + 0x20, 0x21, 0x21, 0x21, 0x0d, 0x0a, 0x0a, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, + 0x63, 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x65, 0x6e, 0x74, 0x65, + 0x72, 0x20, 0x61, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x64, 0x65, 0x74, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x00, 0x0d, 0x0a, 0x0a, 0x4e, + 0x6f, 0x20, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x73, 0x20, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2e, 0x0d, 0x0a, 0x00, 0x43, 0x6f, + 0x70, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, + 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x6c, 0x61, 0x76, 0x65, 0x27, + 0x73, 0x20, 0x45, 0x45, 0x70, 0x72, 0x6f, 0x6d, 0x20, 0x2e, 0x2e, 0x2e, 0x00, 0x44, 0x6f, 0x6e, + 0x65, 0x0d, 0x0a, 0x0a, 0x2d, 0x3e, 0x20, 0x54, 0x75, 0x72, 0x6e, 0x20, 0x75, 0x6e, 0x69, 0x74, + 0x20, 0x6f, 0x66, 0x66, 0x2c, 0x20, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x20, 0x63, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x73, + 0x74, 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x20, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, + 0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x00, 0xc2, 0xaf, 0xc2, 0x09, 0xc2, 0x0a, 0x75, 0x90, 0x0d, + 0x20, 0x17, 0x02, 0xd2, 0xb5, 0x43, 0x90, 0x30, 0x6c, 0x00, 0x7e, 0x10, 0x03, 0x12, 0x0f, 0x38, + 0x7e, 0x68, 0x0a, 0x01, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0b, 0x00, 0x30, 0xb4, 0x02, + 0x80, 0x24, 0x02, 0x1b, 0x3c, 0x20, 0x09, 0x1d, 0xc2, 0x94, 0xd2, 0x95, 0x12, 0x19, 0xfb, 0x53, + 0x90, 0xcf, 0x12, 0x19, 0xfb, 0xc2, 0x95, 0xd2, 0x94, 0x12, 0x19, 0xfb, 0xa5, 0xd9, 0xe6, 0x43, + 0x90, 0x30, 0x12, 0x19, 0xfb, 0x22, 0x7e, 0x68, 0x0a, 0x94, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, + 0x93, 0x7e, 0xe4, 0x10, 0x00, 0x7e, 0x40, 0x55, 0x7a, 0xe9, 0x40, 0x0b, 0xe4, 0x7e, 0x50, 0xaa, + 0x7a, 0xe9, 0x50, 0x1b, 0xe4, 0xbe, 0xe9, 0x40, 0x68, 0x19, 0x7e, 0x68, 0x0a, 0x7a, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x13, 0x7a, 0xe9, 0x40, 0x7e, 0xe9, + 0x10, 0x80, 0xf8, 0x7e, 0x68, 0x0a, 0x75, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0b, 0x00, + 0x7e, 0x68, 0x0a, 0xd8, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x78, 0x00, 0x00, 0x7e, + 0x70, 0x0e, 0x7e, 0xa4, 0xff, 0xff, 0x7e, 0xb4, 0xbf, 0xff, 0x7d, 0xcb, 0x0e, 0xc4, 0x7d, 0xdc, + 0x5d, 0xdb, 0x6c, 0xbb, 0x7d, 0xfa, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, + 0xfb, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 0xfc, 0x5e, 0xf4, 0x7f, 0xff, + 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x6c, 0xbb, + 0x7d, 0xfa, 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x41, 0x0b, 0xb0, 0x7d, 0xfb, 0x5e, + 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x34, 0x0b, 0xb0, 0x7d, 0xfc, 0x5e, 0xf4, 0x7f, 0xff, + 0xbe, 0x7b, 0xb0, 0x78, 0x27, 0x0b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, + 0x78, 0x1a, 0x0b, 0xb0, 0xbe, 0xc4, 0xff, 0xfe, 0x78, 0x92, 0x0e, 0xb4, 0xa5, 0xdf, 0x8b, 0x7e, + 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x77, 0xca, 0x5b, 0xca, 0x6b, + 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x68, 0x0b, 0x2a, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0a, 0x47, 0x12, 0x1a, 0xc9, 0x7e, 0x68, 0x0b, 0x79, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x6c, 0x77, 0xda, 0x6b, 0xca, 0x6b, 0x0b, 0x70, 0x0e, 0xc4, + 0xbe, 0xc4, 0xff, 0xff, 0x78, 0xf6, 0x1b, 0x70, 0x0a, 0x47, 0x12, 0x1a, 0xc9, 0x12, 0x1a, 0x08, + 0x30, 0x09, 0x30, 0xda, 0x6b, 0xda, 0x5b, 0x6c, 0xbb, 0x7e, 0x78, 0x00, 0x00, 0x7d, 0xfa, 0x5e, + 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfb, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, + 0xfc, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, + 0xb0, 0x80, 0xd4, 0x7e, 0x68, 0x0a, 0xb6, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x30, 0x17, + 0x0e, 0x7e, 0x78, 0x04, 0x20, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x44, 0x7b, 0xe0, 0x80, 0x0c, 0x7e, + 0x78, 0x00, 0x00, 0x7a, 0x7c, 0x00, 0x01, 0x7e, 0x44, 0x80, 0x00, 0x0b, 0x00, 0x7e, 0x40, 0x3a, + 0x7c, 0x54, 0x7f, 0x57, 0x7d, 0x84, 0x6c, 0x66, 0x7a, 0x5b, 0x50, 0x0b, 0x5c, 0x0b, 0x50, 0xa5, + 0xde, 0x02, 0x0b, 0x50, 0x1b, 0x84, 0x78, 0xf0, 0x7c, 0x54, 0x7f, 0x57, 0x7d, 0x84, 0x6c, 0x66, + 0xbe, 0x5b, 0x50, 0x78, 0x1a, 0x0b, 0x5c, 0x0b, 0x50, 0xa5, 0xde, 0x02, 0x0b, 0x50, 0x1b, 0x84, + 0x78, 0xee, 0x7e, 0x68, 0x0a, 0x75, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x4b, 0x7f, + 0x45, 0x7e, 0x68, 0x0a, 0x7a, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x68, 0x0a, 0xfa, + 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7d, 0x4b, 0x12, 0x1a, 0xc9, 0x7e, 0x68, 0x0b, 0x0f, + 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x6c, 0x88, 0x7c, 0x95, 0x12, 0x1a, 0xc9, 0x7e, 0x68, + 0x0b, 0x1d, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x4b, 0x90, 0x12, 0x1a, 0xc9, 0x12, + 0x1a, 0x08, 0x30, 0x09, 0x05, 0x7e, 0x4b, 0x90, 0x80, 0xfb, 0x7e, 0x68, 0x0b, 0x7f, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0b, 0x00, 0xd2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, + 0x08, 0xbe, 0xb0, 0x01, 0x78, 0x0b, 0x09, 0xb2, 0x00, 0x14, 0xbe, 0xb0, 0x60, 0x78, 0x02, 0x80, + 0x17, 0x7e, 0x68, 0x0a, 0x7a, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, + 0x09, 0x11, 0x09, 0xb2, 0x00, 0x08, 0x80, 0xfa, 0x7e, 0x68, 0x0a, 0x75, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x1a, 0x93, 0x7e, 0x68, 0x0b, 0xa1, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0b, 0x00, + 0xc2, 0x92, 0x12, 0x19, 0xee, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x1c, + 0x7e, 0xb0, 0x01, 0x19, 0xb2, 0x00, 0x08, 0x09, 0xb2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x37, 0x09, + 0xb2, 0x00, 0x08, 0x5e, 0xb0, 0xc0, 0xbe, 0xb0, 0xc0, 0x78, 0x2b, 0x7e, 0xa0, 0xaa, 0x19, 0xa2, + 0x00, 0x1c, 0x6c, 0xbb, 0x19, 0xb2, 0x00, 0x08, 0x09, 0xb2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x16, + 0x09, 0xb2, 0x00, 0x08, 0x5e, 0xb0, 0xc0, 0x78, 0x0d, 0x7e, 0x68, 0x0a, 0x75, 0x7a, 0x6c, 0x00, + 0xff, 0x12, 0x1a, 0x93, 0x80, 0x1b, 0x7e, 0x68, 0x0a, 0x7a, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, + 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x0a, 0x19, 0xa2, 0x00, 0x1c, 0x09, 0xb2, 0x00, 0x1c, 0x80, + 0xf6, 0x7e, 0x68, 0x0b, 0xc3, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x68, 0x0c, 0x45, + 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x7e, 0xb0, + 0x01, 0x19, 0xb2, 0x00, 0x1c, 0x2e, 0x24, 0x01, 0x00, 0x0b, 0xb0, 0xa5, 0xd9, 0xf3, 0x7e, 0x24, + 0x80, 0x00, 0x7e, 0x11, 0x09, 0x7e, 0xb0, 0x01, 0x0b, 0x00, 0x09, 0xa2, 0x00, 0x1c, 0xbc, 0xab, + 0x78, 0x16, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, + 0x00, 0x0b, 0xb0, 0xa5, 0xd9, 0xe2, 0x80, 0x25, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0xe4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, + 0x09, 0xa2, 0x00, 0x1c, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf5, 0x80, 0xec, 0x7e, 0x68, 0x0c, + 0x69, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x13, 0x8a, 0x7e, 0x24, 0x80, 0x00, 0x7e, + 0x11, 0x09, 0x0b, 0x00, 0x74, 0x10, 0x19, 0xb2, 0x00, 0x10, 0x12, 0x13, 0x03, 0x2e, 0x24, 0x01, + 0x00, 0xa5, 0xd9, 0xee, 0x7e, 0x68, 0x0c, 0x8d, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, + 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0xe4, 0x19, 0xb2, 0x00, 0x10, 0x12, 0x13, 0x03, + 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xef, 0x30, 0x00, 0x03, 0x02, 0x18, 0xb7, 0x02, 0x13, 0xbb, + 0x74, 0x07, 0x19, 0xb2, 0x00, 0x08, 0x12, 0x19, 0xfb, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xc2, 0x0b, 0x7e, 0xb0, 0x55, 0x12, 0x13, + 0x64, 0x7e, 0xb0, 0xaa, 0x12, 0x13, 0x64, 0x7e, 0xb0, 0x00, 0x12, 0x13, 0x64, 0x7e, 0xb0, 0xff, + 0x12, 0x13, 0x64, 0x30, 0x0b, 0x0f, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, + 0x93, 0x12, 0x1a, 0x08, 0x22, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, + 0x22, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x09, 0xa2, 0x00, 0x00, 0xbc, 0xab, 0x78, 0x01, + 0x22, 0x20, 0x09, 0x03, 0xd2, 0x0b, 0x22, 0x12, 0x1a, 0x08, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x19, + 0xee, 0x09, 0xa2, 0x00, 0x00, 0x80, 0xf3, 0xd2, 0x92, 0x12, 0x19, 0xee, 0xc2, 0x92, 0x12, 0x19, + 0xee, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x74, 0x80, 0x19, 0xb2, 0x00, 0x0c, 0x7e, 0x54, + 0x00, 0x02, 0x19, 0xa2, 0x00, 0x04, 0x19, 0xb2, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb2, 0x00, 0x0c, + 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xe1, 0x22, 0x7e, 0x68, 0x0c, 0xb1, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x12, 0x19, 0xee, 0x09, + 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, + 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x0d, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, + 0x93, 0x80, 0x1a, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, + 0x08, 0x30, 0x09, 0x09, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x80, 0xf7, 0x2e, 0x24, 0x01, + 0x00, 0xa5, 0xd9, 0xb6, 0x7e, 0x68, 0x0c, 0xd5, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, + 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, + 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, + 0x78, 0x0d, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x1a, 0x7e, + 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x09, + 0x19, 0xa2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x80, 0xf7, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xb6, + 0x30, 0x04, 0x03, 0x02, 0x16, 0x8c, 0x7e, 0x68, 0x0c, 0xf9, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, + 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, + 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, + 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, 0x78, 0x3c, + 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, + 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, + 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, 0x78, 0x14, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x0a, 0x8b, + 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0xe6, 0x7e, 0xa0, 0x02, + 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x0d, 0x41, + 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, + 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x01, + 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, + 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x3c, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, + 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x02, 0x19, 0xa2, + 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x14, 0x7e, 0x68, + 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, + 0x80, 0x20, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, + 0x30, 0x09, 0xe6, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, + 0x80, 0xf1, 0x7e, 0x68, 0x0d, 0x89, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, + 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, + 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x50, 0xbe, 0xb0, 0x50, 0x78, 0x1f, 0x6c, 0xaa, 0x19, 0xa2, + 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x50, 0x78, 0x0d, 0x7e, 0x68, + 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x20, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x0f, 0x7e, 0xa0, 0x02, 0x19, + 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 0x01, 0x00, 0xa5, + 0xd9, 0xa2, 0x7e, 0x68, 0x0d, 0xd1, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, + 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, + 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0xa0, 0xbe, 0xb0, 0xa0, 0x78, 0x1f, + 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0xa0, + 0x78, 0x0d, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x20, 0x7e, + 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x0f, + 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, + 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x02, 0x18, 0x2b, 0x7e, 0x68, 0x0d, 0x1d, 0x7a, 0x6c, 0x00, + 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x6c, 0xaa, 0x19, + 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, + 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, + 0x06, 0x78, 0x3c, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, + 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, + 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x06, 0x78, 0x14, 0x7e, 0x68, 0x0a, 0x82, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, + 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0xe6, + 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, + 0x68, 0x0d, 0x65, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, + 0x09, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, + 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, + 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x09, 0x78, 0x3c, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, + 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, + 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x09, 0x78, + 0x14, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 0x00, + 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, + 0x12, 0x1a, 0x08, 0x30, 0x09, 0xe6, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, + 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x0d, 0xad, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, + 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, + 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x90, 0xbe, 0xb0, 0x90, 0x78, 0x1f, 0x6c, + 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x90, 0x78, + 0x0d, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x20, 0x7e, 0x68, + 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x0f, 0x7e, + 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, + 0x01, 0x00, 0xa5, 0xd9, 0xa2, 0x02, 0x18, 0xb7, 0x30, 0x17, 0x03, 0x02, 0x19, 0x3b, 0xc2, 0x8a, + 0x12, 0x19, 0x22, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x04, + 0x12, 0x19, 0xee, 0x0b, 0x00, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x20, + 0x8b, 0x3e, 0x20, 0x89, 0x3b, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 0x04, 0x09, 0xa2, 0x00, 0x10, + 0x4e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x30, 0x8b, 0x23, 0x30, 0x89, 0x20, + 0x09, 0xa2, 0x00, 0x10, 0x5e, 0xa0, 0xfd, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x7e, 0xa0, + 0x00, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x19, 0xee, 0x20, 0x8b, 0x05, 0x20, 0x89, 0x02, 0x80, 0x1a, + 0x12, 0x1a, 0x08, 0x30, 0x09, 0x14, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x00, 0x00, 0x5e, + 0xa0, 0xfd, 0x19, 0xa2, 0x00, 0x10, 0x00, 0x00, 0x80, 0xec, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, + 0x89, 0x02, 0x19, 0x3b, 0x20, 0x17, 0xfa, 0x12, 0x13, 0x8a, 0x12, 0x19, 0x22, 0x7e, 0x24, 0x80, + 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x20, 0x89, 0x26, 0x7e, 0xa0, 0xff, 0x19, 0xa2, 0x00, 0x04, + 0x12, 0x19, 0xee, 0x7e, 0xb0, 0x55, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x30, 0x89, 0x0f, + 0x7e, 0xa0, 0x00, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x19, 0xee, 0x20, 0x89, 0x02, 0x80, 0x26, 0x12, + 0x1a, 0x08, 0x30, 0x09, 0x20, 0x7e, 0xa0, 0xff, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x19, 0xee, 0x7e, + 0xb0, 0x55, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x7e, 0xa0, 0x00, 0x19, 0xa2, 0x00, 0x04, + 0x12, 0x19, 0xee, 0x80, 0xe0, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xa8, 0x02, 0x19, 0x3b, 0x7e, + 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, + 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xef, 0x22, 0x30, 0x0a, 0x19, 0x7e, 0x68, 0x0d, 0xf5, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0xd2, 0x09, 0x12, 0x19, 0xee, 0x12, 0x19, 0xee, 0x12, 0x19, + 0xee, 0x02, 0x0f, 0x10, 0x30, 0x17, 0x1c, 0x7e, 0x68, 0x0e, 0x6f, 0x7a, 0x6c, 0x00, 0xff, 0x12, + 0x1a, 0x93, 0x7e, 0x68, 0x0e, 0x91, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1b, 0x3c, + 0x02, 0x19, 0xe6, 0x0b, 0x00, 0x7e, 0x78, 0x19, 0xa0, 0x7a, 0x7c, 0x00, 0xff, 0x7f, 0x67, 0x7a, + 0x6c, 0x00, 0x00, 0x7e, 0x70, 0x3e, 0x7e, 0x7b, 0xb0, 0x7a, 0x6b, 0xb0, 0x0b, 0x7c, 0x0b, 0x6c, + 0xa5, 0xdf, 0xf3, 0x7e, 0x78, 0x19, 0xa0, 0x7a, 0x7c, 0x00, 0x00, 0x89, 0x78, 0x7e, 0x78, 0x00, + 0x00, 0x7a, 0x7c, 0x00, 0xfe, 0x7e, 0x68, 0x7f, 0xbf, 0x7a, 0x6c, 0x00, 0xfe, 0x74, 0xaa, 0x39, + 0xb7, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb7, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb7, 0x55, 0x55, 0x6c, + 0x99, 0x7a, 0x6b, 0x90, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x6b, 0x80, 0xbc, 0x89, 0x68, 0x08, 0x1b, + 0x54, 0x78, 0xf5, 0x8a, 0xff, 0x19, 0xde, 0x8a, 0xff, 0x19, 0xe6, 0x12, 0x1a, 0x08, 0x7e, 0x6b, + 0x80, 0x80, 0xfb, 0x7e, 0x10, 0xff, 0x12, 0x1a, 0x85, 0x80, 0xf8, 0xca, 0xf9, 0x7e, 0xf4, 0x00, + 0xff, 0x1b, 0xf4, 0x78, 0xfc, 0xda, 0xf9, 0x22, 0xca, 0xf9, 0x7e, 0xf4, 0x00, 0x00, 0x1b, 0xf4, + 0x78, 0xfc, 0xda, 0xf9, 0x22, 0x20, 0x09, 0x19, 0xd2, 0x0a, 0x12, 0x19, 0xfb, 0xc2, 0x95, 0xd2, + 0x94, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x43, 0x90, 0x30, + 0x22, 0xca, 0x0b, 0x7e, 0x10, 0x03, 0x7c, 0x30, 0x6c, 0x22, 0x0b, 0x20, 0x9e, 0x30, 0x0a, 0x50, + 0xf9, 0x2e, 0x30, 0x0b, 0x1b, 0x20, 0x68, 0x18, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x53, 0x90, + 0xcf, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x43, 0x90, 0x30, 0xa5, 0xda, 0xe8, + 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x1b, 0x30, 0x68, 0x19, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, + 0xc2, 0x95, 0xd2, 0x94, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x43, 0x90, 0x30, + 0xa5, 0xdb, 0xe7, 0x7e, 0x20, 0x0a, 0x12, 0x19, 0xfb, 0xa5, 0xda, 0xfa, 0xa5, 0xd9, 0xa7, 0xda, + 0x0b, 0x22, 0x20, 0x09, 0x0a, 0x12, 0x19, 0xfb, 0xb2, 0x94, 0x12, 0x19, 0xfb, 0xb2, 0x94, 0x22, + 0x30, 0x17, 0x32, 0x20, 0x09, 0x2f, 0xca, 0x2b, 0xca, 0x7b, 0x7e, 0x78, 0x80, 0x00, 0x7a, 0x7c, + 0x00, 0xfe, 0x12, 0x1b, 0x1c, 0x7e, 0x6b, 0xa0, 0x5c, 0xaa, 0x68, 0x10, 0x29, 0xb7, 0x00, 0x14, + 0x54, 0x60, 0x68, 0xf8, 0x39, 0xa7, 0x00, 0x00, 0x0b, 0x6c, 0x80, 0xe9, 0x12, 0x19, 0xee, 0xd2, + 0xb5, 0xda, 0x7b, 0xda, 0x2b, 0x22, 0x12, 0x1a, 0xd4, 0x7e, 0x68, 0x00, 0x0b, 0x12, 0x1a, 0x93, + 0x22, 0xca, 0x59, 0xca, 0x5b, 0x7e, 0xb4, 0x00, 0x0b, 0x7c, 0xb8, 0xc4, 0x12, 0x1b, 0x04, 0x7c, + 0xb8, 0x12, 0x1b, 0x04, 0x7c, 0xb9, 0xc4, 0x12, 0x1b, 0x04, 0x7c, 0xb9, 0x12, 0x1b, 0x04, 0x7e, + 0xb0, 0x68, 0x7a, 0xb9, 0xb0, 0x0b, 0xb4, 0x6c, 0xbb, 0x7a, 0xb9, 0xb0, 0xda, 0x59, 0xda, 0x5b, + 0x22, 0x5e, 0xb0, 0x0f, 0x7c, 0xab, 0x9e, 0xa0, 0x0a, 0x40, 0x05, 0x2e, 0xb0, 0x37, 0x80, 0x03, + 0x2e, 0xb0, 0x30, 0x7a, 0xb9, 0xb0, 0x0b, 0xb4, 0x22, 0xc2, 0xb5, 0xc2, 0x92, 0x12, 0x19, 0xee, + 0x74, 0x80, 0x39, 0xb7, 0x00, 0x0c, 0x7e, 0x54, 0x00, 0x06, 0x39, 0xa7, 0x00, 0x04, 0x39, 0xb7, + 0x00, 0x00, 0x74, 0x03, 0x39, 0xb7, 0x00, 0x0c, 0x22, 0x7e, 0x78, 0x00, 0x00, 0x7a, 0x7c, 0x00, + 0xff, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0x01, 0x7f, 0x65, 0x7e, 0x74, 0x20, 0x00, 0x12, + 0x08, 0xd6, 0x40, 0x54, 0x7e, 0x78, 0x7c, 0x00, 0x7a, 0x7c, 0x00, 0xff, 0x7e, 0x58, 0x00, 0x00, + 0x7a, 0x5c, 0x00, 0x01, 0x7e, 0x68, 0x7c, 0x00, 0x7a, 0x6c, 0x00, 0x01, 0x7e, 0x74, 0x04, 0x00, + 0x12, 0x08, 0xd6, 0x40, 0x33, 0x74, 0x80, 0x12, 0x1b, 0xb1, 0x40, 0x2c, 0x53, 0x90, 0xcf, 0xd2, + 0x08, 0x7e, 0x04, 0x00, 0x08, 0x7e, 0x14, 0x00, 0x00, 0x84, 0xa5, 0xdb, 0xfc, 0xa5, 0xda, 0xf9, + 0xa5, 0xd9, 0xf6, 0x74, 0x40, 0x12, 0x1b, 0xb1, 0x40, 0x0e, 0x7e, 0x68, 0x0e, 0xc0, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x1a, 0x93, 0x02, 0x19, 0xe6, 0xc2, 0x95, 0xd2, 0x94, 0x80, 0xfe, 0xf5, 0x0a, + 0x7e, 0x78, 0x00, 0x0a, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x68, 0x7f, 0xbf, 0x7a, 0x6c, 0x00, 0x01, + 0x7e, 0x74, 0x00, 0x01, 0x02, 0x08, 0xd6, +}; + +static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = { + 1, 12, 2 }; // Major, Minor, Build + +#undef IMAGE_VERSION_NAME + +#undef IMAGE_ARRAY_NAME + diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_fw_boot2.h linux/drivers/usb/serial/io_fw_boot2.h --- v2.4.2/linux/drivers/usb/serial/io_fw_boot2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_fw_boot2.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,548 @@ +//************************************************************** +//* Edgeport/4 Binary Image +//* Generated by HEX2C v1.06 +//* Copyright(c) 1998 Inside Out Networks, All rights reserved. +//* 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. +//************************************************************** + + +//Image structure definition +#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD) +#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD + typedef struct _EDGE_FIRMWARE_IMAGE_RECORD + { + unsigned short ExtAddr; + unsigned short Addr; + unsigned short Len; + unsigned char Data[0]; + } EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD; + + typedef struct _EDGE_FIRMWARE_VERSION_INFO + { + unsigned char MajorVersion; + unsigned char MinorVersion; + unsigned short BuildNumber; + } EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO; + +#endif + +#if !defined(IMAGE_ARRAY_NAME) +#define IMAGE_ARRAY_NAME FirmwareImage +#define IMAGE_VERSION_NAME FirmwareImageVersion +#endif + +static unsigned char IMAGE_ARRAY_NAME[] = { + +// Segment #1, Start Address 00ff0000, Length 6 +0xff,0x00,0x00,0x00,0x06,0x00, + 0x02, 0x00, 0x80, 0x02, 0x00, 0x03, + +// Segment #2, Start Address 00ff000b, Length 3 +0xff,0x00,0x0b,0x00,0x03,0x00, + 0x02, 0x00, 0x0b, + +// Segment #3, Start Address 00ff0013, Length 3 +0xff,0x00,0x13,0x00,0x03,0x00, + 0x02, 0x02, 0x56, + +// Segment #4, Start Address 00ff001b, Length 3 +0xff,0x00,0x1b,0x00,0x03,0x00, + 0x02, 0x00, 0x1b, + +// Segment #5, Start Address 00ff0023, Length 3 +0xff,0x00,0x23,0x00,0x03,0x00, + 0x02, 0x00, 0x23, + +// Segment #6, Start Address 00ff002b, Length 3 +0xff,0x00,0x2b,0x00,0x03,0x00, + 0x02, 0x00, 0x2b, + +// Segment #7, Start Address 00ff0033, Length 3 +0xff,0x00,0x33,0x00,0x03,0x00, + 0x02, 0x00, 0x33, + +// Segment #8, Start Address 00ff003b, Length 3 +0xff,0x00,0x3b,0x00,0x03,0x00, + 0x02, 0x00, 0x3b, + +// Segment #9, Start Address 00ff0043, Length 3 +0xff,0x00,0x43,0x00,0x03,0x00, + 0x02, 0x00, 0x43, + +// Segment #10, Start Address 00ff004b, Length 3 +0xff,0x00,0x4b,0x00,0x03,0x00, + 0x02, 0x00, 0x4b, + +// Segment #11, Start Address 00ff0053, Length 3 +0xff,0x00,0x53,0x00,0x03,0x00, + 0x02, 0x01, 0xf5, + +// Segment #12, Start Address 00ff007b, Length 3 +0xff,0x00,0x7b,0x00,0x03,0x00, + 0x02, 0x00, 0x7b, + +// Segment #13, Start Address 00ff0080, Length 534 +0xff,0x00,0x80,0x00,0x16,0x02, + 0x7e, 0xb3, 0x91, 0x01, 0x20, 0xe3, 0x0c, 0x7e, 0xb3, 0x3f, 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, + 0xf2, 0x80, 0x0a, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x74, 0x00, 0x7a, + 0xb3, 0x91, 0x00, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x7e, 0xf8, 0x00, 0x24, 0x7e, 0x00, 0x01, + 0x7e, 0x10, 0x00, 0x12, 0x09, 0xd0, 0x69, 0x20, 0x00, 0x0a, 0x5e, 0x40, 0x1f, 0xbe, 0x24, 0x00, + 0x00, 0x78, 0x09, 0x7e, 0x00, 0x03, 0x7a, 0x03, 0x90, 0x00, 0x80, 0x07, 0x7e, 0x00, 0x02, 0x7a, + 0x03, 0x90, 0x00, 0x75, 0xb0, 0xdf, 0x7e, 0x00, 0x01, 0x7a, 0x03, 0x94, 0x00, 0x7a, 0x03, 0x01, + 0x24, 0x7e, 0x00, 0x01, 0x7a, 0x03, 0x93, 0x00, 0x7e, 0x00, 0x00, 0xa5, 0xd8, 0xfd, 0x75, 0xa8, + 0x00, 0x75, 0xb1, 0x00, 0xca, 0x29, 0x12, 0x0c, 0x66, 0x12, 0x0c, 0x37, 0xf5, 0x21, 0x7a, 0xa1, + 0x20, 0x20, 0x09, 0x08, 0x20, 0x0a, 0x0a, 0x7e, 0xb0, 0x0c, 0x80, 0x08, 0x7e, 0xb0, 0x00, 0x80, + 0x03, 0x7e, 0xb0, 0x08, 0x7a, 0xb3, 0x92, 0x00, 0x12, 0x02, 0x96, 0xda, 0x29, 0x74, 0x10, 0x7a, + 0xb3, 0x91, 0x01, 0x7e, 0x20, 0x04, 0x7c, 0xb2, 0xc2, 0xd7, 0x13, 0x13, 0x13, 0x13, 0x7a, 0xb3, + 0x91, 0x00, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x10, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x74, 0x02, + 0x7a, 0xb3, 0x91, 0x12, 0xa5, 0xda, 0xdf, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, + 0xb3, 0x91, 0x1c, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x07, 0x74, + 0x34, 0x7a, 0xb3, 0x91, 0x13, 0x74, 0x3f, 0x7a, 0xb3, 0x91, 0x14, 0x74, 0x02, 0x7a, 0xb3, 0x91, + 0x06, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x07, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x44, 0x7a, + 0xb3, 0x91, 0x07, 0x74, 0xef, 0x7a, 0xb3, 0x91, 0x04, 0x74, 0x07, 0x7a, 0xb3, 0x91, 0x06, 0x7e, + 0xb3, 0x91, 0x07, 0x7a, 0xb1, 0x0a, 0x75, 0x09, 0x01, 0xd2, 0xaa, 0xd2, 0xaf, 0xe4, 0x7e, 0x60, + 0x02, 0x4d, 0x22, 0x78, 0x03, 0x7e, 0x60, 0x03, 0x7c, 0x76, 0x7e, 0x04, 0x28, 0x00, 0x8d, 0xef, + 0x1b, 0x04, 0x78, 0xfa, 0x04, 0x7e, 0x20, 0x07, 0x7a, 0x23, 0x91, 0x06, 0x7e, 0x23, 0x91, 0x07, + 0x7e, 0x31, 0x0a, 0xbc, 0x32, 0x68, 0x22, 0x7a, 0x21, 0x0a, 0x7e, 0x21, 0x09, 0x68, 0x17, 0xca, + 0xb8, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0xb3, 0x91, 0x07, 0x44, 0x02, 0x7a, 0xb3, 0x91, + 0x07, 0xda, 0xb8, 0x75, 0x09, 0x00, 0x30, 0xe0, 0xc1, 0x6c, 0x67, 0x7a, 0x63, 0x90, 0x00, 0x80, + 0xb9, 0xbe, 0xb0, 0x02, 0x22, 0xc0, 0xd0, 0x75, 0x08, 0xfe, 0x12, 0x0a, 0xc0, 0x74, 0x02, 0x7a, + 0xb3, 0x91, 0x06, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x07, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x74, + 0x00, 0x7a, 0xb3, 0x91, 0x07, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x04, 0x7e, 0xb3, 0x3f, 0xf2, 0x30, + 0xe0, 0x08, 0x74, 0x18, 0x7a, 0xb3, 0x91, 0x01, 0x80, 0x06, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x01, + 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x04, 0x02, 0x02, 0x36, 0x75, 0x08, 0xff, 0x12, 0x0a, 0xc0, 0x74, + 0x01, 0x7a, 0xb3, 0x91, 0x04, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0xb3, 0x91, 0x07, 0x54, + 0xfc, 0x7a, 0xb3, 0x91, 0x07, 0x32, 0xca, 0xb8, 0x75, 0x08, 0x02, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, + 0x91, 0x03, 0x20, 0xe5, 0x08, 0x30, 0xe0, 0x2b, 0x12, 0x02, 0x9e, 0x80, 0xf1, 0x7e, 0xb3, 0x91, + 0x04, 0x30, 0xe0, 0x05, 0xda, 0xb8, 0x02, 0x02, 0x39, 0x30, 0xe1, 0x05, 0xda, 0xb8, 0x02, 0x01, + 0xf5, 0x30, 0xe6, 0x05, 0x12, 0x04, 0x03, 0x80, 0xd5, 0x30, 0xe2, 0x05, 0xda, 0xb8, 0x02, 0x00, + 0x80, 0x80, 0xcb, 0xda, 0xb8, 0x32, + +// Segment #14, EXCLUDED Start Address 00ff31d7, Length 1 + + +// Segment #15, Start Address 00ff0296, Length 2090 +0xff,0x00,0x96,0x02,0x2a,0x08, + 0xe4, 0x7a, 0xb3, 0x3f, 0xf1, 0x02, 0x03, 0x41, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xca, 0x3b, + 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, + 0x7e, 0xb3, 0x01, 0x2e, 0xb4, 0x00, 0x02, 0x80, 0x1c, 0xb4, 0x01, 0x19, 0x7e, 0xb3, 0x91, 0x14, + 0x54, 0x14, 0x68, 0x05, 0x12, 0x03, 0x05, 0x80, 0x23, 0x7e, 0xb3, 0x91, 0x14, 0x30, 0xe5, 0x1c, + 0x12, 0x04, 0x43, 0x80, 0x17, 0x7e, 0xb3, 0x91, 0x14, 0x30, 0xe5, 0x05, 0x12, 0x04, 0x43, 0x80, + 0x0b, 0x7e, 0xb3, 0x91, 0x14, 0x54, 0x14, 0x68, 0x03, 0x12, 0x03, 0x05, 0xda, 0xeb, 0xda, 0x7b, + 0xda, 0x6b, 0xda, 0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x20, + 0xe4, 0x19, 0x75, 0x08, 0x0a, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x2d, 0x70, 0x0a, 0x7e, 0xb3, + 0x01, 0x2e, 0xb4, 0x01, 0x1f, 0x02, 0x03, 0x9d, 0x02, 0x09, 0x8b, 0x75, 0x08, 0x0b, 0x12, 0x0a, + 0xc0, 0x74, 0x14, 0x7a, 0xb3, 0x91, 0x14, 0x7e, 0xb3, 0x01, 0x2e, 0xb4, 0x02, 0x0c, 0x12, 0x03, + 0x4d, 0x02, 0x03, 0x41, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0x7e, 0x00, 0x00, 0x7a, 0x03, + 0x01, 0x2e, 0x7a, 0x03, 0x01, 0x2f, 0x22, 0x7e, 0xb3, 0x01, 0x25, 0x54, 0x60, 0x60, 0x05, 0xb4, + 0x40, 0x1e, 0x80, 0x1c, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x05, 0x15, 0x75, 0x08, 0x71, 0x12, 0x0a, + 0xc0, 0x7e, 0xb3, 0x01, 0x28, 0x7e, 0xa0, 0x01, 0x7a, 0xa3, 0x91, 0x06, 0x7a, 0xb3, 0x91, 0x07, + 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x12, 0x22, 0xbe, 0x57, + 0x01, 0x2b, 0x28, 0x04, 0x7e, 0x57, 0x01, 0x2b, 0x7a, 0x0f, 0x01, 0x31, 0x7a, 0x57, 0x01, 0x35, + 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x12, 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, + 0x1a, 0x70, 0x53, 0x7e, 0xb3, 0x91, 0x14, 0x20, 0xe4, 0x4c, 0x7e, 0xef, 0x01, 0x31, 0x7e, 0xf7, + 0x01, 0x35, 0x7e, 0x07, 0x01, 0x35, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0xe0, 0x7a, 0xb3, + 0x91, 0x17, 0xa3, 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x06, 0xa5, 0xb8, 0x10, 0xf0, 0x80, 0x19, 0x7e, + 0xb0, 0x00, 0x7a, 0xb3, 0x01, 0x2e, 0xbe, 0x00, 0x10, 0x68, 0x0d, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, + 0x01, 0x2e, 0x74, 0x80, 0x7a, 0xb3, 0x91, 0x1e, 0x7a, 0xef, 0x01, 0x31, 0x7a, 0xf7, 0x01, 0x35, + 0x75, 0x08, 0x06, 0x12, 0x0a, 0xc0, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0xca, 0x0b, 0xca, + 0x1b, 0xca, 0x2b, 0xca, 0x3b, 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0x75, + 0x08, 0x03, 0x12, 0x0a, 0xc0, 0x74, 0x00, 0x7a, 0xb3, 0x01, 0x2d, 0x74, 0x00, 0x7a, 0xb3, 0x91, + 0x00, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x12, 0x04, 0xb2, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, + 0xda, 0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x08, 0x03, + 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x2f, 0xb4, 0x02, 0x11, 0x74, 0x00, 0x7a, 0xb3, 0x01, 0x2f, + 0x7a, 0xb3, 0x01, 0x2e, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0xb4, 0x01, 0x46, 0x7e, 0xb3, + 0x91, 0x04, 0x20, 0xe6, 0x42, 0x7e, 0x23, 0x91, 0x1a, 0x7c, 0x32, 0x7e, 0x13, 0x01, 0x30, 0x2c, + 0x21, 0x7a, 0x23, 0x01, 0x30, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x01, 0x37, 0x7e, 0xb3, 0x91, 0x16, + 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0xa5, 0xdb, 0xf4, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x75, 0x08, + 0x70, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x30, 0x7e, 0xa3, 0x01, 0x2c, 0xbc, 0xab, 0x78, 0x03, + 0x12, 0x05, 0x52, 0x22, 0x02, 0x09, 0x8b, 0xda, 0x59, 0x02, 0x04, 0x15, 0x74, 0xe0, 0x7a, 0xb3, + 0x91, 0x00, 0x7e, 0x03, 0x91, 0x10, 0x7e, 0x13, 0x91, 0x11, 0x7e, 0x33, 0x91, 0x12, 0x7e, 0x23, + 0x91, 0x13, 0x7e, 0x53, 0x91, 0x14, 0x7e, 0x43, 0x91, 0x15, 0x7e, 0x73, 0x91, 0x16, 0x7e, 0x63, + 0x91, 0x17, 0x7a, 0x0f, 0x01, 0x25, 0x7a, 0x1f, 0x01, 0x29, 0x75, 0x08, 0x04, 0x12, 0x0a, 0xc0, + 0x7a, 0x01, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x11, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x21, 0x08, 0x12, + 0x0a, 0xc0, 0x7a, 0x31, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x41, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x51, + 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x61, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x71, 0x08, 0x12, 0x0a, 0xc0, + 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x04, 0x12, 0x05, 0x26, 0x22, + 0x6d, 0x00, 0x7e, 0x14, 0x01, 0x02, 0x7a, 0x07, 0x01, 0x35, 0x7a, 0x03, 0x01, 0x30, 0x7e, 0xb3, + 0x01, 0x25, 0x20, 0xe7, 0x0f, 0x7a, 0x23, 0x01, 0x2f, 0x7a, 0x33, 0x01, 0x2e, 0xbe, 0x07, 0x01, + 0x2b, 0x68, 0x09, 0x22, 0x7a, 0x33, 0x01, 0x2f, 0x7a, 0x23, 0x01, 0x2e, 0x7e, 0xb3, 0x01, 0x25, + 0x54, 0xe3, 0x23, 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, + 0x06, 0x30, 0xe4, 0x03, 0x02, 0x09, 0x8b, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, + 0xf0, 0x90, 0x05, 0x7e, 0x75, 0x84, 0xff, 0x73, 0x02, 0x07, 0x39, 0x02, 0x05, 0xc6, 0x02, 0x07, + 0xd2, 0x02, 0x07, 0xed, 0x02, 0x06, 0xd0, 0x02, 0x06, 0x5b, 0x02, 0x08, 0x1e, 0x02, 0x08, 0x1e, + 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, + 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x27, 0x02, 0x08, 0xf9, 0x02, 0x08, + 0x24, 0x02, 0x08, 0x24, 0x02, 0x08, 0x24, 0x02, 0x08, 0x24, 0x02, 0x08, 0x24, 0x02, 0x08, 0x24, + 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 0xb3, 0x01, 0x26, + 0xb4, 0x06, 0x2a, 0x7e, 0xb3, 0x01, 0x27, 0x60, 0x79, 0x7c, 0x0b, 0x7e, 0x13, 0x01, 0x28, 0x7e, + 0x17, 0x01, 0x29, 0x75, 0x08, 0x72, 0x12, 0x0a, 0xc0, 0x7a, 0x01, 0x08, 0x12, 0x0a, 0xc0, 0x7a, + 0x11, 0x08, 0x12, 0x0a, 0xc0, 0x12, 0x09, 0xd0, 0x40, 0x58, 0x02, 0x03, 0x84, 0xb4, 0x08, 0x1c, + 0x75, 0x08, 0x74, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x3f, 0xf1, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, + 0x00, 0x00, 0x7a, 0x0b, 0xb0, 0x7e, 0x54, 0x00, 0x01, 0x02, 0x03, 0x84, 0xb4, 0x00, 0x33, 0x75, + 0x08, 0x75, 0x12, 0x0a, 0xc0, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0x7e, + 0xb3, 0x3f, 0xf2, 0x30, 0xe0, 0x07, 0x74, 0x02, 0x7a, 0x0b, 0xb0, 0x80, 0x05, 0x74, 0x00, 0x7a, + 0x0b, 0xb0, 0x0b, 0x14, 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x7e, 0x54, 0x00, 0x02, 0xda, 0x0b, 0x02, + 0x03, 0x84, 0x02, 0x09, 0x8b, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, + 0x1c, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x00, 0x5f, 0x75, 0x08, 0x76, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, + 0x01, 0x2a, 0x54, 0x0f, 0xb4, 0x02, 0x05, 0x7e, 0xb0, 0x60, 0x80, 0x17, 0xb4, 0x00, 0x05, 0x7e, + 0xb0, 0x00, 0x80, 0x0f, 0x7e, 0xb3, 0x01, 0x2a, 0x20, 0xe7, 0x05, 0x7e, 0xb0, 0x40, 0x80, 0x03, + 0x7e, 0xb0, 0x20, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x11, 0x30, 0xe0, 0x04, 0x74, 0x01, + 0x80, 0x02, 0x74, 0x00, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0x7a, 0x0b, + 0xb0, 0x0b, 0x14, 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0x54, + 0x00, 0x02, 0xda, 0x0b, 0x02, 0x03, 0x84, 0x02, 0x09, 0x8b, 0x7e, 0xb3, 0x01, 0x2a, 0x54, 0x0f, + 0xb4, 0x02, 0x05, 0x7e, 0xb0, 0x60, 0x80, 0x17, 0xb4, 0x00, 0x05, 0x7e, 0xb0, 0x00, 0x80, 0x0f, + 0x7e, 0xb3, 0x01, 0x2a, 0x20, 0xe7, 0x05, 0x7e, 0xb0, 0x40, 0x80, 0x03, 0x7e, 0xb0, 0x20, 0x7a, + 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x01, 0x28, 0xb4, 0x00, 0x26, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x01, + 0x0e, 0x75, 0x08, 0x77, 0x12, 0x0a, 0xc0, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x80, 0x1b, 0xb4, + 0x03, 0x0e, 0x75, 0x08, 0x78, 0x12, 0x0a, 0xc0, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x11, 0x80, 0x0a, + 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x12, 0x09, 0x8b, 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, + 0x02, 0x03, 0x77, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x09, 0x1f, 0x75, 0x08, 0x79, 0x12, 0x0a, 0xc0, + 0x7e, 0xb3, 0x01, 0x28, 0xbe, 0xb3, 0x3f, 0xf1, 0x68, 0x0d, 0xca, 0xb8, 0x12, 0x01, 0xf1, 0xda, + 0xb8, 0x50, 0x76, 0x7a, 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x08, 0x7a, 0x12, + 0x0a, 0xc0, 0x80, 0x62, 0xb4, 0x03, 0x19, 0x75, 0x08, 0x7b, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, + 0x28, 0xb4, 0x01, 0x55, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, + 0xb4, 0x01, 0x19, 0x75, 0x08, 0x7c, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x28, 0xb4, 0x01, 0x39, + 0x7e, 0xb3, 0x3f, 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, + 0xb3, 0x01, 0x27, 0x60, 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x01, 0x28, 0x7e, 0x17, 0x01, 0x29, 0x75, + 0x08, 0x73, 0x12, 0x0a, 0xc0, 0x7a, 0x01, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x11, 0x08, 0x12, 0x0a, + 0xc0, 0x12, 0x0a, 0x0a, 0x40, 0x03, 0x02, 0x03, 0x77, 0x02, 0x09, 0x8b, 0x7e, 0xb3, 0x01, 0x26, + 0xb4, 0x0b, 0xf6, 0x75, 0x08, 0x7d, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x28, 0x7e, 0xa3, 0x01, + 0x2a, 0x4c, 0xab, 0x78, 0xe4, 0x80, 0xdf, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, + 0xb3, 0x91, 0x1c, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x0a, 0xcf, 0x75, 0x08, 0x7e, 0x12, 0x0a, 0xc0, + 0x7e, 0xb3, 0x01, 0x28, 0x70, 0xc3, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0x7a, 0x0b, + 0xb0, 0x7e, 0x54, 0x00, 0x01, 0x02, 0x03, 0x84, 0x02, 0x09, 0x8b, 0x02, 0x09, 0x8b, 0x02, 0x09, + 0x8b, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x04, 0x20, 0x75, 0x08, 0xc3, 0x12, 0x0a, 0xc0, 0x7e, 0x04, + 0x00, 0x01, 0x7e, 0x17, 0x01, 0x27, 0x7e, 0x18, 0x01, 0x37, 0x7a, 0x1c, 0x00, 0x00, 0x7e, 0x47, + 0x01, 0x2b, 0x12, 0x0a, 0xcc, 0x02, 0x08, 0xf3, 0xb4, 0x06, 0x42, 0x75, 0x08, 0xc1, 0x12, 0x0a, + 0xc0, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, 0xd7, 0x01, 0x27, 0x7e, + 0x78, 0x01, 0x37, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x01, 0x2b, 0x75, 0x08, 0xc1, 0x12, 0x0a, + 0xc0, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 0x0b, 0x63, 0x7e, + 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0x40, 0x65, 0x80, 0x60, 0xb4, 0x00, 0x24, + 0xc2, 0xaf, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x94, 0x00, 0x7a, 0xb3, 0x01, 0x24, 0x12, 0x03, 0x77, + 0xe4, 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 0xca, 0x02, 0xff, 0xca, + 0x06, 0x00, 0x00, 0x32, 0xb4, 0x09, 0x20, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0x23, 0x91, + 0x07, 0x7e, 0x57, 0x01, 0x27, 0x4d, 0x55, 0x68, 0x05, 0x4e, 0x20, 0x02, 0x80, 0x03, 0x5e, 0x20, + 0xfd, 0x7a, 0x23, 0x91, 0x07, 0x80, 0x16, 0xb4, 0x07, 0x16, 0xc2, 0xaf, 0x7e, 0x07, 0x01, 0x29, + 0x7e, 0x17, 0x01, 0x27, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, 0xca, 0x28, 0x32, 0x02, 0x03, 0x77, + 0x02, 0x09, 0x8b, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, + 0xb3, 0x01, 0x26, 0xb4, 0x03, 0x15, 0x75, 0x08, 0xc2, 0x12, 0x0a, 0xc0, 0x7e, 0x04, 0x00, 0x01, + 0x7e, 0x17, 0x01, 0x27, 0x7e, 0x57, 0x01, 0x2b, 0x02, 0x03, 0x84, 0xb4, 0x05, 0x41, 0x75, 0x08, + 0xc0, 0x12, 0x0a, 0xc0, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x7e, + 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x01, 0x27, 0x7e, + 0x47, 0x01, 0x2b, 0x12, 0x0a, 0xcc, 0x7e, 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, + 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x01, 0x2b, 0x02, 0x03, 0x84, 0xb4, + 0x01, 0x20, 0x7e, 0x00, 0x00, 0x7e, 0x10, 0x01, 0x75, 0x08, 0x72, 0x12, 0x0a, 0xc0, 0x7a, 0x01, + 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x11, 0x08, 0x12, 0x0a, 0xc0, 0x12, 0x09, 0xd0, 0x40, 0x03, 0x02, + 0x03, 0x84, 0x02, 0x09, 0x8b, 0x75, 0x08, 0x07, 0x12, 0x0a, 0xc0, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, + 0x90, 0x00, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x15, 0x74, 0x01, + 0x7a, 0xb3, 0x91, 0x11, 0x7e, 0xb3, 0x91, 0x15, 0x54, 0x60, 0xbe, 0xb0, 0x40, 0x68, 0x08, 0x74, + 0x20, 0x7a, 0xb3, 0x91, 0x15, 0x80, 0xed, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x74, 0x04, 0x7a, + 0xb3, 0x91, 0x14, 0x74, 0xff, 0x7a, 0xb3, 0x01, 0x2d, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, + 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 0x0a, 0x57, 0x40, 0x1f, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, + 0x00, 0x00, 0xca, 0x0b, 0xca, 0x49, 0x12, 0x0a, 0xcc, 0xda, 0x59, 0xda, 0x0b, 0x7e, 0x43, 0x01, + 0x24, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0xc3, 0x22, 0x7e, 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, + 0x00, 0xd0, 0xa8, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, + 0x0a, 0x57, 0x40, 0x31, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7f, 0x61, 0x7e, 0x78, + 0x01, 0x37, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x01, 0x2b, 0xbd, 0x74, 0x78, 0x17, 0x75, 0x08, + 0xc1, 0x12, 0x0a, 0xc0, 0x12, 0x0b, 0x63, 0x40, 0x0c, 0x7e, 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, + 0x00, 0xd0, 0xa8, 0xc3, 0x22, 0x7e, 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0xd3, + 0x22, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x34, 0x7f, 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, + 0x7d, 0x75, 0x7d, 0x87, 0x7e, 0x34, 0x7f, 0x03, 0x7e, 0x1b, 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, + 0x00, 0x3e, 0x00, 0x0a, 0x50, 0x2d, 0x75, 0x0b, 0x3a, 0x30, 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, + 0x50, 0x02, 0x2d, 0x38, 0xbc, 0x1b, 0x50, 0x30, 0x3e, 0x10, 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, + 0x69, 0x41, 0x00, 0x02, 0x0b, 0x1a, 0x30, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, + 0xff, 0x78, 0x05, 0x7e, 0x1b, 0x90, 0x0a, 0x49, 0x4d, 0x44, 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, + 0x28, 0x04, 0x7e, 0x44, 0x00, 0xff, 0xc3, 0x22, 0xd3, 0x22, + +// Segment #16, EXCLUDED Start Address 00ff7c00, Length 227 + + +// Segment #17, EXCLUDED Start Address 00ff7f00, Length 192 + + +// Segment #17, Start Address 00ff7fc0, Length 64 +0xff,0x00,0xc0,0x7f,0x40,0x00, + 0x40, 0x01, 0x02, 0x00, 0xd7, 0x31, 0x02, 0x00, 0x03, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +// Segment #18, Start Address 00ff0ac0, Length 4163 +0xff,0x00,0xc0,0x0a,0x43,0x10, + 0xca, 0x08, 0x7e, 0x01, 0x08, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x80, 0x50, 0x0b, 0x1a, + 0x60, 0x0b, 0x35, 0x0b, 0x1a, 0x70, 0x0b, 0x35, 0x0b, 0x1a, 0x80, 0x0b, 0x35, 0x0b, 0x1a, 0x90, + 0x0b, 0x35, 0x0b, 0x1a, 0xa0, 0x0b, 0x35, 0x0b, 0x1a, 0xb0, 0x0b, 0x35, 0x0b, 0x1a, 0xc0, 0x0b, + 0x35, 0x0b, 0x1a, 0xd0, 0x0b, 0x35, 0x1b, 0x0a, 0x60, 0x0b, 0x15, 0x1b, 0x0a, 0x70, 0x0b, 0x15, + 0x1b, 0x0a, 0x80, 0x0b, 0x15, 0x1b, 0x0a, 0x90, 0x0b, 0x15, 0x1b, 0x0a, 0xa0, 0x0b, 0x15, 0x1b, + 0x0a, 0xb0, 0x0b, 0x15, 0x1b, 0x0a, 0xc0, 0x0b, 0x15, 0x1b, 0x0a, 0xd0, 0x0b, 0x15, 0x9e, 0x44, + 0x00, 0x10, 0x50, 0xaa, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x0e, 0x7e, 0x1b, 0xc0, 0x7a, 0x0b, 0xc0, + 0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, 0xfc, 0x7c, + 0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, 0x44, 0x00, + 0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, 0xfa, 0x7f, + 0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, 0x40, 0x9d, + 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x0b, 0x8d, 0xda, 0x79, + 0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x7e, 0xc0, 0x03, + 0x7e, 0xd0, 0x00, 0x7a, 0xd3, 0x90, 0x00, 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 0x55, 0x39, + 0xb5, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb5, 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 0x70, 0x50, + 0x06, 0x2d, 0x70, 0x7d, 0x07, 0x6d, 0x77, 0x7c, 0x31, 0x7e, 0x7b, 0x00, 0x7a, 0x6b, 0x00, 0x0b, + 0x7c, 0x0b, 0x6c, 0xa5, 0xd9, 0xf3, 0x7f, 0x16, 0x1b, 0x1c, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x1b, + 0x10, 0xbc, 0x10, 0x68, 0x06, 0x1b, 0x54, 0x78, 0xf5, 0x80, 0x2f, 0x6d, 0x00, 0x7c, 0x20, 0x7f, + 0x16, 0x9f, 0x10, 0x7f, 0x27, 0x9f, 0x20, 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 0x01, 0x78, + 0x19, 0x0b, 0x2c, 0x0b, 0x1c, 0xa5, 0xdb, 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x06, 0x6c, 0xdc, 0x7a, + 0xd3, 0x90, 0x00, 0x4d, 0x77, 0x78, 0x90, 0xc2, 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x08, 0x10, 0x02, 0x10, + 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, 0x18, 0x7f, 0xbd, 0x7a, 0x1c, 0x00, 0xff, 0x0b, + 0x1a, 0x00, 0x5e, 0x10, 0x1f, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, 0x51, 0x23, 0x7e, 0x18, 0x0c, + 0x0d, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 0x08, 0xa5, 0xb8, 0x02, 0x03, + 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, 0x7e, 0xe8, 0x7f, 0xbf, 0x7a, 0xec, 0x00, 0xff, 0xe0, 0xf5, + 0x23, 0x54, 0xc0, 0x68, 0x38, 0x7e, 0xe8, 0x7f, 0xbe, 0x7a, 0xec, 0x00, 0xff, 0xe0, 0x60, 0x2e, + 0x12, 0x0c, 0x37, 0xf5, 0x21, 0x7a, 0xa1, 0x20, 0x20, 0x09, 0x0c, 0x20, 0x0a, 0x12, 0x7e, 0xb0, + 0x0e, 0x7a, 0xb3, 0x92, 0x00, 0x80, 0x10, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x92, 0x00, 0x80, 0x07, + 0x7e, 0xb0, 0x0a, 0x7a, 0xb3, 0x92, 0x00, 0x7a, 0xb1, 0x0d, 0x02, 0x0c, 0xc4, 0x22, 0x7e, 0xb0, + 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x03, 0x7a, 0xb3, 0x90, 0x00, 0x12, + 0x19, 0x0c, 0x80, 0xea, 0xc2, 0xaf, 0xc2, 0x11, 0xc2, 0x12, 0x75, 0xb0, 0xdf, 0x7e, 0x00, 0x01, + 0x7a, 0x03, 0x93, 0x00, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x90, 0x00, 0x6c, 0x00, 0x7e, 0x10, 0x03, + 0x12, 0x0c, 0xf5, 0x7e, 0x68, 0x2c, 0x66, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x0b, 0x00, + 0x80, 0x32, 0x02, 0x1a, 0x6e, 0x20, 0x11, 0x2b, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x90, 0x00, 0x12, + 0x19, 0x0c, 0x7e, 0xb0, 0x03, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x02, 0x7a, + 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0xa5, 0xd9, 0xdc, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x90, 0x00, + 0x12, 0x19, 0x0c, 0x22, 0x7e, 0x68, 0x2c, 0xf9, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, + 0xe4, 0x10, 0x00, 0x7e, 0x40, 0x55, 0x7a, 0xe9, 0x40, 0x0b, 0xe4, 0x7e, 0x50, 0xaa, 0x7a, 0xe9, + 0x50, 0x1b, 0xe4, 0xbe, 0xe9, 0x40, 0x68, 0x19, 0x7e, 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0x13, 0x7a, 0xe9, 0x40, 0x7e, 0xe9, 0x10, 0x80, + 0xf8, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x0b, 0x00, 0x7e, 0x68, + 0x2d, 0x3d, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x78, 0x00, 0x00, 0x7e, 0x70, 0x0e, + 0x7e, 0xa4, 0xff, 0xff, 0x7e, 0xb4, 0xbf, 0xff, 0x7d, 0xcb, 0x0e, 0xc4, 0x7d, 0xdc, 0x5d, 0xdb, + 0x6c, 0xbb, 0x7d, 0xfa, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 0xfb, 0x5e, + 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 0xfc, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, + 0xb0, 0x0b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x6c, 0xbb, 0x7d, 0xfa, + 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x41, 0x0b, 0xb0, 0x7d, 0xfb, 0x5e, 0xf4, 0x7f, + 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x34, 0x0b, 0xb0, 0x7d, 0xfc, 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, + 0xb0, 0x78, 0x27, 0x0b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x1a, + 0x0b, 0xb0, 0xbe, 0xc4, 0xff, 0xfe, 0x78, 0x92, 0x0e, 0xb4, 0xa5, 0xdf, 0x8b, 0x7e, 0x68, 0x2c, + 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x77, 0xca, 0x5b, 0xca, 0x6b, 0x7e, 0x68, + 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x2d, 0x8f, 0x7a, 0x6c, 0x00, + 0xff, 0x12, 0x19, 0xc4, 0x0a, 0x47, 0x12, 0x19, 0xfa, 0x7e, 0x68, 0x2d, 0xde, 0x7a, 0x6c, 0x00, + 0xff, 0x12, 0x19, 0xc4, 0x6c, 0x77, 0xda, 0x6b, 0xca, 0x6b, 0x0b, 0x70, 0x0e, 0xc4, 0xbe, 0xc4, + 0xff, 0xff, 0x78, 0xf6, 0x1b, 0x70, 0x0a, 0x47, 0x12, 0x19, 0xfa, 0x12, 0x19, 0x19, 0x30, 0x11, + 0x30, 0xda, 0x6b, 0xda, 0x5b, 0x6c, 0xbb, 0x7e, 0x78, 0x00, 0x00, 0x7d, 0xfa, 0x5e, 0xf4, 0x7f, + 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfb, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfc, 0x5e, + 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x80, + 0xd4, 0x7e, 0x68, 0x2d, 0x1b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x30, 0x1f, 0x0e, 0x7e, + 0x78, 0x04, 0x20, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x44, 0x7b, 0xe0, 0x80, 0x0c, 0x7e, 0x78, 0x00, + 0x00, 0x7a, 0x7c, 0x00, 0x01, 0x7e, 0x44, 0x80, 0x00, 0x0b, 0x00, 0x7e, 0x40, 0x3a, 0x7c, 0x54, + 0x7f, 0x57, 0x7d, 0x84, 0x6c, 0x66, 0x7a, 0x5b, 0x50, 0x0b, 0x5c, 0x0b, 0x50, 0xa5, 0xde, 0x02, + 0x0b, 0x50, 0x1b, 0x84, 0x78, 0xf0, 0x7c, 0x54, 0x7f, 0x57, 0x7d, 0x84, 0x6c, 0x66, 0xbe, 0x5b, + 0x50, 0x78, 0x1a, 0x0b, 0x5c, 0x0b, 0x50, 0xa5, 0xde, 0x02, 0x0b, 0x50, 0x1b, 0x84, 0x78, 0xee, + 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x4b, 0x7f, 0x45, 0x7e, + 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x2d, 0x5f, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7d, 0x4b, 0x12, 0x19, 0xfa, 0x7e, 0x68, 0x2d, 0x74, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x19, 0xc4, 0x6c, 0x88, 0x7c, 0x95, 0x12, 0x19, 0xfa, 0x7e, 0x68, 0x2d, 0x82, + 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x4b, 0x90, 0x12, 0x19, 0xfa, 0x12, 0x19, 0x19, + 0x30, 0x11, 0x05, 0x7e, 0x4b, 0x90, 0x80, 0xfb, 0x7e, 0x68, 0x2e, 0x28, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x19, 0xc4, 0x0b, 0x00, 0x7e, 0xb0, 0x80, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xa0, 0x55, 0x7a, + 0xa3, 0x91, 0x10, 0x7e, 0xb3, 0x91, 0x07, 0x7e, 0xb3, 0x91, 0x10, 0xbc, 0xab, 0x78, 0x20, 0x7e, + 0xa0, 0xaa, 0x7a, 0xa3, 0x91, 0x10, 0x7e, 0xb3, 0x91, 0x07, 0x7e, 0xb3, 0x91, 0x10, 0xbc, 0xab, + 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x1b, 0x7e, + 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0x0a, + 0x7a, 0xa3, 0x91, 0x10, 0x7e, 0xb3, 0x91, 0x10, 0x80, 0xf6, 0x7e, 0x68, 0x2e, 0x4a, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x12, 0x31, 0x0b, 0x00, 0x7e, 0xe4, 0x10, 0x00, 0x7e, 0xa0, + 0xa5, 0xca, 0xa8, 0x7a, 0xe9, 0xa0, 0x7e, 0xb0, 0x30, 0x7a, 0xb3, 0x95, 0x00, 0x7e, 0xe9, 0xa0, + 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x95, 0x00, 0x12, 0x19, 0x0c, 0x0b, 0xe5, 0x7e, 0xb0, 0x20, 0x7a, + 0xb3, 0x95, 0x00, 0x7e, 0xe9, 0xb0, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x95, 0x00, 0x7e, 0xe9, 0xb0, + 0xda, 0xa8, 0xbc, 0xab, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, + 0xc4, 0x80, 0x1d, 0x7e, 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, + 0x19, 0x30, 0x11, 0x0c, 0x7e, 0xb0, 0x38, 0x7a, 0xb3, 0x95, 0x00, 0x7e, 0xe9, 0xb0, 0x80, 0xfb, + 0x80, 0x00, 0x7e, 0x68, 0x2d, 0xe4, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x0b, 0x00, 0x75, + 0xb0, 0xdf, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, 0x08, 0xbe, 0xb0, 0x01, 0x78, 0x0b, 0x09, + 0xb2, 0x00, 0x14, 0xbe, 0xb0, 0x60, 0x78, 0x02, 0x80, 0x17, 0x7e, 0x68, 0x2c, 0xdf, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0x11, 0x09, 0xb2, 0x00, 0x08, 0x80, + 0xfa, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x2e, 0x06, + 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x0b, 0x00, 0x75, 0xb0, 0xef, 0x12, 0x18, 0xff, 0x7e, + 0x24, 0x80, 0x00, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x1c, 0x7e, 0xb0, 0x01, 0x19, 0xb2, 0x00, + 0x08, 0x09, 0xb2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x37, 0x09, 0xb2, 0x00, 0x08, 0x5e, 0xb0, 0xc0, + 0xbe, 0xb0, 0xc0, 0x78, 0x2b, 0x7e, 0xa0, 0xaa, 0x19, 0xa2, 0x00, 0x1c, 0x6c, 0xbb, 0x19, 0xb2, + 0x00, 0x08, 0x09, 0xb2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x16, 0x09, 0xb2, 0x00, 0x08, 0x5e, 0xb0, + 0xc0, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x1b, + 0x7e, 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, + 0x0a, 0x19, 0xa2, 0x00, 0x1c, 0x09, 0xb2, 0x00, 0x1c, 0x80, 0xf6, 0x7e, 0x68, 0x2e, 0x6c, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x2e, 0xee, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, + 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x7e, 0xb0, 0x01, 0x19, 0xb2, 0x00, 0x1c, 0x2e, + 0x24, 0x01, 0x00, 0x0b, 0xb0, 0xa5, 0xd9, 0xf3, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x7e, + 0xb0, 0x01, 0x0b, 0x00, 0x09, 0xa2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x16, 0x7e, 0x68, 0x2c, 0xe7, + 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 0x0b, 0xb0, 0xa5, 0xd9, 0xe2, + 0x80, 0x25, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, + 0x30, 0x11, 0xe4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x09, 0xa2, 0x00, 0x1c, 0x2e, 0x24, + 0x01, 0x00, 0xa5, 0xd9, 0xf5, 0x80, 0xec, 0x7e, 0x68, 0x2f, 0x12, 0x7a, 0x6c, 0x00, 0xff, 0x12, + 0x19, 0xc4, 0x12, 0x12, 0x31, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x74, 0x10, + 0x19, 0xb2, 0x00, 0x10, 0x12, 0x11, 0xaa, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xee, 0x7e, 0x68, + 0x2f, 0x36, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, + 0x0b, 0x00, 0xe4, 0x19, 0xb2, 0x00, 0x10, 0x12, 0x11, 0xaa, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, + 0xef, 0x30, 0x00, 0x03, 0x02, 0x17, 0x3b, 0x02, 0x12, 0x6a, 0x74, 0x07, 0x19, 0xb2, 0x00, 0x08, + 0x12, 0x19, 0x0c, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, + 0xb2, 0x00, 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, + 0xb2, 0x00, 0x14, 0xc2, 0x13, 0x7e, 0xb0, 0x55, 0x12, 0x12, 0x0b, 0x7e, 0xb0, 0xaa, 0x12, 0x12, + 0x0b, 0x7e, 0xb0, 0x00, 0x12, 0x12, 0x0b, 0x7e, 0xb0, 0xff, 0x12, 0x12, 0x0b, 0x30, 0x13, 0x0f, + 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x22, 0x7e, + 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x22, 0x19, 0xb2, 0x00, 0x00, 0x12, + 0x18, 0xff, 0x09, 0xa2, 0x00, 0x00, 0xbc, 0xab, 0x78, 0x01, 0x22, 0x20, 0x11, 0x03, 0xd2, 0x13, + 0x22, 0x12, 0x19, 0x19, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x09, 0xa2, 0x00, 0x00, 0x80, + 0xf3, 0x75, 0xb0, 0xdf, 0x12, 0x18, 0xff, 0x75, 0xb0, 0xef, 0x12, 0x18, 0xff, 0x7e, 0x24, 0x80, + 0x00, 0x7e, 0x11, 0x21, 0x74, 0x80, 0x19, 0xb2, 0x00, 0x0c, 0x7e, 0x54, 0x00, 0x02, 0x19, 0xa2, + 0x00, 0x04, 0x19, 0xb2, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb2, 0x00, 0x0c, 0x74, 0x06, 0x19, 0xb2, + 0x00, 0x08, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xdb, 0x22, 0x7e, 0x68, 0x2f, 0x5a, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x12, 0x18, + 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x09, + 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x19, 0xc4, 0x80, 0x1a, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, + 0x12, 0x19, 0x19, 0x30, 0x11, 0x09, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x80, 0xf7, 0x2e, + 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xb6, 0x7e, 0x68, 0x2f, 0x7e, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, + 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, + 0x18, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, + 0xb0, 0x0a, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, + 0x1a, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, + 0x11, 0x09, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x80, 0xf7, 0x2e, 0x24, 0x01, 0x00, 0xa5, + 0xd9, 0xb6, 0x30, 0x04, 0x03, 0x02, 0x15, 0x9f, 0x7e, 0x68, 0x2f, 0xa2, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, + 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, + 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, + 0x78, 0x3c, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, + 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, + 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, 0x78, 0x14, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, + 0x00, 0xff, 0x12, 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, + 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0xe6, 0x7e, + 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, + 0x2f, 0xea, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, + 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, + 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, + 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x3c, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, + 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x02, + 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x14, + 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 0xa5, + 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, + 0x19, 0x19, 0x30, 0x11, 0xe6, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, + 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x30, 0x32, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, + 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, + 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x50, 0xbe, 0xb0, 0x50, 0x78, 0x1f, 0x6c, 0xaa, + 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x50, 0x78, 0x0d, + 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x20, 0x7e, 0x68, 0x2c, + 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0x0f, 0x7e, 0xa0, + 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 0x01, + 0x00, 0xa5, 0xd9, 0xa2, 0x7e, 0x68, 0x30, 0x7a, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, + 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x01, 0x19, + 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0xa0, 0xbe, 0xb0, 0xa0, + 0x78, 0x1f, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, + 0xb0, 0xa0, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, + 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, + 0x11, 0x0f, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, + 0xf1, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x7e, 0x68, 0x30, 0x9e, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x20, 0xb1, 0x26, 0x7e, + 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x30, 0xb1, 0x19, 0x6c, 0xaa, 0x19, 0xa2, + 0x00, 0x10, 0x12, 0x18, 0xff, 0x20, 0xb1, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, + 0x12, 0x19, 0xc4, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, + 0x12, 0x19, 0x19, 0x30, 0x11, 0x0f, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, + 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xae, 0x02, 0x17, 0x3b, 0x7e, + 0x68, 0x2f, 0xc6, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, + 0x21, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, + 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, + 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x06, 0x78, 0x3c, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, + 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, + 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x06, 0x78, + 0x14, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, + 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, + 0x12, 0x19, 0x19, 0x30, 0x11, 0xe6, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, + 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x30, 0x0e, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, + 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, + 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, + 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x09, 0x78, 0x3c, 0x7e, + 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, + 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, + 0x00, 0x18, 0x5e, 0xb0, 0x09, 0x78, 0x14, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, + 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0xe6, 0x7e, 0xa0, 0x01, 0x19, + 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x30, 0x56, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x7e, + 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x90, + 0xbe, 0xb0, 0x90, 0x78, 0x1f, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, + 0x00, 0x18, 0x5e, 0xb0, 0x90, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, + 0x19, 0xc4, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, + 0x19, 0x19, 0x30, 0x11, 0x0f, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, + 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xa2, 0x20, 0x1f, 0x68, 0x12, 0x12, + 0x31, 0x12, 0x17, 0xa9, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x20, 0x89, 0x26, + 0x7e, 0xa0, 0xff, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x18, 0xff, 0x7e, 0xb0, 0x55, 0x19, 0xb2, 0x00, + 0x00, 0x12, 0x18, 0xff, 0x30, 0x89, 0x0f, 0x7e, 0xa0, 0x00, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x18, + 0xff, 0x20, 0x89, 0x02, 0x80, 0x26, 0x12, 0x19, 0x19, 0x30, 0x11, 0x20, 0x7e, 0xa0, 0xff, 0x19, + 0xa2, 0x00, 0x04, 0x12, 0x18, 0xff, 0x7e, 0xb0, 0x55, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x18, 0xff, + 0x7e, 0xa0, 0x00, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x18, 0xff, 0x80, 0xe0, 0x2e, 0x24, 0x01, 0x00, + 0xa5, 0xd9, 0xa8, 0x02, 0x17, 0xc2, 0x02, 0x18, 0x4c, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, + 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, + 0xef, 0x22, 0x30, 0x1f, 0x03, 0x02, 0x18, 0x4c, 0xc2, 0x8a, 0x12, 0x17, 0xa9, 0x0b, 0x00, 0x12, + 0x18, 0x16, 0x20, 0x8b, 0x24, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x02, 0x7a, 0xb3, 0x91, + 0x07, 0x74, 0x0c, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x07, 0x12, 0x19, 0x0c, + 0x30, 0x8b, 0x06, 0x12, 0x18, 0x16, 0x30, 0x8b, 0xad, 0x12, 0x19, 0x19, 0x30, 0x11, 0xa7, 0x12, + 0x18, 0x16, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x07, 0x12, 0x19, + 0x0c, 0x12, 0x18, 0x16, 0x80, 0xe9, 0x7e, 0xa0, 0x00, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x06, 0x7a, + 0xa3, 0x91, 0x07, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7a, 0xa3, 0x91, 0x07, 0x12, 0x18, 0xff, + 0x74, 0xef, 0x7a, 0xb3, 0x91, 0x04, 0x74, 0x80, 0x7a, 0xb3, 0x91, 0x03, 0x74, 0x0c, 0x7a, 0xb3, + 0x91, 0x06, 0x74, 0x08, 0x7a, 0xb3, 0x91, 0x07, 0x12, 0x19, 0x0c, 0x22, 0x30, 0x12, 0x19, 0x7e, + 0x68, 0x30, 0xc2, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0xd2, 0x11, 0x12, 0x18, 0xff, 0x12, + 0x18, 0xff, 0x12, 0x18, 0xff, 0x02, 0x0c, 0xca, 0x30, 0x1f, 0x1c, 0x7e, 0x68, 0x31, 0x3c, 0x7a, + 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x31, 0x5e, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, + 0xc4, 0x12, 0x1a, 0x6e, 0x02, 0x18, 0xf7, 0x0b, 0x00, 0x7e, 0x78, 0x18, 0xb1, 0x7a, 0x7c, 0x00, + 0xff, 0x7f, 0x67, 0x7a, 0x6c, 0x00, 0x00, 0x7e, 0x70, 0x3e, 0x7e, 0x7b, 0xb0, 0x7a, 0x6b, 0xb0, + 0x0b, 0x7c, 0x0b, 0x6c, 0xa5, 0xdf, 0xf3, 0x7e, 0x78, 0x18, 0xb1, 0x7a, 0x7c, 0x00, 0x00, 0x89, + 0x78, 0x7e, 0x78, 0x00, 0x00, 0x7a, 0x7c, 0x00, 0xfe, 0x7e, 0x68, 0x7f, 0xbf, 0x7a, 0x6c, 0x00, + 0xfe, 0x74, 0xaa, 0x39, 0xb7, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb7, 0x2a, 0xaa, 0x74, 0xa0, 0x39, + 0xb7, 0x55, 0x55, 0x6c, 0x99, 0x7a, 0x6b, 0x90, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x6b, 0x80, 0xbc, + 0x89, 0x68, 0x08, 0x1b, 0x54, 0x78, 0xf5, 0x8a, 0xff, 0x18, 0xef, 0x8a, 0xff, 0x18, 0xf7, 0x12, + 0x19, 0x19, 0x7e, 0x6b, 0x80, 0x80, 0xfb, 0x7e, 0x10, 0xff, 0x12, 0x19, 0xac, 0x80, 0xf8, 0xca, + 0xf9, 0x7e, 0xf4, 0x00, 0xff, 0x1b, 0xf4, 0x78, 0xfc, 0xda, 0xf9, 0x22, 0xca, 0xf9, 0x7e, 0xf4, + 0x00, 0x00, 0x1b, 0xf4, 0x78, 0xfc, 0xda, 0xf9, 0x22, 0x20, 0x11, 0x20, 0xd2, 0x12, 0x12, 0x19, + 0x0c, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x12, 0x19, + 0x0c, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x90, 0x00, 0x22, 0xca, 0x0b, 0x7e, 0x10, + 0x03, 0x7c, 0x30, 0x6c, 0x22, 0x0b, 0x20, 0x9e, 0x30, 0x0a, 0x50, 0xf9, 0x2e, 0x30, 0x0b, 0x1b, + 0x20, 0x68, 0x20, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x03, 0x7a, 0xb3, 0x90, 0x00, + 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x90, 0x00, + 0xa5, 0xda, 0xe0, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x1b, 0x30, 0x68, 0x20, 0x12, 0x19, 0x0c, + 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, + 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x90, 0x00, 0xa5, 0xdb, 0xe0, 0x7e, 0x20, 0x0a, + 0x12, 0x19, 0x0c, 0xa5, 0xda, 0xfa, 0xa5, 0xd9, 0x98, 0xda, 0x0b, 0x22, 0x20, 0x11, 0x14, 0x12, + 0x19, 0x0c, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x00, 0x7a, + 0xb3, 0x90, 0x00, 0x22, 0x30, 0x1f, 0x32, 0x20, 0x11, 0x2f, 0xca, 0x2b, 0xca, 0x7b, 0x7e, 0x78, + 0x80, 0x00, 0x7a, 0x7c, 0x00, 0xfe, 0x12, 0x1a, 0x4d, 0x7e, 0x6b, 0xa0, 0x5c, 0xaa, 0x68, 0x10, + 0x29, 0xb7, 0x00, 0x14, 0x54, 0x60, 0x68, 0xf8, 0x39, 0xa7, 0x00, 0x00, 0x0b, 0x6c, 0x80, 0xe9, + 0x12, 0x18, 0xff, 0xd2, 0xb5, 0xda, 0x7b, 0xda, 0x2b, 0x22, 0x12, 0x1a, 0x05, 0x7e, 0x68, 0x00, + 0x0c, 0x12, 0x19, 0xc4, 0x22, 0xca, 0x59, 0xca, 0x5b, 0x7e, 0xb4, 0x00, 0x0c, 0x7c, 0xb8, 0xc4, + 0x12, 0x1a, 0x35, 0x7c, 0xb8, 0x12, 0x1a, 0x35, 0x7c, 0xb9, 0xc4, 0x12, 0x1a, 0x35, 0x7c, 0xb9, + 0x12, 0x1a, 0x35, 0x7e, 0xb0, 0x68, 0x7a, 0xb9, 0xb0, 0x0b, 0xb4, 0x6c, 0xbb, 0x7a, 0xb9, 0xb0, + 0xda, 0x59, 0xda, 0x5b, 0x22, 0x5e, 0xb0, 0x0f, 0x7c, 0xab, 0x9e, 0xa0, 0x0a, 0x40, 0x05, 0x2e, + 0xb0, 0x37, 0x80, 0x03, 0x2e, 0xb0, 0x30, 0x7a, 0xb9, 0xb0, 0x0b, 0xb4, 0x22, 0xc2, 0xb5, 0x75, + 0xb0, 0xef, 0x12, 0x18, 0xff, 0x74, 0x80, 0x39, 0xb7, 0x00, 0x0c, 0x7e, 0x54, 0x00, 0x06, 0x39, + 0xa7, 0x00, 0x04, 0x39, 0xb7, 0x00, 0x00, 0x74, 0x03, 0x39, 0xb7, 0x00, 0x0c, 0x22, 0x7e, 0x78, + 0x00, 0x00, 0x7a, 0x7c, 0x00, 0xff, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0x01, 0x7f, 0x65, + 0x7e, 0x74, 0x20, 0x00, 0x12, 0x0b, 0x63, 0x40, 0x58, 0x7e, 0x78, 0x7c, 0x00, 0x7a, 0x7c, 0x00, + 0xff, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0x01, 0x7e, 0x68, 0x7c, 0x00, 0x7a, 0x6c, 0x00, + 0x01, 0x7e, 0x74, 0x04, 0x00, 0x12, 0x0b, 0x63, 0x40, 0x37, 0x74, 0x80, 0x12, 0x1a, 0xea, 0x40, + 0x30, 0x7e, 0x00, 0x03, 0x7a, 0x03, 0x90, 0x00, 0xd2, 0x10, 0x7e, 0x04, 0x00, 0x08, 0x7e, 0x14, + 0x00, 0x00, 0x84, 0xa5, 0xdb, 0xfc, 0xa5, 0xda, 0xf9, 0xa5, 0xd9, 0xf6, 0x74, 0x40, 0x12, 0x1a, + 0xea, 0x40, 0x0e, 0x7e, 0x68, 0x31, 0x8d, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x02, 0x18, + 0xf7, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x80, 0xfe, 0xf5, 0x0b, 0x7e, 0x78, 0x00, 0x0b, + 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x68, 0x7f, 0xbf, 0x7a, 0x6c, 0x00, 0x01, 0x7e, 0x74, 0x00, 0x01, + 0x02, 0x0b, 0x63, + +// Segment #19, EXCLUDED Start Address 00ff2c66, Length 1393 + +}; + +static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = { + 2, 0, 3 }; // Major, Minor, Build + +#undef IMAGE_VERSION_NAME + +#undef IMAGE_ARRAY_NAME + diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_fw_down.h linux/drivers/usb/serial/io_fw_down.h --- v2.4.2/linux/drivers/usb/serial/io_fw_down.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_fw_down.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,1123 @@ +//************************************************************** +//* Edgeport/4 Binary Image +//* Generated by HEX2C v1.06 +//* Copyright(c) 1998 Inside Out Networks, All rights reserved. +//* 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. +//************************************************************** + + +//Image structure definition +#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD) + #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD + typedef struct _EDGE_FIRMWARE_IMAGE_RECORD + { + unsigned short ExtAddr; + unsigned short Addr; + unsigned short Len; + unsigned char Data[0]; + } EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD; + + typedef struct _EDGE_FIRMWARE_VERSION_INFO + { + unsigned char MajorVersion; + unsigned char MinorVersion; + unsigned short BuildNumber; + } EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO; + +#endif + +#if !defined(IMAGE_ARRAY_NAME) + #define IMAGE_ARRAY_NAME FirmwareImage + #define IMAGE_VERSION_NAME FirmwareImageVersion +#endif + +static unsigned char IMAGE_ARRAY_NAME[] = { + +// Segment #1, Start Address 00ff0000, Length 6 +0xff,0x00,0x00,0x00,0x06,0x00, + 0x02, 0x00, 0x80, 0x02, 0x49, 0x39, + +// Segment #2, Start Address 00ff000b, Length 3 +0xff,0x00,0x0b,0x00,0x03,0x00, + 0x02, 0x44, 0x1a, + +// Segment #3, Start Address 00ff0013, Length 3 +0xff,0x00,0x13,0x00,0x03,0x00, + 0x02, 0x00, 0x13, + +// Segment #4, Start Address 00ff001b, Length 3 +0xff,0x00,0x1b,0x00,0x03,0x00, + 0x02, 0x00, 0x1b, + +// Segment #5, Start Address 00ff0023, Length 3 +0xff,0x00,0x23,0x00,0x03,0x00, + 0x02, 0x00, 0x23, + +// Segment #6, Start Address 00ff002b, Length 3 +0xff,0x00,0x2b,0x00,0x03,0x00, + 0x02, 0x00, 0x2b, + +// Segment #7, Start Address 00ff0033, Length 3 +0xff,0x00,0x33,0x00,0x03,0x00, + 0x02, 0x00, 0x33, + +// Segment #8, Start Address 00ff003b, Length 3 +0xff,0x00,0x3b,0x00,0x03,0x00, + 0x02, 0x00, 0x3b, + +// Segment #9, Start Address 00ff0043, Length 3 +0xff,0x00,0x43,0x00,0x03,0x00, + 0x02, 0x00, 0x43, + +// Segment #10, Start Address 00ff004b, Length 3 +0xff,0x00,0x4b,0x00,0x03,0x00, + 0x02, 0x70, 0xd4, + +// Segment #11, Start Address 00ff0053, Length 3 +0xff,0x00,0x53,0x00,0x03,0x00, + 0x02, 0x77, 0x9d, + +// Segment #12, Start Address 00ff007b, Length 3 +0xff,0x00,0x7b,0x00,0x03,0x00, + 0x02, 0x00, 0x7b, + +// Segment #13, Start Address 00ff0080, Length 7 +0xff,0x00,0x80,0x00,0x07,0x00, + 0x7e, 0x14, 0x00, 0x00, 0x02, 0x40, 0x51, + +// Segment #14, Start Address 00ff4000, Length 15920 +0xff,0x00,0x00,0x40,0x30,0x3e, + 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x14, 0x7f, 0xf8, 0x7e, 0x24, 0x00, 0xfe, 0x7d, 0x31, 0x0b, 0x1a, + 0x50, 0x1b, 0x0a, 0x50, 0x7e, 0x14, 0x40, 0x1b, 0x02, 0x40, 0x6a, 0x7e, 0xf8, 0x00, 0x59, 0xd2, + 0x04, 0xc2, 0x94, 0xd2, 0x95, 0x7e, 0xf4, 0x40, 0x2c, 0x02, 0x40, 0x7c, 0x12, 0x7f, 0x3f, 0xf5, + 0x2e, 0x7a, 0xa1, 0x2d, 0x7a, 0x11, 0x58, 0x12, 0x77, 0xda, 0x12, 0x40, 0xdc, 0x7e, 0xb3, 0x3f, + 0xf1, 0x60, 0x03, 0x12, 0x43, 0x68, 0x75, 0xf1, 0x00, 0x12, 0x78, 0x7f, 0xd2, 0xaf, 0x02, 0x44, + 0x06, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x5f, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xa9, + 0x25, 0x87, 0x03, 0xa9, 0xd5, 0x87, 0xd2, 0x93, 0x89, 0x08, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, + 0x40, 0x78, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xc2, 0x93, 0x89, 0x08, 0x7e, 0x08, 0x00, 0x20, + 0x7e, 0x44, 0x04, 0x00, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0x8e, 0x02, 0x7e, 0x4b, 0x7e, 0x08, + 0x01, 0x59, 0x7e, 0x44, 0x28, 0x7c, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0xa0, 0x02, 0x7e, 0x4b, + 0x7e, 0x08, 0x00, 0x59, 0x7e, 0x44, 0x01, 0x00, 0x7e, 0x40, 0x53, 0x7e, 0xe4, 0x40, 0xb2, 0x02, + 0x7e, 0x4b, 0x75, 0x57, 0x20, 0x75, 0x56, 0x30, 0x7e, 0x04, 0x00, 0x08, 0x75, 0x54, 0x58, 0x75, + 0x55, 0x08, 0x75, 0x51, 0x08, 0x75, 0x53, 0x01, 0x75, 0x89, 0x01, 0x75, 0x8a, 0x01, 0x75, 0x8c, + 0x00, 0xd2, 0x8c, 0x7e, 0x04, 0x00, 0x02, 0x7a, 0x05, 0x42, 0x89, 0xf4, 0x75, 0xb7, 0x7f, 0x75, + 0xb8, 0x7f, 0x75, 0xb3, 0x07, 0x75, 0xb2, 0x07, 0xd2, 0xa9, 0x22, 0xd2, 0x92, 0xe4, 0xd5, 0xe0, + 0xfd, 0xc2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x2e, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, + 0x10, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf2, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x72, 0x0b, 0x20, + 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x74, 0xbf, 0x19, 0xb0, + 0x00, 0x0c, 0x74, 0x10, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x80, 0x19, 0xb0, 0x00, 0x0c, 0x7e, 0x54, + 0x00, 0x02, 0x19, 0xa0, 0x00, 0x04, 0x19, 0xb0, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb0, 0x00, 0x0c, + 0x74, 0x07, 0x20, 0x68, 0x02, 0x74, 0x0f, 0x19, 0xb0, 0x00, 0x04, 0x30, 0x6b, 0x17, 0x74, 0xbf, + 0x19, 0xb0, 0x00, 0x0c, 0x74, 0x28, 0x20, 0x68, 0x02, 0x74, 0x20, 0x19, 0xb0, 0x00, 0x04, 0x74, + 0x03, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x0c, 0x19, 0xb0, 0x00, + 0x10, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe4, 0x19, 0xb0, 0x00, 0x04, 0x09, 0xb0, 0x00, + 0x10, 0x54, 0x08, 0x19, 0xb0, 0x00, 0x10, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x22, 0x7c, 0xb2, + 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x41, 0x99, 0x89, 0x24, 0x41, 0xa9, 0x41, 0xc6, 0x41, 0xe3, 0x42, + 0x00, 0x42, 0x1d, 0x42, 0x3a, 0x42, 0x57, 0x42, 0x74, 0xc2, 0x10, 0xc2, 0x18, 0xc2, 0x08, 0x7e, + 0x04, 0x09, 0xcd, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x6d, 0x00, 0x7a, 0x07, 0x01, + 0x79, 0x7a, 0x07, 0x01, 0x89, 0x22, 0xc2, 0x11, 0xc2, 0x19, 0xc2, 0x09, 0x7e, 0x04, 0x0d, 0xcd, + 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7b, 0x7a, 0x07, + 0x01, 0x8b, 0x22, 0xc2, 0x12, 0xc2, 0x1a, 0xc2, 0x0a, 0x7e, 0x04, 0x11, 0xcd, 0x7a, 0x07, 0x01, + 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7d, 0x7a, 0x07, 0x01, 0x8d, 0x22, + 0xc2, 0x13, 0xc2, 0x1b, 0xc2, 0x0b, 0x7e, 0x04, 0x15, 0xcd, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, + 0x01, 0x6f, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7f, 0x7a, 0x07, 0x01, 0x8f, 0x22, 0xc2, 0x14, 0xc2, + 0x1c, 0xc2, 0x0c, 0x7e, 0x04, 0x19, 0xcd, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x6d, + 0x00, 0x7a, 0x07, 0x01, 0x81, 0x7a, 0x07, 0x01, 0x91, 0x22, 0xc2, 0x15, 0xc2, 0x1d, 0xc2, 0x0d, + 0x7e, 0x04, 0x1d, 0xcd, 0x7a, 0x07, 0x01, 0x63, 0x7a, 0x07, 0x01, 0x73, 0x6d, 0x00, 0x7a, 0x07, + 0x01, 0x83, 0x7a, 0x07, 0x01, 0x93, 0x22, 0xc2, 0x16, 0xc2, 0x1e, 0xc2, 0x0e, 0x7e, 0x04, 0x21, + 0xcd, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x85, 0x7a, + 0x07, 0x01, 0x95, 0x22, 0xc2, 0x17, 0xc2, 0x1f, 0xc2, 0x0f, 0x7e, 0x04, 0x25, 0xcd, 0x7a, 0x07, + 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x87, 0x7a, 0x07, 0x01, 0x97, + 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x42, 0x9c, 0x89, 0x24, 0x42, 0xac, 0x42, 0xc3, + 0x42, 0xda, 0x42, 0xf1, 0x43, 0x08, 0x43, 0x1f, 0x43, 0x36, 0x43, 0x4d, 0x30, 0x40, 0x07, 0x20, + 0x58, 0x04, 0xc2, 0x28, 0x80, 0x0c, 0x30, 0x48, 0x07, 0x20, 0x50, 0x04, 0xc2, 0x28, 0x80, 0x02, + 0xd2, 0x28, 0x22, 0x30, 0x41, 0x07, 0x20, 0x59, 0x04, 0xc2, 0x29, 0x80, 0x0c, 0x30, 0x49, 0x07, + 0x20, 0x51, 0x04, 0xc2, 0x29, 0x80, 0x02, 0xd2, 0x29, 0x22, 0x30, 0x42, 0x07, 0x20, 0x5a, 0x04, + 0xc2, 0x2a, 0x80, 0x0c, 0x30, 0x4a, 0x07, 0x20, 0x52, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, 0x2a, + 0x22, 0x30, 0x43, 0x07, 0x20, 0x5b, 0x04, 0xc2, 0x2b, 0x80, 0x0c, 0x30, 0x4b, 0x07, 0x20, 0x53, + 0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2b, 0x22, 0x30, 0x44, 0x07, 0x20, 0x5c, 0x04, 0xc2, 0x2c, + 0x80, 0x0c, 0x30, 0x4c, 0x07, 0x20, 0x54, 0x04, 0xc2, 0x2c, 0x80, 0x02, 0xd2, 0x2c, 0x22, 0x30, + 0x45, 0x07, 0x20, 0x5d, 0x04, 0xc2, 0x2d, 0x80, 0x0c, 0x30, 0x4d, 0x07, 0x20, 0x55, 0x04, 0xc2, + 0x2d, 0x80, 0x02, 0xd2, 0x2d, 0x22, 0x30, 0x46, 0x07, 0x20, 0x5e, 0x04, 0xc2, 0x2e, 0x80, 0x0c, + 0x30, 0x4e, 0x07, 0x20, 0x56, 0x04, 0xc2, 0x2e, 0x80, 0x02, 0xd2, 0x2e, 0x22, 0x30, 0x47, 0x07, + 0x20, 0x5f, 0x04, 0xc2, 0x2f, 0x80, 0x0c, 0x30, 0x4f, 0x07, 0x20, 0x57, 0x04, 0xc2, 0x2f, 0x80, + 0x02, 0xd2, 0x2f, 0x22, 0x43, 0xcc, 0x43, 0x79, 0xbe, 0xb0, 0x02, 0x40, 0x01, 0x22, 0x23, 0x0a, + 0x5b, 0x49, 0x55, 0x43, 0x64, 0x99, 0x54, 0xd3, 0x22, 0xa9, 0xc5, 0x87, 0x12, 0x43, 0xd7, 0x7e, + 0x04, 0x05, 0xcd, 0x7a, 0x07, 0x01, 0xc1, 0x7a, 0x07, 0x01, 0xc3, 0x7e, 0x04, 0x01, 0xcd, 0x7a, + 0x07, 0x01, 0xc7, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x04, 0x76, 0xbd, 0x7a, 0x05, 0x4b, 0x75, 0xf1, + 0x01, 0x75, 0xe1, 0x1f, 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x75, 0xf1, 0x02, 0x75, 0xe1, 0x03, + 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x43, 0xa2, 0x1c, 0x12, 0x40, 0xeb, 0x7e, 0x20, 0x00, 0x12, + 0x41, 0x8e, 0x0b, 0x20, 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0xd2, 0xa8, 0x22, 0xa9, 0xd5, 0x87, 0x12, + 0x43, 0xd7, 0xd2, 0x92, 0xc2, 0xa8, 0x22, 0x75, 0xa3, 0x00, 0x53, 0xa2, 0x03, 0x75, 0xc1, 0x00, + 0x53, 0xc0, 0x03, 0x7e, 0x00, 0x05, 0x7a, 0x01, 0xf1, 0x43, 0xf4, 0x80, 0x43, 0xe4, 0x80, 0xe5, + 0xf2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xf2, 0xe5, 0xe2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xe2, 0x75, + 0xe1, 0x10, 0xa5, 0xd8, 0xe1, 0x22, 0x12, 0x44, 0x76, 0x12, 0x44, 0x8c, 0x12, 0x45, 0x27, 0x12, + 0x45, 0x57, 0x12, 0x49, 0x0f, 0x12, 0x44, 0xd8, 0x80, 0xec, 0xca, 0x09, 0x12, 0x44, 0x58, 0x10, + 0x01, 0x12, 0xd5, 0x51, 0x1e, 0x63, 0x53, 0x01, 0x7e, 0x00, 0x54, 0x2e, 0x01, 0x53, 0xa5, 0xe6, + 0xf5, 0x51, 0x80, 0x12, 0x20, 0x02, 0x1e, 0x75, 0x53, 0x00, 0x85, 0x54, 0x51, 0xd2, 0x02, 0x74, + 0x00, 0x80, 0x0d, 0x30, 0x02, 0x0f, 0xc2, 0x02, 0x7e, 0x00, 0x56, 0x2e, 0x01, 0x53, 0xa5, 0xe6, + 0x53, 0x90, 0xcf, 0x42, 0x90, 0xda, 0x09, 0x32, 0xe5, 0x23, 0x60, 0x19, 0x7e, 0x14, 0x00, 0x00, + 0x09, 0xb1, 0x01, 0xb9, 0xb4, 0x00, 0x02, 0x80, 0x05, 0x14, 0x19, 0xb1, 0x01, 0xb9, 0xa5, 0x0a, + 0xbe, 0x21, 0x2e, 0x78, 0xeb, 0x22, 0xc2, 0xaf, 0x7e, 0xb3, 0x3f, 0xf1, 0xb4, 0x01, 0x0a, 0xc0, + 0xf1, 0x75, 0xf1, 0x02, 0x12, 0x72, 0xff, 0xd0, 0xf1, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x22, + 0x60, 0x43, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, 0x03, 0x80, 0x38, 0x39, 0x7e, 0x04, 0x80, 0x00, + 0x7e, 0x20, 0x00, 0x13, 0x50, 0x21, 0x09, 0xa0, 0x00, 0x04, 0x4e, 0xa0, 0x05, 0x19, 0xa0, 0x00, + 0x04, 0x0a, 0x32, 0x09, 0x53, 0x6a, 0x93, 0x5e, 0x51, 0x27, 0x68, 0x0b, 0x09, 0xa0, 0x00, 0x10, + 0x4e, 0xa0, 0x01, 0x19, 0xa0, 0x00, 0x10, 0x2e, 0x04, 0x01, 0x00, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, + 0x78, 0xd1, 0x75, 0x22, 0x00, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x26, 0x60, 0x36, 0x7e, 0x20, + 0x00, 0x7e, 0x30, 0x01, 0xe5, 0x26, 0xa5, 0x5b, 0x68, 0x21, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, + 0x32, 0x01, 0x79, 0xbe, 0x34, 0x00, 0x00, 0x68, 0x12, 0x7e, 0xb1, 0x21, 0xa5, 0x4b, 0x7a, 0xb1, + 0x21, 0xca, 0x19, 0x49, 0x22, 0x45, 0x17, 0x99, 0x24, 0xda, 0x19, 0x3e, 0x30, 0xa5, 0x0a, 0xbe, + 0x21, 0x2e, 0x78, 0xd0, 0xd2, 0xaf, 0x22, 0x4a, 0x98, 0x4d, 0xcd, 0x51, 0x02, 0x54, 0x37, 0x57, + 0x6c, 0x5a, 0xa1, 0x5d, 0xd6, 0x61, 0x0b, 0xc2, 0xaf, 0xe5, 0x24, 0x60, 0x14, 0x7e, 0x20, 0x00, + 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x45, 0x44, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, + 0xef, 0xd2, 0xaf, 0x22, 0xca, 0x28, 0x12, 0x6a, 0xac, 0xda, 0x28, 0x40, 0x09, 0x0a, 0x22, 0x09, + 0xb2, 0x6a, 0x93, 0xf4, 0x52, 0x24, 0x22, 0xc2, 0xaf, 0xe5, 0x23, 0x60, 0x14, 0x7e, 0x20, 0x00, + 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x45, 0x74, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, + 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x45, 0x7f, 0x89, 0x24, 0x45, + 0x8f, 0x45, 0xff, 0x46, 0x6f, 0x46, 0xdf, 0x47, 0x4f, 0x47, 0xbf, 0x48, 0x2f, 0x48, 0x9f, 0x7e, + 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4d, + 0x96, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, + 0x89, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x89, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xb9, 0x80, 0x2e, + 0x7e, 0x63, 0x01, 0xb9, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, + 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x18, 0x6c, 0x00, + 0x7a, 0x03, 0x01, 0xb9, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, + 0x27, 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x50, + 0xcb, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, + 0x8b, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8b, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xba, 0x80, 0x2e, + 0x7e, 0x63, 0x01, 0xba, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, + 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x19, 0x6c, 0x00, + 0x7a, 0x03, 0x01, 0xba, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, + 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x82, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x54, + 0x00, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, + 0x8d, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8d, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbb, 0x80, 0x2e, + 0x7e, 0x63, 0x01, 0xbb, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, + 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1a, 0x6c, 0x00, + 0x7a, 0x03, 0x01, 0xbb, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, + 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x83, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x57, + 0x35, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, + 0x8f, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8f, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbc, 0x80, 0x2e, + 0x7e, 0x63, 0x01, 0xbc, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, + 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1b, 0x6c, 0x00, + 0x7a, 0x03, 0x01, 0xbc, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, + 0x27, 0x01, 0x81, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5a, + 0x6a, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, + 0x91, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x91, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbd, 0x80, 0x2e, + 0x7e, 0x63, 0x01, 0xbd, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, + 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1c, 0x6c, 0x00, + 0x7a, 0x03, 0x01, 0xbd, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, + 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x85, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5d, + 0x9f, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, + 0x93, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x93, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbe, 0x80, 0x2e, + 0x7e, 0x63, 0x01, 0xbe, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, + 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1d, 0x6c, 0x00, + 0x7a, 0x03, 0x01, 0xbe, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, + 0x27, 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x60, + 0xd4, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, + 0x95, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x95, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbf, 0x80, 0x2e, + 0x7e, 0x63, 0x01, 0xbf, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, + 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1e, 0x6c, 0x00, + 0x7a, 0x03, 0x01, 0xbf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, + 0x27, 0x01, 0x87, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x87, 0x00, 0x09, 0xb2, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x64, + 0x09, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, + 0x97, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x97, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xc0, 0x80, 0x2e, + 0x7e, 0x63, 0x01, 0xc0, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, + 0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1f, 0x6c, 0x00, + 0x7a, 0x03, 0x01, 0xc0, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0xc2, + 0xaf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0xa9, 0x32, 0xf2, 0x1a, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, + 0x00, 0x00, 0x78, 0x10, 0xe5, 0xf5, 0x33, 0x82, 0xe7, 0x40, 0x09, 0x85, 0x31, 0x2f, 0x12, 0x7e, + 0x30, 0x75, 0xf6, 0x00, 0xd0, 0xf1, 0xd2, 0xaf, 0x22, 0xc0, 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xc0, + 0xf0, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xd2, 0x01, 0x75, 0x2f, 0x89, 0x12, 0x7e, 0x30, 0x7e, + 0x14, 0x80, 0x00, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x49, 0xd8, 0x20, 0x70, 0x5a, + 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x49, 0xf0, 0x20, 0x71, 0x4b, 0xa5, + 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x08, 0xa5, 0x0a, 0x09, 0xb1, 0x00, + 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x20, 0x20, 0x72, 0x30, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, + 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x38, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, + 0x4a, 0x50, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x68, 0xa5, 0x0a, + 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x80, 0x30, 0x04, 0x0c, 0xc2, 0x04, 0xc0, + 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0xd0, + 0xf0, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x75, 0x2f, 0x80, 0x12, 0x7e, 0x30, 0x54, 0x3e, + 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x66, 0x34, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, + 0x75, 0x2f, 0x81, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, + 0x66, 0x74, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x82, 0x12, 0x7e, 0x30, 0x54, 0x3e, + 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x66, 0xb4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, + 0x75, 0x2f, 0x83, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, + 0x66, 0xf4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x84, 0x12, 0x7e, 0x30, 0x54, 0x3e, + 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x67, 0x34, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, + 0x75, 0x2f, 0x85, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, + 0x67, 0x74, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x86, 0x12, 0x7e, 0x30, 0x54, 0x3e, + 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x67, 0xb4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, + 0x75, 0x2f, 0x87, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, + 0x67, 0xf4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x10, 0x08, 0x01, 0x22, 0x20, 0x28, 0x03, 0xd2, + 0x08, 0x22, 0x75, 0x2f, 0xa0, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x80, 0x00, 0x80, 0x06, 0x20, 0x28, + 0x03, 0xd2, 0x08, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, + 0x03, 0x12, 0x4d, 0x96, 0x30, 0x30, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x08, 0x22, 0x30, 0xe6, 0x02, + 0xd2, 0x60, 0x7e, 0x37, 0x01, 0x79, 0x7e, 0x27, 0x01, 0x99, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, + 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, 0x37, 0x01, 0x59, 0x7d, 0x43, + 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x59, 0x75, 0x2f, 0x94, 0x12, + 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x60, 0xc4, 0x22, 0xc2, + 0x60, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, + 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x99, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x99, 0x7e, 0x37, 0x01, + 0x79, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, + 0x37, 0x01, 0x59, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, + 0x59, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, + 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x0d, 0xcd, + 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x09, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, + 0x59, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4b, 0x0b, 0x22, 0xd2, 0x08, 0x7e, + 0x04, 0x09, 0xcd, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x75, 0x2f, 0x94, 0x12, 0x7e, + 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, + 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, + 0x7e, 0x27, 0x01, 0xa9, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, + 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, + 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, + 0x00, 0x00, 0x2e, 0x27, 0x01, 0xa9, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, + 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, + 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x38, 0x0a, 0x09, + 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0x80, 0x7f, 0x7a, 0x51, + 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x00, 0x00, 0x2e, 0x67, + 0x01, 0xa9, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, + 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, + 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, + 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x00, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, + 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, + 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, + 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, + 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, + 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, + 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, + 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, + 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, + 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4c, 0x6f, 0x75, + 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, + 0x38, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0xda, + 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4c, 0x6f, 0xda, 0xb8, 0x02, + 0x4d, 0x96, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, + 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, + 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, + 0x50, 0x80, 0x02, 0xc2, 0x50, 0x12, 0x42, 0xac, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, + 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, + 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, + 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, + 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4c, 0xc3, 0x75, + 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x09, 0x01, + 0x22, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x75, 0x2f, 0xa1, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x81, + 0x00, 0x80, 0x06, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, + 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x50, 0xcb, 0x30, 0x31, 0x06, 0x20, 0xe6, 0x4f, 0xd2, + 0x09, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x61, 0x7e, 0x37, 0x01, 0x7b, 0x7e, 0x27, 0x01, 0x9b, 0x9d, + 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 0x7a, 0x37, 0x01, 0x7b, 0x7e, + 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, + 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, + 0x10, 0x61, 0xc4, 0x22, 0xc2, 0x61, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, + 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9b, 0x28, 0x04, 0x7e, 0x27, + 0x01, 0x9b, 0x7e, 0x37, 0x01, 0x7b, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, + 0x7a, 0x37, 0x01, 0x7b, 0x7e, 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xcc, + 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, + 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, + 0x30, 0x9e, 0x44, 0x11, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x0d, 0xcd, 0x7d, 0x24, + 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5b, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4e, + 0x40, 0x22, 0xd2, 0x09, 0x7e, 0x04, 0x0d, 0xcd, 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, + 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, + 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, + 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xab, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, + 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, + 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, + 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x01, 0x00, 0x2e, 0x27, 0x01, 0xab, 0x1b, 0x38, 0x20, 0x0b, 0x35, + 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, + 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, + 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, + 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, + 0x64, 0x01, 0x00, 0x2e, 0x67, 0x01, 0xab, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, + 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, + 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, + 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x01, 0x7a, + 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, + 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, + 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, + 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, + 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, + 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, + 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, + 0xe7, 0x02, 0x4f, 0xa4, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, + 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, + 0x10, 0xd2, 0x11, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, + 0x4f, 0xa4, 0xda, 0xb8, 0x02, 0x50, 0xcb, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, + 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, + 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0xa5, 0xfd, 0x5e, + 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x12, 0x42, 0xc3, 0x02, 0x65, 0x9c, + 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, + 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, + 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, + 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, + 0x22, 0x02, 0x4f, 0xf8, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, + 0x30, 0x22, 0x10, 0x0a, 0x01, 0x22, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x75, 0x2f, 0xa2, 0x12, + 0x7e, 0x30, 0x7e, 0x14, 0x82, 0x00, 0x80, 0x06, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x09, 0xb1, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x54, 0x00, 0x30, 0x32, + 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0a, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x62, 0x7e, 0x37, 0x01, 0x7d, + 0x7e, 0x27, 0x01, 0x9d, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x36, 0x7a, 0x05, 0x36, + 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x15, 0xcc, + 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, + 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x62, 0xc4, 0x22, 0xc2, 0x62, 0x2d, 0x23, 0x68, 0x78, 0x6d, + 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, + 0x9d, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9d, 0x7e, 0x37, 0x01, 0x7d, 0x9d, 0x32, 0x7d, 0x02, 0x2e, + 0x05, 0x36, 0x7a, 0x05, 0x36, 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, + 0x42, 0xbe, 0x44, 0x15, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x7e, + 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, + 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x15, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, + 0x34, 0x11, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5d, 0x12, 0x68, 0x34, 0xbe, 0x25, + 0x20, 0x78, 0x03, 0x02, 0x51, 0x75, 0x22, 0xd2, 0x0a, 0x7e, 0x04, 0x11, 0xcd, 0x7a, 0x07, 0x01, + 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, + 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, + 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xad, 0x2e, 0x24, + 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, + 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x02, 0x00, 0x2e, 0x27, 0x01, 0xad, + 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, + 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, + 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, + 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, + 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x02, 0x00, 0x2e, 0x67, 0x01, 0xad, 0x9e, 0x24, 0x00, 0x02, + 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, + 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, + 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, + 0x23, 0x23, 0x44, 0x02, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, + 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, + 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, + 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, + 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, + 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, + 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, + 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, + 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, + 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x52, 0xd9, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, + 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, + 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, + 0x68, 0x07, 0xca, 0xb8, 0x12, 0x52, 0xd9, 0xda, 0xb8, 0x02, 0x54, 0x00, 0x09, 0xb1, 0x00, 0x18, + 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, + 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, + 0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x12, + 0x42, 0xda, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x53, 0x2d, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, + 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0b, 0x01, 0x22, 0x20, 0x2b, 0x03, 0xd2, 0x0b, + 0x22, 0x75, 0x2f, 0xa3, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x83, 0x00, 0x80, 0x06, 0x20, 0x2b, 0x03, + 0xd2, 0x0b, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, + 0x12, 0x57, 0x35, 0x30, 0x33, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0b, 0x22, 0x30, 0xe6, 0x02, 0xd2, + 0x63, 0x7e, 0x37, 0x01, 0x7f, 0x7e, 0x27, 0x01, 0x9f, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, + 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 0x01, 0x5f, 0x7d, 0x43, 0x2d, + 0x42, 0xbe, 0x44, 0x19, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5f, 0x75, 0x2f, 0x94, 0x12, 0x7e, + 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x63, 0xc4, 0x22, 0xc2, 0x63, + 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, + 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9f, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9f, 0x7e, 0x37, 0x01, 0x7f, + 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, + 0x01, 0x5f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x19, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5f, + 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, + 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x19, 0xcd, 0x9d, + 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x15, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5f, + 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x54, 0xaa, 0x22, 0xd2, 0x0b, 0x7e, 0x04, + 0x15, 0xcd, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, 0x01, 0x6f, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, + 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, + 0x27, 0x01, 0xaf, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, + 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x03, + 0x00, 0x2e, 0x27, 0x01, 0xaf, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, + 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, + 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, + 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x03, 0x00, 0x2e, 0x67, 0x01, + 0xaf, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, + 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, + 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, + 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x03, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, + 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, + 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, + 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, + 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, + 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, + 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, + 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, + 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, + 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x56, 0x0e, 0x75, 0x2f, + 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, + 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0xda, 0xb8, + 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x56, 0x0e, 0xda, 0xb8, 0x02, 0x57, + 0x35, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, + 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, + 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, + 0x80, 0x02, 0xc2, 0x53, 0x12, 0x42, 0xf1, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, + 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, + 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, + 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, + 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x56, 0x62, 0x75, 0x2f, + 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0c, 0x01, 0x22, + 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x75, 0x2f, 0xa4, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x84, 0x00, + 0x80, 0x06, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, + 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5a, 0x6a, 0x30, 0x34, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0c, + 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x64, 0x7e, 0x37, 0x01, 0x81, 0x7e, 0x27, 0x01, 0xa1, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, 0x37, 0x01, 0x81, 0x7e, 0x37, + 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x61, + 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, + 0x64, 0xc4, 0x22, 0xc2, 0x64, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x81, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa1, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0xa1, 0x7e, 0x37, 0x01, 0x81, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, + 0x37, 0x01, 0x81, 0x7e, 0x37, 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xcc, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x61, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, + 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, + 0x9e, 0x44, 0x1d, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x19, 0xcd, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x61, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x57, 0xdf, + 0x22, 0xd2, 0x0c, 0x7e, 0x04, 0x19, 0xcd, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x75, + 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, + 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, + 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb1, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, + 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, + 0x01, 0xc9, 0x7e, 0x24, 0x04, 0x00, 0x2e, 0x27, 0x01, 0xb1, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, + 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, + 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x14, 0x22, + 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, + 0x04, 0x00, 0x2e, 0x67, 0x01, 0xb1, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, + 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, + 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, + 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x04, 0x7a, 0x69, + 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, + 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, + 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, + 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, + 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, + 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, + 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, + 0x02, 0x59, 0x43, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, + 0xb1, 0x00, 0x04, 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, + 0xd2, 0x14, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x59, + 0x43, 0xda, 0xb8, 0x02, 0x5a, 0x6a, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, + 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, + 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 0x50, + 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x12, 0x43, 0x08, 0x02, 0x65, 0x9c, 0x75, + 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, + 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, + 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, + 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, + 0x02, 0x59, 0x97, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, + 0x22, 0x10, 0x0d, 0x01, 0x22, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x75, 0x2f, 0xa5, 0x12, 0x7e, + 0x30, 0x7e, 0x14, 0x85, 0x00, 0x80, 0x06, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x09, 0xb1, 0x00, + 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5d, 0x9f, 0x30, 0x35, 0x06, + 0x20, 0xe6, 0x4f, 0xd2, 0x0d, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x65, 0x7e, 0x37, 0x01, 0x83, 0x7e, + 0x27, 0x01, 0xa3, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3c, 0x7a, 0x05, 0x3c, 0x7a, + 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x21, 0xcc, 0x38, + 0x68, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, + 0x30, 0x12, 0x68, 0x34, 0x10, 0x65, 0xc4, 0x22, 0xc2, 0x65, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, + 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa3, + 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa3, 0x7e, 0x37, 0x01, 0x83, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, + 0x3c, 0x7a, 0x05, 0x3c, 0x7a, 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x21, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, + 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, + 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x21, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, + 0x1d, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x63, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, + 0x78, 0x03, 0x02, 0x5b, 0x14, 0x22, 0xd2, 0x0d, 0x7e, 0x04, 0x1d, 0xcd, 0x7a, 0x07, 0x01, 0x63, + 0x7a, 0x07, 0x01, 0x73, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, + 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, + 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb3, 0x2e, 0x24, 0x00, + 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, + 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, + 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x05, 0x00, 0x2e, 0x27, 0x01, 0xb3, 0x1b, + 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, + 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, + 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, + 0x00, 0x10, 0xd2, 0x15, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, + 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x05, 0x00, 0x2e, 0x67, 0x01, 0xb3, 0x9e, 0x24, 0x00, 0x02, 0x40, + 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, + 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, + 0x23, 0x44, 0x05, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, + 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, + 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, + 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, + 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, + 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, + 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, + 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, + 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5c, 0x78, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, + 0x07, 0xca, 0xb8, 0x12, 0x5c, 0x78, 0xda, 0xb8, 0x02, 0x5d, 0x9f, 0x09, 0xb1, 0x00, 0x18, 0x7e, + 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, + 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, + 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, 0x02, 0xc2, 0x55, 0x12, 0x43, + 0x1f, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, + 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, + 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, + 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, + 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5c, 0xcc, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, + 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0e, 0x01, 0x22, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, + 0x75, 0x2f, 0xa6, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x86, 0x00, 0x80, 0x06, 0x20, 0x2e, 0x03, 0xd2, + 0x0e, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, + 0x60, 0xd4, 0x30, 0x36, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0e, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x66, + 0x7e, 0x37, 0x01, 0x85, 0x7e, 0x27, 0x01, 0xa5, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, + 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, 0x65, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x25, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x65, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, + 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x66, 0xc4, 0x22, 0xc2, 0x66, 0x2d, + 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x68, + 0x6a, 0xbe, 0x27, 0x01, 0xa5, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa5, 0x7e, 0x37, 0x01, 0x85, 0x9d, + 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, + 0x65, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x25, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x65, 0x75, + 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, + 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x25, 0xcd, 0x9d, 0x24, + 0x12, 0x68, 0x34, 0x7e, 0x34, 0x21, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x65, 0x12, + 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5e, 0x49, 0x22, 0xd2, 0x0e, 0x7e, 0x04, 0x21, + 0xcd, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, + 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, + 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, + 0x01, 0xb5, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, + 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, + 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x06, 0x00, + 0x2e, 0x27, 0x01, 0xb5, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, + 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, + 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, + 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, + 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x06, 0x00, 0x2e, 0x67, 0x01, 0xb5, + 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, + 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, + 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, + 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x06, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, + 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, + 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, + 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, + 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, + 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, + 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, + 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, + 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, + 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5f, 0xad, 0x75, 0x2f, 0x99, + 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, + 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0xda, 0xb8, 0x30, + 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5f, 0xad, 0xda, 0xb8, 0x02, 0x60, 0xd4, + 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, + 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, + 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, + 0x02, 0xc2, 0x56, 0x12, 0x43, 0x36, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, + 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, + 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, + 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, + 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x60, 0x01, 0x75, 0x2f, 0x95, + 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0f, 0x01, 0x22, 0x20, + 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x75, 0x2f, 0xa7, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x87, 0x00, 0x80, + 0x06, 0x20, 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, + 0xda, 0xb8, 0x68, 0x03, 0x12, 0x64, 0x09, 0x30, 0x37, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0f, 0x22, + 0x30, 0xe6, 0x02, 0xd2, 0x67, 0x7e, 0x37, 0x01, 0x87, 0x7e, 0x27, 0x01, 0xa7, 0x9d, 0x32, 0x40, + 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 0x01, 0x87, 0x7e, 0x37, 0x01, + 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x67, 0x75, + 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x67, + 0xc4, 0x22, 0xc2, 0x67, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x87, + 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa7, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa7, + 0x7e, 0x37, 0x01, 0x87, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, + 0x01, 0x87, 0x7e, 0x37, 0x01, 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xcc, 0x38, 0x13, + 0x7a, 0x47, 0x01, 0x67, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, + 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, + 0x44, 0x29, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x25, 0xcd, 0x7d, 0x24, 0x2d, 0x43, + 0x7a, 0x47, 0x01, 0x67, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x61, 0x7e, 0x22, + 0xd2, 0x0f, 0x7e, 0x04, 0x25, 0xcd, 0x7a, 0x07, 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x75, 0x2f, + 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, + 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, + 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb7, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, + 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, + 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, + 0xc9, 0x7e, 0x24, 0x07, 0x00, 0x2e, 0x27, 0x01, 0xb7, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, + 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, + 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, + 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0x80, + 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x07, + 0x00, 0x2e, 0x67, 0x01, 0xb7, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, + 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, + 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, + 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x07, 0x7a, 0x69, 0xb0, + 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, + 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, + 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, + 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, + 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, + 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, + 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, + 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, + 0x62, 0xe2, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, + 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, + 0x17, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x62, 0xe2, + 0xda, 0xb8, 0x02, 0x64, 0x09, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, + 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, + 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, + 0x68, 0x04, 0xd2, 0x57, 0x80, 0x02, 0xc2, 0x57, 0x12, 0x43, 0x4d, 0x02, 0x65, 0x9c, 0x75, 0x2f, + 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, + 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, + 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, + 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, + 0x63, 0x36, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, + 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, + 0x20, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, + 0xd2, 0x50, 0x80, 0x02, 0xc2, 0x50, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, + 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, + 0xc2, 0x59, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x02, + 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, + 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, + 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, + 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5b, + 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, 0x80, 0x02, 0xc2, + 0x53, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, + 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, + 0x50, 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, + 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, + 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, + 0x02, 0xc2, 0x55, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, + 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, + 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, 0x02, 0xc2, 0x56, 0x02, 0x65, 0x88, 0x7c, + 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, + 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, + 0x57, 0x80, 0x02, 0xc2, 0x57, 0x02, 0x65, 0x88, 0x54, 0xf0, 0xc4, 0xa5, 0xff, 0xc4, 0xa5, 0x4f, + 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0x22, 0xca, 0x19, 0x5e, 0x20, + 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xcd, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, + 0xb0, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x02, 0x7e, 0x64, 0x00, 0x02, 0x02, 0x65, 0xe7, 0xca, + 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xcd, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, + 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0x7a, 0x79, 0x60, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x03, + 0x7e, 0x64, 0x00, 0x03, 0x02, 0x65, 0xe7, 0xd2, 0x04, 0x7e, 0x27, 0x01, 0xcb, 0x2d, 0x26, 0xbe, + 0x24, 0x04, 0x00, 0x38, 0x2e, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7e, 0x79, 0xa0, + 0x7a, 0x09, 0xa0, 0x0b, 0x04, 0x0b, 0x74, 0xbd, 0x04, 0x68, 0x23, 0xa5, 0xdb, 0xef, 0x7a, 0x27, + 0x01, 0xcb, 0x7e, 0x25, 0x30, 0x2d, 0x26, 0x7a, 0x25, 0x30, 0x7a, 0x07, 0x01, 0xc9, 0xda, 0x19, + 0xc2, 0xd7, 0x22, 0x75, 0x2f, 0x9a, 0x12, 0x7e, 0x30, 0xda, 0x19, 0xd2, 0xd7, 0x22, 0x7e, 0x04, + 0x01, 0xcd, 0x80, 0xd7, 0x4d, 0x42, 0x4a, 0xae, 0x4b, 0xa8, 0x4d, 0x7b, 0x49, 0x4f, 0x49, 0x4f, + 0x4c, 0xa7, 0x49, 0x4f, 0x4d, 0xbf, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x4d, 0xc6, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x50, 0x77, 0x4d, 0xe3, 0x4e, 0xdd, 0x50, 0xb0, 0x49, 0x4f, 0x49, 0x4f, + 0x4f, 0xdc, 0x49, 0x4f, 0x50, 0xf4, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x50, 0xfb, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x53, 0xac, 0x51, 0x18, 0x52, 0x12, 0x53, 0xe5, 0x49, 0x4f, 0x49, 0x4f, + 0x53, 0x11, 0x49, 0x4f, 0x54, 0x29, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x54, 0x30, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x56, 0xe1, 0x54, 0x4d, 0x55, 0x47, 0x57, 0x1a, 0x49, 0x4f, 0x49, 0x4f, + 0x56, 0x46, 0x49, 0x4f, 0x57, 0x5e, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x57, 0x65, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x5a, 0x16, 0x57, 0x82, 0x58, 0x7c, 0x5a, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x59, 0x7b, 0x49, 0x4f, 0x5a, 0x93, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x5a, 0x9a, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x5d, 0x4b, 0x5a, 0xb7, 0x5b, 0xb1, 0x5d, 0x84, 0x49, 0x4f, 0x49, 0x4f, + 0x5c, 0xb0, 0x49, 0x4f, 0x5d, 0xc8, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x5d, 0xcf, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x60, 0x80, 0x5d, 0xec, 0x5e, 0xe6, 0x60, 0xb9, 0x49, 0x4f, 0x49, 0x4f, + 0x5f, 0xe5, 0x49, 0x4f, 0x60, 0xfd, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x61, 0x04, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x63, 0xb5, 0x61, 0x21, 0x62, 0x1b, 0x63, 0xee, 0x49, 0x4f, 0x49, 0x4f, + 0x63, 0x1a, 0x49, 0x4f, 0x64, 0x32, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x64, 0x39, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, + 0x49, 0x4f, 0x49, 0x4f, 0xca, 0x29, 0x1e, 0x50, 0x40, 0x0d, 0x7e, 0x54, 0x0b, 0x10, 0x9c, 0xb5, + 0xa4, 0x2e, 0x54, 0x68, 0x51, 0x89, 0x54, 0x7e, 0x39, 0x00, 0x7a, 0x19, 0x00, 0x0b, 0x34, 0x80, + 0xe9, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, + 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, + 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, + 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, + 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, + 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, + 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, + 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, + 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, + 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, + 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, + 0x35, 0xda, 0x29, 0x22, 0x1e, 0x50, 0x40, 0x0d, 0x7e, 0x54, 0x0b, 0x1c, 0x9c, 0xb5, 0xa4, 0x2e, + 0x54, 0x69, 0x1f, 0x89, 0x54, 0x7e, 0x19, 0x00, 0x7a, 0x39, 0x00, 0x0b, 0x34, 0x80, 0xe9, 0x7e, + 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, + 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, + 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, + 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, + 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, + 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, + 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, + 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, + 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, + 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, + 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, + 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, + 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, + 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, + 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, + 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, + 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, + 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, + 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, + 0x00, 0x0b, 0x35, 0x22, 0x6a, 0x9b, 0x6c, 0x4f, 0x6c, 0x67, 0x6c, 0x82, 0x6d, 0x1d, 0x6d, 0xb5, + 0x6d, 0xd0, 0x6e, 0x62, 0x6d, 0xeb, 0x6e, 0x2c, 0x7c, 0xb3, 0xbe, 0xb0, 0x09, 0x28, 0x14, 0x75, + 0x2f, 0x09, 0x12, 0x7e, 0x30, 0x75, 0x57, 0x10, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x43, 0xe1, 0xc0, + 0xd0, 0xf1, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x23, 0x6c, 0xaa, 0x2e, 0x54, 0x6a, 0x54, 0x0b, 0x58, + 0x50, 0x89, 0x54, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x75, 0x2f, 0xb0, 0x12, 0x7e, + 0x30, 0x0a, 0x22, 0x09, 0xb2, 0x6a, 0x93, 0x42, 0x24, 0xd0, 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, + 0x3b, 0x49, 0x33, 0x6a, 0xb7, 0x89, 0x34, 0x6a, 0xc7, 0x6a, 0xf5, 0x6b, 0x23, 0x6b, 0x51, 0x6b, + 0x7f, 0x6b, 0xad, 0x6b, 0xdb, 0x6c, 0x09, 0x12, 0x41, 0xa9, 0xd2, 0x28, 0xd2, 0x08, 0xc2, 0x40, + 0xc2, 0x48, 0xc2, 0x38, 0xc2, 0x30, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xb9, 0x7e, 0x04, 0x00, 0x20, + 0x7a, 0x07, 0x01, 0x99, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xa9, 0x12, 0x41, 0x16, 0x12, + 0x64, 0x40, 0x02, 0x6c, 0x37, 0x12, 0x41, 0xc6, 0xd2, 0x29, 0xd2, 0x09, 0xc2, 0x41, 0xc2, 0x49, + 0xc2, 0x39, 0xc2, 0x31, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xba, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, + 0x01, 0x9b, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xab, 0x12, 0x41, 0x16, 0x12, 0x64, 0x69, + 0x02, 0x6c, 0x37, 0x12, 0x41, 0xe3, 0xd2, 0x2a, 0xd2, 0x0a, 0xc2, 0x42, 0xc2, 0x4a, 0xc2, 0x3a, + 0xc2, 0x32, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbb, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9d, + 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xad, 0x12, 0x41, 0x16, 0x12, 0x64, 0x92, 0x02, 0x6c, + 0x37, 0x12, 0x42, 0x00, 0xd2, 0x2b, 0xd2, 0x0b, 0xc2, 0x43, 0xc2, 0x4b, 0xc2, 0x3b, 0xc2, 0x33, + 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbc, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9f, 0x7e, 0x04, + 0x00, 0x38, 0x7a, 0x07, 0x01, 0xaf, 0x12, 0x41, 0x16, 0x12, 0x64, 0xbb, 0x02, 0x6c, 0x37, 0x12, + 0x42, 0x1d, 0xd2, 0x2c, 0xd2, 0x0c, 0xc2, 0x44, 0xc2, 0x4c, 0xc2, 0x3c, 0xc2, 0x34, 0x6d, 0x00, + 0x7a, 0x03, 0x01, 0xbd, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa1, 0x7e, 0x04, 0x00, 0x38, + 0x7a, 0x07, 0x01, 0xb1, 0x12, 0x41, 0x16, 0x12, 0x64, 0xe4, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x3a, + 0xd2, 0x2d, 0xd2, 0x0d, 0xc2, 0x45, 0xc2, 0x4d, 0xc2, 0x3d, 0xc2, 0x35, 0x6d, 0x00, 0x7a, 0x03, + 0x01, 0xbe, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa3, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, + 0x01, 0xb3, 0x12, 0x41, 0x16, 0x12, 0x65, 0x0d, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x57, 0xd2, 0x2e, + 0xd2, 0x0e, 0xc2, 0x46, 0xc2, 0x4e, 0xc2, 0x3e, 0xc2, 0x36, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbf, + 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa5, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb5, + 0x12, 0x41, 0x16, 0x12, 0x65, 0x36, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x74, 0xd2, 0x2f, 0xd2, 0x0f, + 0xc2, 0x47, 0xc2, 0x4f, 0xc2, 0x3f, 0xc2, 0x37, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xc0, 0x7e, 0x04, + 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa7, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb7, 0x12, 0x41, + 0x16, 0x12, 0x65, 0x5f, 0x02, 0x6c, 0x37, 0x7e, 0xa0, 0xd0, 0x7e, 0x60, 0x0f, 0x12, 0x65, 0xbf, + 0x40, 0x0c, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xc2, 0xd7, 0x22, 0x75, + 0x2f, 0xb1, 0x12, 0x7e, 0x30, 0x0a, 0x52, 0x23, 0x6d, 0x00, 0x59, 0x05, 0x00, 0x32, 0x12, 0x41, + 0x72, 0x12, 0x41, 0x8e, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb2, 0x12, 0x7e, 0x30, 0x0a, 0x22, 0x09, + 0xb2, 0x6a, 0x93, 0x42, 0x23, 0x7e, 0xb0, 0x9c, 0x19, 0xb2, 0x01, 0xb9, 0x12, 0x45, 0x74, 0xd0, + 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, + 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, + 0x12, 0x44, 0x40, 0xca, 0xb8, 0x09, 0xb0, 0x00, 0x10, 0x44, 0x02, 0x19, 0xb0, 0x00, 0x10, 0xda, + 0xb8, 0x80, 0x02, 0x54, 0xbf, 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x08, 0x80, 0x02, + 0x54, 0xf7, 0x09, 0x30, 0x00, 0x0c, 0xca, 0xb8, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xda, 0xb8, + 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x6a, 0x93, 0x3e, 0x20, + 0x0a, 0x62, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x20, 0x42, 0x27, 0xca, 0xb8, 0x74, 0x61, 0x19, + 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x10, 0x59, 0x46, 0x01, 0xa9, 0x09, 0xb0, 0x00, 0x10, 0x44, + 0x01, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x11, 0xf4, 0x52, 0x27, 0x74, 0xa1, 0x19, 0xb0, + 0x00, 0x08, 0x7e, 0x44, 0x00, 0x38, 0x59, 0x46, 0x01, 0xa9, 0xd0, 0xa8, 0x22, 0x7c, 0x74, 0x7e, + 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, + 0xb0, 0x00, 0x08, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x04, 0x44, 0x80, 0x80, 0x02, 0x54, 0x7f, + 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x02, 0x80, 0x02, 0x54, 0xfd, 0x19, 0xb0, 0x00, + 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x6a, 0x93, 0xa5, 0xfd, 0xf4, 0xa5, 0xfe, + 0xca, 0x28, 0x3e, 0x20, 0x0a, 0x62, 0xda, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x10, 0xa5, + 0xed, 0x42, 0x28, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x04, 0xa5, + 0xee, 0x52, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x04, 0x68, 0x10, 0xa5, 0xed, 0x42, 0x29, 0x42, 0x26, + 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x15, 0xa5, 0xee, 0x52, 0x29, 0x7c, 0x74, + 0x5e, 0x70, 0x02, 0x78, 0x0a, 0x52, 0x26, 0x7e, 0x44, 0x00, 0x20, 0x59, 0x46, 0x01, 0x99, 0x12, + 0x42, 0x91, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, + 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 0x00, 0x10, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, + 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, + 0x19, 0x40, 0x00, 0x18, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb5, 0x12, 0x7e, + 0x30, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0xb0, 0x00, 0x0c, 0x44, 0x40, 0x19, 0xb0, 0x00, + 0x0c, 0xe5, 0x58, 0xb4, 0x07, 0x23, 0x09, 0xb0, 0x00, 0x10, 0x4e, 0xb0, 0x02, 0x19, 0xb0, 0x00, + 0x10, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x54, + 0xf7, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb6, 0x12, + 0x7e, 0x30, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe5, 0x58, 0xb4, 0x07, 0x18, 0x09, 0x30, 0x00, + 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x44, 0x08, 0x19, 0xb0, 0x00, + 0x04, 0x19, 0x30, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x0c, 0x54, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xd0, + 0xa8, 0x22, 0x75, 0x2f, 0xb4, 0x12, 0x7e, 0x30, 0x7a, 0x21, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x41, + 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0xb0, 0x01, 0x7e, 0xa0, 0xc8, 0x7c, 0x64, 0x12, 0x65, 0xbf, 0xc0, + 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xd0, 0xa8, 0x22, 0x6e, 0x9c, 0x6e, 0xe3, + 0x6f, 0x2a, 0x6f, 0x71, 0x6f, 0xb8, 0x6f, 0xff, 0x70, 0x46, 0x70, 0x8d, 0x75, 0x2f, 0x55, 0x12, + 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, + 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x69, 0x7e, 0x27, 0x01, 0x79, 0x2d, 0x23, 0x7e, 0x09, + 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x0d, 0xcc, 0x38, 0x0f, 0x1b, 0x34, + 0x78, 0xec, 0x7a, 0x17, 0x01, 0x69, 0x7a, 0x27, 0x01, 0x79, 0x02, 0x4a, 0x98, 0x7e, 0x14, 0x09, + 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x01, 0x12, 0x7e, 0x30, 0x7a, + 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6b, 0x7e, + 0x27, 0x01, 0x7b, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, + 0x14, 0x11, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6b, 0x7a, 0x27, 0x01, + 0x7b, 0x02, 0x4d, 0xcd, 0x7e, 0x14, 0x0d, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, + 0x75, 0x2f, 0x02, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, + 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6d, 0x7e, 0x27, 0x01, 0x7d, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, + 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x15, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, + 0x7a, 0x17, 0x01, 0x6d, 0x7a, 0x27, 0x01, 0x7d, 0x02, 0x51, 0x02, 0x7e, 0x14, 0x11, 0xcd, 0x80, + 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x03, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, + 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6f, 0x7e, 0x27, 0x01, + 0x7f, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x19, + 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6f, 0x7a, 0x27, 0x01, 0x7f, 0x02, + 0x54, 0x37, 0x7e, 0x14, 0x15, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, + 0x04, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, + 0x7e, 0x17, 0x01, 0x71, 0x7e, 0x27, 0x01, 0x81, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, + 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x1d, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, + 0x01, 0x71, 0x7a, 0x27, 0x01, 0x81, 0x02, 0x57, 0x6c, 0x7e, 0x14, 0x19, 0xcd, 0x80, 0xeb, 0x75, + 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x05, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, + 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x73, 0x7e, 0x27, 0x01, 0x83, 0x2d, + 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x21, 0xcc, 0x38, + 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x73, 0x7a, 0x27, 0x01, 0x83, 0x02, 0x5a, 0xa1, + 0x7e, 0x14, 0x1d, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x06, 0x12, + 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, + 0x01, 0x75, 0x7e, 0x27, 0x01, 0x85, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, + 0x0b, 0x14, 0xbe, 0x14, 0x25, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x75, + 0x7a, 0x27, 0x01, 0x85, 0x02, 0x5d, 0xd6, 0x7e, 0x14, 0x21, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, + 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, + 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x77, 0x7e, 0x27, 0x01, 0x87, 0x2d, 0x23, 0x7e, + 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x29, 0xcc, 0x38, 0x0f, 0x1b, + 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x77, 0x7a, 0x27, 0x01, 0x87, 0x02, 0x61, 0x0b, 0x7e, 0x14, + 0x25, 0xcd, 0x80, 0xeb, 0xca, 0xb8, 0xc0, 0xf1, 0x75, 0x2f, 0x02, 0x12, 0x7e, 0x30, 0xe5, 0xc0, + 0x54, 0x03, 0x68, 0x05, 0x12, 0x77, 0xdd, 0x80, 0xf5, 0x30, 0xc2, 0x08, 0x75, 0xf1, 0x01, 0x12, + 0x71, 0xe9, 0x80, 0x14, 0x30, 0xc3, 0x08, 0x75, 0xf1, 0x01, 0x12, 0x71, 0x0d, 0x80, 0x09, 0x30, + 0xc4, 0x06, 0x75, 0xf1, 0x02, 0x12, 0x72, 0xf9, 0xd0, 0xf1, 0xda, 0xb8, 0x32, 0x75, 0x2f, 0x10, + 0x12, 0x7e, 0x30, 0xca, 0x0b, 0xca, 0x39, 0xca, 0x59, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x5c, 0xe5, + 0xe5, 0x54, 0xc0, 0x68, 0x4f, 0xe5, 0xe6, 0x6c, 0xaa, 0x7e, 0x37, 0x01, 0xc5, 0x2d, 0x35, 0xbe, + 0x34, 0x04, 0x00, 0x38, 0x4a, 0x7a, 0x37, 0x01, 0xc5, 0x7e, 0x37, 0x01, 0xc3, 0x7d, 0x43, 0x2d, + 0x45, 0xbe, 0x44, 0x09, 0xcc, 0x38, 0x40, 0x7a, 0x47, 0x01, 0xc3, 0x75, 0x2f, 0x11, 0x12, 0x7e, + 0x30, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x73, 0xc8, 0xa9, 0x21, 0xe5, 0x1f, 0xa9, 0xd4, + 0xe4, 0xa9, 0x24, 0xe4, 0xfc, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x3b, 0xe5, 0xe5, 0x54, 0xc0, 0x78, + 0xb4, 0x12, 0x76, 0x6a, 0xda, 0x59, 0xda, 0x39, 0xda, 0x0b, 0x22, 0x80, 0x29, 0x80, 0x58, 0x75, + 0x2f, 0x16, 0x12, 0x7e, 0x30, 0x80, 0xed, 0x75, 0x2f, 0x12, 0x12, 0x7e, 0x30, 0x7a, 0xb1, 0x2f, + 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x09, 0xcd, 0x9d, 0x54, 0x12, 0x73, 0xc8, 0x7e, 0x34, 0x05, 0xcd, + 0x7d, 0x54, 0x2d, 0x43, 0x80, 0xa1, 0xe5, 0xe5, 0x54, 0x03, 0x78, 0x12, 0x75, 0x2f, 0x13, 0x12, + 0x7e, 0x30, 0x7e, 0x0f, 0x29, 0xe9, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xe9, 0x80, 0xa7, 0x75, 0x2f, + 0x14, 0x12, 0x7e, 0x30, 0x7e, 0x0f, 0x29, 0xed, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xed, 0xa9, 0xd7, + 0xe4, 0xa9, 0x27, 0xe4, 0xfc, 0x80, 0x9d, 0x75, 0x2f, 0x15, 0x12, 0x7e, 0x30, 0x7e, 0x0f, 0x29, + 0xf1, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xf1, 0x80, 0xe5, 0x75, 0x2f, 0x18, 0x12, 0x7e, 0x30, 0xca, + 0x09, 0xca, 0x39, 0xca, 0x2b, 0xc2, 0xc2, 0xa9, 0x21, 0xf2, 0x52, 0xe5, 0xf5, 0x33, 0x82, 0xe7, + 0x40, 0x44, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x54, 0x00, 0x40, 0x9d, 0x35, 0x40, 0x43, 0x7a, 0x37, + 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc7, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x52, + 0x7a, 0x47, 0x01, 0xc7, 0x7d, 0x45, 0x12, 0x75, 0x26, 0xa9, 0x20, 0xf5, 0x22, 0x75, 0x2f, 0x19, + 0x12, 0x7e, 0x30, 0x7a, 0x91, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x81, 0xf7, 0x7a, 0x91, 0xf6, 0xe5, + 0xf5, 0x33, 0x82, 0xe7, 0x50, 0xbc, 0xda, 0x2b, 0xda, 0x39, 0xda, 0x09, 0x22, 0x80, 0x41, 0x80, + 0x64, 0x2d, 0x53, 0x6d, 0x33, 0x70, 0xb7, 0x7e, 0x04, 0x01, 0xcd, 0x7a, 0x07, 0x01, 0xc9, 0x7a, + 0x07, 0x01, 0xc7, 0xa9, 0x32, 0xf2, 0xdf, 0x85, 0x30, 0x2f, 0x12, 0x7e, 0x30, 0x75, 0xf6, 0x00, + 0x80, 0xd4, 0xca, 0x59, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x54, 0x12, 0x75, 0x26, 0x7e, 0x34, 0x01, + 0xcd, 0x7d, 0x54, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc7, 0x12, 0x75, 0x26, 0xda, 0x49, 0x80, 0x99, + 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x0f, 0x29, 0xd9, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xd9, + 0x80, 0x9d, 0x7e, 0x0f, 0x29, 0xe1, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xe1, 0xa9, 0xd7, 0xf4, 0xa9, + 0x27, 0xf4, 0xfc, 0x80, 0x8a, 0x7e, 0x0f, 0x29, 0xdd, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xdd, 0x80, + 0xeb, 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x2f, 0x29, 0xf9, 0x0b, 0x2c, 0x7a, 0x2f, 0x29, + 0xf9, 0x80, 0x34, 0x7e, 0x2f, 0x2a, 0x01, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, 0x01, 0xa9, 0xd7, 0xf4, + 0xa9, 0x27, 0xf4, 0xfc, 0x80, 0x21, 0x7e, 0x2f, 0x29, 0xfd, 0x0b, 0x2c, 0x7a, 0x2f, 0x29, 0xfd, + 0x80, 0xeb, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x2f, 0x28, 0x12, 0x7e, 0x30, 0xca, + 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xc2, 0xc4, 0xa9, 0x21, 0xf2, 0xb6, 0xe5, 0xf5, 0x33, 0x72, 0xe7, + 0x40, 0xe0, 0x7e, 0x0d, 0x30, 0x7e, 0x1d, 0x34, 0x7e, 0x2d, 0x38, 0x7e, 0x3d, 0x3c, 0x7e, 0x85, + 0x40, 0x7d, 0x90, 0x4d, 0x91, 0x4d, 0x92, 0x4d, 0x93, 0x4d, 0x94, 0x4d, 0x95, 0x4d, 0x96, 0x4d, + 0x97, 0x4d, 0x98, 0x68, 0x72, 0x7a, 0x11, 0xf3, 0x7a, 0x01, 0xf3, 0x7a, 0x31, 0xf3, 0x7a, 0x21, + 0xf3, 0x7a, 0x51, 0xf3, 0x7a, 0x41, 0xf3, 0x7a, 0x71, 0xf3, 0x7a, 0x61, 0xf3, 0x7a, 0x91, 0xf3, + 0x7a, 0x81, 0xf3, 0x30, 0x73, 0x1a, 0x7a, 0xb1, 0xf3, 0x7a, 0xa1, 0xf3, 0x7a, 0xd1, 0xf3, 0x7a, + 0xc1, 0xf3, 0x7a, 0xf1, 0xf3, 0x7a, 0xe1, 0xf3, 0x7d, 0x78, 0x7a, 0xf1, 0xf3, 0x7a, 0xe1, 0xf3, + 0xa9, 0x30, 0xf5, 0x03, 0x02, 0x72, 0xe6, 0x75, 0x2f, 0x29, 0x12, 0x7e, 0x30, 0x20, 0x73, 0x0b, + 0x75, 0x2f, 0x0a, 0x12, 0x7e, 0x30, 0x75, 0xf6, 0x0a, 0x80, 0x09, 0x75, 0x2f, 0x12, 0x12, 0x7e, + 0x30, 0x75, 0xf6, 0x12, 0x6d, 0x00, 0x7d, 0x10, 0x7a, 0x0d, 0x30, 0x7a, 0x0d, 0x34, 0x7a, 0x0d, + 0x38, 0x7a, 0x0d, 0x3c, 0x7a, 0x05, 0x40, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x1e, 0xb0, + 0x40, 0x0c, 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x75, 0x0b, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0xa1, + 0xe3, 0x7a, 0x39, 0xa0, 0x0b, 0x34, 0x80, 0xea, 0xb4, 0x40, 0xe3, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, + 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, + 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, + 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, + 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, + 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, + 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, + 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, + 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, + 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, + 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, + 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, + 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, + 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, + 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, + 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, + 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, + 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, + 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, + 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, + 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x22, 0x1e, 0xb0, 0x40, 0x0c, + 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x76, 0x69, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0x39, 0xa0, 0x7a, + 0xa1, 0xf3, 0x0b, 0x34, 0x80, 0xea, 0xb4, 0x40, 0xe3, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, + 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, + 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, + 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, + 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, + 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, + 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, + 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, + 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, + 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, + 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, + 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, + 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, + 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, + 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, + 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, + 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, + 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, + 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, + 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, + 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x22, 0xc2, 0xaf, 0x7e, 0x37, 0x01, 0xc5, + 0x4d, 0x33, 0x68, 0x3b, 0x7e, 0x07, 0x01, 0xc1, 0x7e, 0x54, 0x09, 0xcd, 0x9d, 0x50, 0xbd, 0x35, + 0x40, 0x02, 0x7d, 0x35, 0xca, 0x39, 0x7e, 0x65, 0x4b, 0x99, 0x64, 0xda, 0x39, 0x7e, 0x07, 0x01, + 0xc5, 0x9d, 0x03, 0x7a, 0x07, 0x01, 0xc5, 0x2e, 0x37, 0x01, 0xc1, 0x7a, 0x37, 0x01, 0xc1, 0xbe, + 0x34, 0x09, 0xcc, 0x28, 0xc7, 0x7e, 0x34, 0x05, 0xcd, 0x7a, 0x37, 0x01, 0xc1, 0x80, 0xbd, 0xd2, + 0xaf, 0x22, 0x75, 0x2f, 0x53, 0x12, 0x7e, 0x30, 0x7e, 0x15, 0x4d, 0x80, 0x11, 0x75, 0x2f, 0x51, + 0x12, 0x7e, 0x30, 0x0b, 0x08, 0x10, 0x0b, 0x05, 0x9e, 0x34, 0x00, 0x02, 0x28, 0x4d, 0x7c, 0xb2, + 0x20, 0xe7, 0x27, 0x54, 0x07, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x6e, 0x8c, 0x7c, 0xb2, 0x54, 0x78, + 0x03, 0x03, 0x03, 0x7c, 0x2b, 0x9d, 0x13, 0x40, 0x1a, 0x68, 0x12, 0x7a, 0x15, 0x4d, 0x7a, 0x25, + 0x4f, 0x7e, 0x64, 0x77, 0x47, 0x7a, 0x65, 0x4b, 0x89, 0x24, 0x02, 0x77, 0x55, 0x7e, 0x64, 0x76, + 0xbd, 0x80, 0xf2, 0x2d, 0x13, 0x9d, 0x31, 0xca, 0x39, 0x7d, 0x31, 0x2d, 0x10, 0xca, 0x19, 0xca, + 0x29, 0x99, 0x24, 0xda, 0x29, 0xda, 0x09, 0xda, 0x39, 0x80, 0xa2, 0x7a, 0x15, 0x4d, 0x7e, 0x64, + 0x77, 0x33, 0x4d, 0x33, 0x78, 0x09, 0x7c, 0xb2, 0x20, 0xe7, 0x2a, 0x7e, 0x64, 0x76, 0xb2, 0x7a, + 0x65, 0x4b, 0x22, 0x75, 0x2f, 0x52, 0x12, 0x7e, 0x30, 0x7e, 0x21, 0x4d, 0x7e, 0x09, 0x30, 0x0b, + 0x04, 0x1b, 0x34, 0x78, 0x89, 0x80, 0xd4, 0x75, 0x2f, 0x54, 0x12, 0x7e, 0x30, 0x7e, 0x15, 0x4d, + 0x7e, 0x25, 0x4f, 0x80, 0x90, 0x5e, 0x20, 0x07, 0x54, 0x78, 0x7e, 0x44, 0x77, 0xd1, 0x30, 0xe6, + 0x16, 0x4d, 0x33, 0x68, 0x26, 0x1b, 0x34, 0x7e, 0x09, 0x40, 0x0b, 0x04, 0x7e, 0x44, 0x6a, 0x68, + 0x20, 0xe3, 0x04, 0x7e, 0x44, 0x77, 0xd9, 0xca, 0x09, 0xca, 0x39, 0x99, 0x44, 0xda, 0x39, 0xda, + 0x09, 0x7e, 0x64, 0x76, 0xbd, 0x4d, 0x33, 0x68, 0xa6, 0x89, 0x64, 0x7a, 0x15, 0x4d, 0xf5, 0x4f, + 0x7e, 0x64, 0x77, 0x96, 0x80, 0x99, 0x7e, 0x15, 0x4d, 0xe5, 0x4f, 0x80, 0xc4, 0xc0, 0xd0, 0xc0, + 0xd1, 0xc0, 0xe0, 0xca, 0x19, 0xa9, 0x20, 0xdf, 0x12, 0xa9, 0x21, 0xdf, 0x1b, 0x75, 0x2f, 0x01, + 0x12, 0x7e, 0x30, 0x53, 0xdf, 0xf7, 0x12, 0x40, 0xdc, 0x80, 0x0d, 0x75, 0x2f, 0xfe, 0x12, 0x7e, + 0x30, 0x7e, 0x14, 0x00, 0x53, 0x02, 0x40, 0x51, 0xda, 0x19, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, + 0x32, 0x03, 0xa5, 0xcb, 0x19, 0xb1, 0x80, 0x00, 0x22, 0x22, 0x02, 0x78, 0x52, 0xca, 0x0b, 0xca, + 0x1b, 0xca, 0x2b, 0xca, 0x3b, 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0xc0, + 0xf1, 0x7e, 0xb3, 0x2a, 0x1d, 0xb4, 0x00, 0x02, 0x80, 0x19, 0xb4, 0x01, 0x16, 0x30, 0xc0, 0x08, + 0x75, 0xf1, 0x00, 0x12, 0x78, 0x3c, 0x80, 0x1f, 0x30, 0xc1, 0x1c, 0x75, 0xf1, 0x00, 0x12, 0x78, + 0xcd, 0x80, 0x14, 0x30, 0xc1, 0x08, 0x75, 0xf1, 0x00, 0x12, 0x78, 0xcd, 0x80, 0x09, 0x30, 0xc0, + 0x06, 0x75, 0xf1, 0x00, 0x12, 0x78, 0x3c, 0xd0, 0xf1, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, + 0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0xc2, 0xc0, 0x7e, 0xb3, + 0x2a, 0x1d, 0xb4, 0x02, 0x07, 0x12, 0x78, 0x5e, 0x02, 0x78, 0x52, 0x22, 0xb4, 0x01, 0xfc, 0x02, + 0x78, 0x98, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x2a, 0x1d, 0x7a, 0x03, 0x2a, 0x1e, 0x22, 0x7e, 0xb3, + 0x2a, 0x15, 0x54, 0x60, 0x60, 0x05, 0xb4, 0x40, 0x15, 0x80, 0x13, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, + 0x05, 0x0c, 0x75, 0x2f, 0x71, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xf5, 0x8f, 0x22, 0x75, + 0xf6, 0x00, 0x22, 0xbe, 0x57, 0x2a, 0x1b, 0x28, 0x04, 0x7e, 0x57, 0x2a, 0x1b, 0x7a, 0x0f, 0x2a, + 0x20, 0x7a, 0x57, 0x2a, 0x24, 0x02, 0x78, 0x98, 0x7e, 0xef, 0x2a, 0x20, 0x7e, 0xf7, 0x2a, 0x24, + 0x7e, 0x07, 0x2a, 0x24, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0x7e, 0xeb, 0xb0, 0xf5, 0xf3, + 0xa3, 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x04, 0xa5, 0xb8, 0x08, 0xf0, 0x7a, 0xef, 0x2a, 0x20, 0x7a, + 0xf7, 0x2a, 0x24, 0x75, 0x2f, 0x06, 0x12, 0x7e, 0x30, 0x7a, 0x01, 0xf6, 0x22, 0xc2, 0xc1, 0x75, + 0x2f, 0x03, 0x12, 0x7e, 0x30, 0xa9, 0x36, 0xe2, 0x16, 0xe5, 0xf5, 0x54, 0xc0, 0x68, 0x07, 0xa9, + 0xd7, 0xf4, 0xa9, 0x27, 0xf4, 0xfc, 0x53, 0xe1, 0x3f, 0x43, 0xf2, 0x88, 0x02, 0x79, 0x44, 0x7e, + 0xb3, 0x2a, 0x1e, 0xb4, 0x02, 0x0f, 0xa9, 0xd4, 0xe4, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x2a, 0x1e, + 0x7a, 0xb3, 0x2a, 0x1d, 0x22, 0xb4, 0x01, 0x39, 0x7e, 0x21, 0xe6, 0x7c, 0x32, 0x7e, 0x13, 0x2a, + 0x1f, 0x2c, 0x21, 0x7a, 0x23, 0x2a, 0x1f, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x2a, 0x26, 0xe5, 0xe3, + 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0xa5, 0xdb, 0xf6, 0xa9, 0xd4, 0xe4, 0x75, 0x2f, 0x70, 0x12, 0x7e, + 0x30, 0x7e, 0xb3, 0x2a, 0x1f, 0x7e, 0xa3, 0x2a, 0x1c, 0xbc, 0xab, 0x78, 0x03, 0x12, 0x79, 0xdb, + 0x22, 0x02, 0x7d, 0x44, 0xe5, 0xe6, 0xb4, 0x08, 0x65, 0xa9, 0xc4, 0xe2, 0x7e, 0x01, 0xe3, 0x7e, + 0x11, 0xe3, 0x7e, 0x31, 0xe3, 0x7e, 0x21, 0xe3, 0x7e, 0x51, 0xe3, 0x7e, 0x41, 0xe3, 0x7e, 0x71, + 0xe3, 0x7e, 0x61, 0xe3, 0x7a, 0x0f, 0x2a, 0x15, 0x7a, 0x1f, 0x2a, 0x19, 0x75, 0x2f, 0x04, 0x12, + 0x7e, 0x30, 0x7a, 0x01, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x21, + 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x31, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x41, 0x2f, 0x12, 0x7e, 0x30, + 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, + 0x7e, 0x30, 0xa9, 0xd4, 0xe4, 0xa9, 0xd7, 0xf4, 0xa9, 0xc6, 0xe2, 0x12, 0x79, 0xaf, 0x22, 0x6d, + 0x00, 0x7e, 0x14, 0x01, 0x02, 0x7a, 0x07, 0x2a, 0x24, 0x7a, 0x03, 0x2a, 0x1f, 0x7e, 0xb3, 0x2a, + 0x15, 0x20, 0xe7, 0x0f, 0x7a, 0x23, 0x2a, 0x1e, 0x7a, 0x33, 0x2a, 0x1d, 0xbe, 0x07, 0x2a, 0x1b, + 0x68, 0x09, 0x22, 0x7a, 0x33, 0x2a, 0x1e, 0x7a, 0x23, 0x2a, 0x1d, 0x7e, 0xb3, 0x2a, 0x15, 0x54, + 0xe3, 0x23, 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 0x06, + 0x30, 0xe4, 0x03, 0x02, 0x7d, 0x44, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 0xf0, + 0x90, 0x7a, 0x07, 0x75, 0x84, 0xff, 0x73, 0x02, 0x7b, 0x5b, 0x02, 0x7a, 0x4f, 0x02, 0x7b, 0xf8, + 0x02, 0x7c, 0x13, 0x02, 0x7a, 0xf4, 0x02, 0x7a, 0xb5, 0x02, 0x7c, 0x2c, 0x02, 0x7c, 0x2c, 0x02, + 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, + 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x35, 0x02, 0x7c, 0xe9, 0x02, 0x7c, 0x32, + 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x7e, + 0xb3, 0x2a, 0x16, 0xb4, 0x06, 0x2a, 0x7e, 0xb3, 0x2a, 0x17, 0x60, 0x56, 0x7c, 0x0b, 0x7e, 0x13, + 0x2a, 0x18, 0x7e, 0x17, 0x2a, 0x19, 0x75, 0x2f, 0x72, 0x12, 0x7e, 0x30, 0x7a, 0x01, 0x2f, 0x12, + 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x7d, 0x4e, 0x40, 0x35, 0x02, 0x78, 0x83, + 0xb4, 0x08, 0x10, 0x75, 0x2f, 0x74, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x3f, 0xf1, 0xf5, 0xf3, 0x75, + 0xf6, 0x01, 0x22, 0xb4, 0x00, 0x1c, 0x75, 0x2f, 0x75, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x3f, 0xf2, + 0x30, 0xe0, 0x05, 0x75, 0xf3, 0x02, 0x80, 0x03, 0x75, 0xf3, 0x00, 0x75, 0xf3, 0x00, 0x75, 0xf6, + 0x02, 0x22, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x00, 0x35, 0x75, 0x2f, 0x76, 0x12, + 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0xf5, 0xf1, 0x7e, 0xb3, 0x2a, 0x1a, 0x20, 0xe7, + 0x09, 0xe5, 0xe1, 0x30, 0xe7, 0x0d, 0x74, 0x01, 0x80, 0x0b, 0xe5, 0xe1, 0x30, 0xe6, 0x04, 0x74, + 0x01, 0x80, 0x02, 0x74, 0x00, 0x53, 0xf1, 0x80, 0xf5, 0xf3, 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, + 0x22, 0x02, 0x7d, 0x44, 0xc0, 0xf1, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0x42, 0xf1, 0x7e, 0xb3, + 0x2a, 0x18, 0xb4, 0x00, 0x45, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x01, 0x24, 0x75, 0x2f, 0x77, 0x12, + 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0x78, 0x05, 0x53, 0xe1, 0x3f, 0x80, 0x37, 0x7e, + 0xb3, 0x2a, 0x1a, 0x20, 0xe7, 0x05, 0x53, 0xe1, 0x7f, 0x80, 0x2b, 0x53, 0xe1, 0xbf, 0x80, 0x26, + 0xb4, 0x03, 0x17, 0x75, 0x2f, 0x78, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x20, 0xe7, 0x05, + 0x43, 0xe1, 0x80, 0x80, 0x11, 0x43, 0xe1, 0x40, 0x80, 0x0c, 0x43, 0xe1, 0xc0, 0xd0, 0xf1, 0x75, + 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x22, 0xd0, 0xf1, 0x02, 0x78, 0x7f, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, + 0x09, 0x23, 0x75, 0x2f, 0x79, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xbe, 0xb3, 0x3f, 0xf1, + 0x68, 0x11, 0xca, 0xb8, 0xc0, 0xf1, 0x12, 0x43, 0x68, 0xd0, 0xf1, 0xda, 0xb8, 0x50, 0x76, 0x7a, + 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x2f, 0x7a, 0x12, 0x7e, 0x30, 0x80, 0x62, + 0xb4, 0x03, 0x19, 0x75, 0x2f, 0x7b, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xb4, 0x01, 0x55, + 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 0xb4, 0x01, 0x19, 0x75, + 0x2f, 0x7c, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xb4, 0x01, 0x39, 0x7e, 0xb3, 0x3f, 0xf2, + 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 0xb3, 0x2a, 0x17, 0x60, + 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x2a, 0x18, 0x7e, 0x17, 0x2a, 0x19, 0x75, 0x2f, 0x73, 0x12, 0x7e, + 0x30, 0x7a, 0x01, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x7d, 0x7a, + 0x40, 0x03, 0x02, 0x78, 0x7f, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x0b, 0xf6, 0x75, + 0x2f, 0x7d, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0x7e, 0xa3, 0x2a, 0x1a, 0x4c, 0xab, 0x78, + 0xe4, 0x80, 0xdf, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x0a, 0xdb, 0x75, 0x2f, 0x7e, 0x12, 0x7e, 0x30, + 0x7e, 0xb3, 0x2a, 0x18, 0x70, 0xcf, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0x02, 0x7d, 0x44, 0x02, + 0x7d, 0x44, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x04, 0x20, 0x75, 0x2f, 0xc3, 0x12, + 0x7e, 0x30, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x17, 0x7e, 0x18, 0x2a, 0x26, 0x7a, 0x1c, + 0x00, 0x00, 0x7e, 0x47, 0x2a, 0x1b, 0x12, 0x7e, 0x3c, 0x02, 0x7c, 0xe3, 0xb4, 0x06, 0x3a, 0x75, + 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, + 0xd7, 0x2a, 0x17, 0x7e, 0x78, 0x2a, 0x26, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2a, 0x1b, 0x75, + 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7e, + 0x75, 0xd0, 0x87, 0xd0, 0xa8, 0x40, 0x4f, 0x80, 0x4a, 0xb4, 0x00, 0x1c, 0xc2, 0xaf, 0xa9, 0xd5, + 0x87, 0x12, 0x78, 0x7f, 0xe4, 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, + 0xca, 0x02, 0xff, 0xca, 0x06, 0x00, 0x00, 0x32, 0xb4, 0x09, 0x12, 0x7e, 0x57, 0x2a, 0x17, 0x4d, + 0x55, 0x68, 0x05, 0xa9, 0xd2, 0xb1, 0x80, 0x03, 0xa9, 0xc2, 0xb1, 0x80, 0x16, 0xb4, 0x07, 0x16, + 0xc2, 0xaf, 0x7e, 0x07, 0x2a, 0x19, 0x7e, 0x17, 0x2a, 0x17, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, + 0xca, 0x28, 0x32, 0x02, 0x78, 0x7f, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x03, 0x15, + 0x75, 0x2f, 0xc2, 0x12, 0x7e, 0x30, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x17, 0x7e, 0x57, + 0x2a, 0x1b, 0x02, 0x78, 0x83, 0xb4, 0x05, 0x39, 0x75, 0x2f, 0xc0, 0x12, 0x7e, 0x30, 0xc0, 0xa8, + 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x7e, 0x08, 0x2a, 0x26, 0x7a, 0x0c, 0x00, 0x00, 0x7e, + 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x2a, 0x17, 0x7e, 0x47, 0x2a, 0x1b, 0x12, 0x7e, 0x3c, 0xd0, 0x87, + 0xd0, 0xa8, 0x7e, 0x08, 0x2a, 0x26, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x2a, 0x1b, 0x02, 0x78, + 0x83, 0x02, 0x7d, 0x44, 0x75, 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x43, 0xe1, 0xc0, 0x22, 0xc0, 0xa8, + 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7d, 0xb9, 0x40, 0x19, 0x7e, 0x08, 0x2a, 0x26, + 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0xca, 0x49, 0x12, 0x7e, 0x3c, 0xda, 0x59, 0xda, 0x0b, 0xd0, + 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, + 0xa9, 0xd5, 0x87, 0x12, 0x7d, 0xb9, 0x40, 0x2b, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, + 0x7f, 0x61, 0x7e, 0x78, 0x2a, 0x26, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2a, 0x1b, 0xbd, 0x74, + 0x78, 0x11, 0x75, 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0x12, 0x7e, 0x75, 0x40, 0x06, 0xd0, 0x87, 0xd0, + 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x34, 0x7f, + 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, 0x87, 0x7e, 0x34, 0x7f, 0xc2, + 0x7e, 0x1b, 0xb0, 0x7e, 0x34, 0x7f, 0x03, 0xb4, 0x01, 0x04, 0x7e, 0x34, 0x7f, 0xcc, 0x7e, 0x1b, + 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, 0x2d, 0x75, 0x0b, 0x3a, 0x30, + 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, 0x1b, 0x50, 0x30, 0x3e, 0x10, + 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, 0x1a, 0x30, 0xbd, 0x38, 0x50, + 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, 0x90, 0x0a, 0x49, 0x4d, 0x44, + 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, 0xff, 0xc3, 0x22, 0xd3, 0x22, + +// Segment #15, Start Address 00ff7fc6, Length 4 +0xff,0x00,0xc6,0x7f,0x04,0x00, + 0x01, 0x0c, 0x03, 0x00, + +// Segment #16, Start Address 00ff7e30, Length 315 +0xff,0x00,0x30,0x7e,0x3b,0x01, + 0xca, 0x08, 0x7e, 0x01, 0x2f, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x7e, 0x1b, 0xc0, 0x7a, + 0x0b, 0xc0, 0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, + 0xfc, 0x7c, 0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, + 0x44, 0x00, 0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, + 0xfa, 0x7f, 0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, + 0x40, 0x9d, 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x7e, 0x9f, + 0xda, 0x79, 0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x43, + 0x90, 0x30, 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb5, 0x2a, 0xaa, 0x74, 0xa0, + 0x39, 0xb5, 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 0x70, 0x50, 0x06, 0x2d, 0x70, 0x7d, 0x07, + 0x6d, 0x77, 0x7c, 0x31, 0x7e, 0x7b, 0x00, 0x7a, 0x6b, 0x00, 0x0b, 0x7c, 0x0b, 0x6c, 0xa5, 0xd9, + 0xf3, 0x7f, 0x16, 0x1b, 0x1c, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x1b, 0x10, 0xbc, 0x10, 0x68, 0x06, + 0x1b, 0x54, 0x78, 0xf5, 0x80, 0x2c, 0x6d, 0x00, 0x7c, 0x20, 0x7f, 0x16, 0x9f, 0x10, 0x7f, 0x27, + 0x9f, 0x20, 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 0x01, 0x78, 0x16, 0x0b, 0x2c, 0x0b, 0x1c, + 0xa5, 0xdb, 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x03, 0x63, 0x90, 0x30, 0x4d, 0x77, 0x78, 0x93, 0xc2, + 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, + 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x04, 0x00, 0x08, 0x10, 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, + 0x18, 0x7f, 0xbd, 0x7a, 0x1c, 0x00, 0xfe, 0x0b, 0x1a, 0x00, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, + 0x51, 0x23, 0x7e, 0x18, 0x7f, 0x15, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, + 0x08, 0xa5, 0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, +}; + +static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = { + 1, 12, 3 }; // Major, Minor, Build + +#undef IMAGE_VERSION_NAME + +#undef IMAGE_ARRAY_NAME + diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_fw_down2.h linux/drivers/usb/serial/io_fw_down2.h --- v2.4.2/linux/drivers/usb/serial/io_fw_down2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_fw_down2.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,1135 @@ +//************************************************************** +//* Edgeport/4 Binary Image +//* Generated by HEX2C v1.06 +//* Copyright(c) 1998 Inside Out Networks, All rights reserved. +//* 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. +//************************************************************** + + +//Image structure definition +#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD) + #define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD + typedef struct _EDGE_FIRMWARE_IMAGE_RECORD + { + unsigned short ExtAddr; + unsigned short Addr; + unsigned short Len; + unsigned char Data[0]; + } EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD; + + typedef struct _EDGE_FIRMWARE_VERSION_INFO + { + unsigned char MajorVersion; + unsigned char MinorVersion; + unsigned short BuildNumber; + } EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO; + +#endif + +#if !defined(IMAGE_ARRAY_NAME) + #define IMAGE_ARRAY_NAME FirmwareImage + #define IMAGE_VERSION_NAME FirmwareImageVersion +#endif + +static unsigned char IMAGE_ARRAY_NAME[] = { + +// Segment #1, Start Address 00ff0000, Length 6 +0xff,0x00,0x00,0x00,0x06,0x00, + 0x02, 0x00, 0x80, 0x02, 0x45, 0x14, + +// Segment #2, Start Address 00ff000b, Length 3 +0xff,0x00,0x0b,0x00,0x03,0x00, + 0x02, 0x44, 0xa5, + +// Segment #3, Start Address 00ff0013, Length 3 +0xff,0x00,0x13,0x00,0x03,0x00, + 0x02, 0x63, 0xab, + +// Segment #4, Start Address 00ff001b, Length 3 +0xff,0x00,0x1b,0x00,0x03,0x00, + 0x02, 0x00, 0x1b, + +// Segment #5, Start Address 00ff0023, Length 3 +0xff,0x00,0x23,0x00,0x03,0x00, + 0x02, 0x00, 0x23, + +// Segment #6, Start Address 00ff002b, Length 3 +0xff,0x00,0x2b,0x00,0x03,0x00, + 0x02, 0x00, 0x2b, + +// Segment #7, Start Address 00ff0033, Length 3 +0xff,0x00,0x33,0x00,0x03,0x00, + 0x02, 0x00, 0x33, + +// Segment #8, Start Address 00ff003b, Length 3 +0xff,0x00,0x3b,0x00,0x03,0x00, + 0x02, 0x00, 0x3b, + +// Segment #9, Start Address 00ff0043, Length 3 +0xff,0x00,0x43,0x00,0x03,0x00, + 0x02, 0x00, 0x43, + +// Segment #10, Start Address 00ff004b, Length 3 +0xff,0x00,0x4b,0x00,0x03,0x00, + 0x02, 0x00, 0x4b, + +// Segment #11, Start Address 00ff0053, Length 3 +0xff,0x00,0x53,0x00,0x03,0x00, + 0x02, 0x67, 0x5f, + +// Segment #12, Start Address 00ff007b, Length 3 +0xff,0x00,0x7b,0x00,0x03,0x00, + 0x02, 0x00, 0x7b, + +// Segment #13, Start Address 00ff0080, Length 7 +0xff,0x00,0x80,0x00,0x07,0x00, + 0x7e, 0x14, 0x00, 0x00, 0x02, 0x40, 0x52, + +// Segment #14, Start Address 00ff3000, Length 2918 +0xff,0x00,0x00,0x30,0x66,0x0b, + 0x12, 0x30, 0x64, 0x12, 0x30, 0xff, 0x12, 0x31, 0x2f, 0x12, 0x30, 0xb0, 0x80, 0xf2, 0xe5, 0x23, + 0x60, 0x19, 0x7e, 0x14, 0x00, 0x00, 0x09, 0xb1, 0x01, 0xb9, 0xb4, 0x00, 0x02, 0x80, 0x05, 0x14, + 0x19, 0xb1, 0x01, 0xb9, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xeb, 0x22, 0xc2, 0xaf, 0x7e, 0xb3, + 0x3f, 0xf1, 0xb4, 0x01, 0x03, 0x12, 0x65, 0x67, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x7e, 0xb3, 0x3f, + 0xf1, 0xb4, 0x01, 0x1d, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x1a, 0x6c, 0xaa, + 0x60, 0x0f, 0xca, 0x0b, 0xca, 0x39, 0xca, 0x59, 0x12, 0x64, 0x24, 0xda, 0x59, 0xda, 0x39, 0xda, + 0x0b, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x22, 0x60, 0x43, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, + 0x03, 0x80, 0x38, 0x39, 0x7e, 0x04, 0x80, 0x00, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x21, 0x09, 0xa0, + 0x00, 0x04, 0x4e, 0xa0, 0x05, 0x19, 0xa0, 0x00, 0x04, 0x0a, 0x32, 0x09, 0x53, 0x35, 0x33, 0x5e, + 0x51, 0x27, 0x68, 0x0b, 0x09, 0xa0, 0x00, 0x10, 0x4e, 0xa0, 0x01, 0x19, 0xa0, 0x00, 0x10, 0x2e, + 0x04, 0x01, 0x00, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xd1, 0x75, 0x22, 0x00, 0xd2, 0xaf, 0x22, + 0xc2, 0xaf, 0xe5, 0x26, 0x60, 0x36, 0x7e, 0x20, 0x00, 0x7e, 0x30, 0x01, 0xe5, 0x26, 0xa5, 0x5b, + 0x68, 0x21, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x32, 0x01, 0x79, 0xbe, 0x34, 0x00, 0x00, 0x68, + 0x12, 0x7e, 0xb1, 0x21, 0xa5, 0x4b, 0x7a, 0xb1, 0x21, 0xca, 0x19, 0x49, 0x22, 0x30, 0xef, 0x99, + 0x24, 0xda, 0x19, 0x3e, 0x30, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xd0, 0xd2, 0xaf, 0x22, 0x46, + 0x4f, 0x49, 0x7c, 0x4c, 0xa9, 0x4f, 0xd6, 0x53, 0x03, 0x56, 0x30, 0x59, 0x5d, 0x5c, 0x8a, 0xc2, + 0xaf, 0xe5, 0x24, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x31, 0x1c, + 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xef, 0xd2, 0xaf, 0x22, 0xca, 0x28, 0x12, 0x35, + 0x4c, 0xda, 0x28, 0x40, 0x09, 0x0a, 0x22, 0x09, 0xb2, 0x35, 0x33, 0xf4, 0x52, 0x24, 0x22, 0xc2, + 0xaf, 0xe5, 0x23, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x31, 0x4c, + 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, + 0x2b, 0x49, 0x22, 0x31, 0x57, 0x89, 0x24, 0x31, 0x67, 0x31, 0xd0, 0x32, 0x39, 0x32, 0xa2, 0x33, + 0x0b, 0x33, 0x74, 0x33, 0xdd, 0x34, 0x46, 0x7e, 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 0x00, 0x78, + 0x24, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, + 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x49, 0x45, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, + 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x89, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x89, 0x7e, + 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xb9, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xb9, 0xa5, 0xbe, 0x00, 0x1f, + 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, + 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x18, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xb9, 0x12, 0x64, 0x86, 0x22, + 0x7e, 0x27, 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, + 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, + 0x4c, 0x72, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, + 0x01, 0x8b, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8b, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xba, 0x80, + 0x27, 0x7e, 0x63, 0x01, 0xba, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, + 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x19, 0x6c, + 0x00, 0x7a, 0x03, 0x01, 0xba, 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, + 0x00, 0x78, 0x24, 0x7e, 0x24, 0x82, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, + 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4f, 0x9f, 0x7d, 0x21, 0xda, 0x19, 0x30, + 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x8d, 0x68, 0x0d, 0x7a, 0x27, 0x01, + 0x8d, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbb, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xbb, 0xa5, 0xbe, + 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, + 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x1a, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xbb, 0x12, 0x64, + 0x86, 0x22, 0x7e, 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x83, 0x00, + 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, + 0x12, 0x12, 0x52, 0xcc, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, + 0xbe, 0x27, 0x01, 0x8f, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8f, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, + 0xbc, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xbc, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, + 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, + 0x1b, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xbc, 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 0x81, 0xbe, + 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, + 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x55, 0xf9, 0x7d, 0x21, 0xda, + 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x91, 0x68, 0x0d, 0x7a, + 0x27, 0x01, 0x91, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbd, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xbd, + 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, + 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x1c, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xbd, + 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, + 0x85, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, + 0x19, 0x7d, 0x12, 0x12, 0x59, 0x26, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, + 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x93, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x93, 0x7e, 0x60, 0x9c, 0x7a, + 0x63, 0x01, 0xbe, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xbe, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, + 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, + 0x35, 0xc2, 0x1d, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xbe, 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, + 0x85, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5c, 0x53, 0x7d, + 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x95, 0x68, + 0x0d, 0x7a, 0x27, 0x01, 0x95, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbf, 0x80, 0x27, 0x7e, 0x63, + 0x01, 0xbf, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, + 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x1e, 0x6c, 0x00, 0x7a, 0x03, + 0x01, 0xbf, 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 0x87, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, + 0x7e, 0x24, 0x87, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, + 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5f, 0x80, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, + 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x97, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x97, 0x7e, 0x60, + 0x9c, 0x7a, 0x63, 0x01, 0xc0, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xc0, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, + 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, + 0x12, 0x73, 0x35, 0xc2, 0x1f, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xc0, 0x12, 0x64, 0x86, 0x22, 0xc2, + 0xaf, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, 0x00, 0x00, 0x78, 0x28, 0x74, 0x20, 0x7a, 0xb3, 0x91, + 0x00, 0x7e, 0xb3, 0x91, 0x15, 0x30, 0xe5, 0x1b, 0x7e, 0xb3, 0x91, 0x1a, 0xbe, 0xb0, 0x3f, 0x38, + 0x0c, 0x85, 0x31, 0x2f, 0x12, 0x73, 0x35, 0x74, 0x80, 0x7a, 0xb3, 0x91, 0x1e, 0x74, 0x20, 0x7a, + 0xb3, 0x91, 0x15, 0xd2, 0xaf, 0x22, 0x35, 0x3b, 0x36, 0xe8, 0x37, 0x00, 0x37, 0x1b, 0x37, 0xb6, + 0x38, 0x4e, 0x38, 0x69, 0x38, 0xfb, 0x38, 0x84, 0x38, 0xc5, 0x7c, 0xb3, 0xbe, 0xb0, 0x09, 0x28, + 0x22, 0x75, 0x2f, 0x09, 0x12, 0x73, 0x35, 0x75, 0x57, 0x02, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x00, + 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x11, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x01, 0x7a, 0xb3, + 0x91, 0x11, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x23, 0x6c, 0xaa, 0x2e, 0x54, 0x34, 0xe6, 0x0b, 0x58, + 0x50, 0x89, 0x54, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x75, 0x2f, 0xb0, 0x12, 0x73, + 0x35, 0x0a, 0x22, 0x09, 0xb2, 0x35, 0x33, 0x42, 0x24, 0xd0, 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, + 0x3b, 0x49, 0x33, 0x35, 0x57, 0x89, 0x34, 0x35, 0x67, 0x35, 0x95, 0x35, 0xc3, 0x35, 0xf1, 0x36, + 0x1f, 0x36, 0x4d, 0x36, 0x7b, 0x36, 0xa9, 0x12, 0x41, 0xba, 0xd2, 0x28, 0xd2, 0x08, 0xc2, 0x40, + 0xc2, 0x48, 0xc2, 0x38, 0xc2, 0x30, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xb9, 0x7e, 0x04, 0x00, 0x20, + 0x7a, 0x07, 0x01, 0x99, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xa9, 0x12, 0x41, 0x27, 0x12, + 0x5f, 0xb7, 0x02, 0x36, 0xd7, 0x12, 0x41, 0xd7, 0xd2, 0x29, 0xd2, 0x09, 0xc2, 0x41, 0xc2, 0x49, + 0xc2, 0x39, 0xc2, 0x31, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xba, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, + 0x01, 0x9b, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xab, 0x12, 0x41, 0x27, 0x12, 0x5f, 0xe0, + 0x02, 0x36, 0xd7, 0x12, 0x41, 0xf4, 0xd2, 0x2a, 0xd2, 0x0a, 0xc2, 0x42, 0xc2, 0x4a, 0xc2, 0x3a, + 0xc2, 0x32, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbb, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9d, + 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xad, 0x12, 0x41, 0x27, 0x12, 0x60, 0x09, 0x02, 0x36, + 0xd7, 0x12, 0x42, 0x11, 0xd2, 0x2b, 0xd2, 0x0b, 0xc2, 0x43, 0xc2, 0x4b, 0xc2, 0x3b, 0xc2, 0x33, + 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbc, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9f, 0x7e, 0x04, + 0x00, 0x38, 0x7a, 0x07, 0x01, 0xaf, 0x12, 0x41, 0x27, 0x12, 0x60, 0x32, 0x02, 0x36, 0xd7, 0x12, + 0x42, 0x2e, 0xd2, 0x2c, 0xd2, 0x0c, 0xc2, 0x44, 0xc2, 0x4c, 0xc2, 0x3c, 0xc2, 0x34, 0x6d, 0x00, + 0x7a, 0x03, 0x01, 0xbd, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa1, 0x7e, 0x04, 0x00, 0x38, + 0x7a, 0x07, 0x01, 0xb1, 0x12, 0x41, 0x27, 0x12, 0x60, 0x5b, 0x02, 0x36, 0xd7, 0x12, 0x42, 0x4b, + 0xd2, 0x2d, 0xd2, 0x0d, 0xc2, 0x45, 0xc2, 0x4d, 0xc2, 0x3d, 0xc2, 0x35, 0x6d, 0x00, 0x7a, 0x03, + 0x01, 0xbe, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa3, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, + 0x01, 0xb3, 0x12, 0x41, 0x27, 0x12, 0x60, 0x84, 0x02, 0x36, 0xd7, 0x12, 0x42, 0x68, 0xd2, 0x2e, + 0xd2, 0x0e, 0xc2, 0x46, 0xc2, 0x4e, 0xc2, 0x3e, 0xc2, 0x36, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbf, + 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa5, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb5, + 0x12, 0x41, 0x27, 0x12, 0x60, 0xad, 0x02, 0x36, 0xd7, 0x12, 0x42, 0x85, 0xd2, 0x2f, 0xd2, 0x0f, + 0xc2, 0x47, 0xc2, 0x4f, 0xc2, 0x3f, 0xc2, 0x37, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xc0, 0x7e, 0x04, + 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa7, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb7, 0x12, 0x41, + 0x27, 0x12, 0x60, 0xd6, 0x02, 0x36, 0xd7, 0x7e, 0xa0, 0xd0, 0x7e, 0x60, 0x0f, 0x12, 0x61, 0x36, + 0x40, 0x05, 0x12, 0x64, 0x86, 0xc2, 0xd7, 0x22, 0x75, 0x2f, 0xb1, 0x12, 0x73, 0x35, 0x0a, 0x52, + 0x23, 0x6d, 0x00, 0x59, 0x05, 0x00, 0x32, 0x12, 0x41, 0x83, 0x12, 0x41, 0x9f, 0xd0, 0xa8, 0x22, + 0x75, 0x2f, 0xb2, 0x12, 0x73, 0x35, 0x0a, 0x22, 0x09, 0xb2, 0x35, 0x33, 0x42, 0x23, 0x7e, 0xb0, + 0x9c, 0x19, 0xb2, 0x01, 0xb9, 0x12, 0x31, 0x4c, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, + 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x19, + 0x30, 0x00, 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x12, 0x44, 0x40, 0xca, 0xb8, 0x09, 0xb0, + 0x00, 0x10, 0x44, 0x02, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x02, 0x54, 0xbf, 0x7c, 0x74, + 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x08, 0x80, 0x02, 0x54, 0xf7, 0x09, 0x30, 0x00, 0x0c, 0xca, + 0xb8, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xda, 0xb8, 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, + 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x35, 0x33, 0x3e, 0x20, 0x0a, 0x62, 0x7c, 0x74, 0x5e, 0x70, 0x02, + 0x68, 0x20, 0x42, 0x27, 0xca, 0xb8, 0x74, 0x61, 0x19, 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x10, + 0x59, 0x46, 0x01, 0xa9, 0x09, 0xb0, 0x00, 0x10, 0x44, 0x01, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, + 0x80, 0x11, 0xf4, 0x52, 0x27, 0x74, 0xa1, 0x19, 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x38, 0x59, + 0x46, 0x01, 0xa9, 0xd0, 0xa8, 0x22, 0x7c, 0x74, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, + 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x7c, 0x74, 0x5e, 0x70, + 0x01, 0x68, 0x04, 0x44, 0x80, 0x80, 0x02, 0x54, 0x7f, 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, + 0x44, 0x02, 0x80, 0x02, 0x54, 0xfd, 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, + 0x09, 0xb6, 0x35, 0x33, 0xa5, 0xfd, 0xf4, 0xa5, 0xfe, 0xca, 0x28, 0x3e, 0x20, 0x0a, 0x62, 0xda, + 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x10, 0xa5, 0xed, 0x42, 0x28, 0x42, 0x26, 0x7e, 0x44, + 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x04, 0xa5, 0xee, 0x52, 0x28, 0x7c, 0x74, 0x5e, 0x70, + 0x04, 0x68, 0x10, 0xa5, 0xed, 0x42, 0x29, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, + 0x99, 0x80, 0x15, 0xa5, 0xee, 0x52, 0x29, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x78, 0x0a, 0x52, 0x26, + 0x7e, 0x44, 0x00, 0x20, 0x59, 0x46, 0x01, 0x99, 0x12, 0x42, 0xa2, 0xd0, 0xa8, 0x22, 0x7e, 0x04, + 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, + 0x00, 0x10, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, + 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 0x00, 0x18, 0x19, 0x30, 0x00, + 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb5, 0x12, 0x73, 0x35, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, + 0x09, 0xb0, 0x00, 0x0c, 0x44, 0x40, 0x19, 0xb0, 0x00, 0x0c, 0xe5, 0x58, 0xb4, 0x07, 0x23, 0x09, + 0xb0, 0x00, 0x10, 0x4e, 0xb0, 0x02, 0x19, 0xb0, 0x00, 0x10, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, + 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x54, 0xf7, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, + 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb6, 0x12, 0x73, 0x35, 0x7e, 0x04, 0x80, 0x00, 0x4c, + 0x02, 0xe5, 0x58, 0xb4, 0x07, 0x18, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, + 0x09, 0xb0, 0x00, 0x04, 0x44, 0x08, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 0x00, 0x0c, 0x09, 0xb0, + 0x00, 0x0c, 0x54, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb4, 0x12, 0x73, + 0x35, 0x7a, 0x21, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x41, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0xb0, 0x01, + 0x7e, 0xa0, 0xc8, 0x7c, 0x64, 0x12, 0x61, 0x36, 0x12, 0x64, 0x86, 0xd0, 0xa8, 0x22, 0x39, 0x2e, + 0x39, 0x75, 0x39, 0xbc, 0x3a, 0x03, 0x3a, 0x4a, 0x3a, 0x91, 0x3a, 0xd8, 0x3b, 0x1f, 0x75, 0x2f, + 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, + 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x69, 0x7e, 0x27, 0x01, 0x79, 0x2d, 0x23, + 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x08, 0x2c, 0x38, 0x0f, + 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x69, 0x7a, 0x27, 0x01, 0x79, 0x02, 0x46, 0x4f, 0x7e, + 0x14, 0x04, 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x01, 0x12, 0x73, + 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, + 0x6b, 0x7e, 0x27, 0x01, 0x7b, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, + 0x14, 0xbe, 0x14, 0x0c, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6b, 0x7a, + 0x27, 0x01, 0x7b, 0x02, 0x49, 0x7c, 0x7e, 0x14, 0x08, 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, + 0x73, 0x35, 0x75, 0x2f, 0x02, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, + 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x6d, 0x7e, 0x27, 0x01, 0x7d, 0x2d, 0x23, 0x7e, 0x09, + 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x10, 0x2c, 0x38, 0x0f, 0x1b, 0x34, + 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6d, 0x7a, 0x27, 0x01, 0x7d, 0x02, 0x4c, 0xa9, 0x7e, 0x14, 0x0c, + 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x03, 0x12, 0x73, 0x35, 0x7a, + 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x6f, 0x7e, + 0x27, 0x01, 0x7f, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, + 0x14, 0x14, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6f, 0x7a, 0x27, 0x01, + 0x7f, 0x02, 0x4f, 0xd6, 0x7e, 0x14, 0x10, 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, + 0x75, 0x2f, 0x04, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, + 0x73, 0x35, 0x7e, 0x17, 0x01, 0x71, 0x7e, 0x27, 0x01, 0x81, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, + 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x18, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, + 0x7a, 0x17, 0x01, 0x71, 0x7a, 0x27, 0x01, 0x81, 0x02, 0x53, 0x03, 0x7e, 0x14, 0x14, 0x2d, 0x80, + 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x05, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, + 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x73, 0x7e, 0x27, 0x01, + 0x83, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x1c, + 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x73, 0x7a, 0x27, 0x01, 0x83, 0x02, + 0x56, 0x30, 0x7e, 0x14, 0x18, 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, + 0x06, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, + 0x7e, 0x17, 0x01, 0x75, 0x7e, 0x27, 0x01, 0x85, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, + 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x20, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, + 0x01, 0x75, 0x7a, 0x27, 0x01, 0x85, 0x02, 0x59, 0x5d, 0x7e, 0x14, 0x1c, 0x2d, 0x80, 0xeb, 0x75, + 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x07, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, + 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x77, 0x7e, 0x27, 0x01, 0x87, 0x2d, + 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x24, 0x2c, 0x38, + 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x77, 0x7a, 0x27, 0x01, 0x87, 0x02, 0x5c, 0x8a, + 0x7e, 0x14, 0x20, 0x2d, 0x80, 0xeb, + +// Segment #15, Start Address 00ff4000, Length 13109 +0xff,0x00,0x00,0x40,0x35,0x33, + 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x14, 0x7f, 0xf8, 0x7e, 0x24, 0x00, 0xfe, 0x7d, 0x31, 0x0b, 0x1a, + 0x50, 0x1b, 0x0a, 0x50, 0x7e, 0x14, 0x40, 0x1b, 0x02, 0x40, 0x74, 0x7e, 0xf8, 0x00, 0x59, 0x75, + 0xb0, 0xdf, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x90, 0x00, 0x7e, 0xf4, 0x40, 0x30, 0x02, 0x40, 0x8b, + 0x12, 0x74, 0x4e, 0xf5, 0x2e, 0x7a, 0xa1, 0x2d, 0x7a, 0x11, 0x58, 0x12, 0x6b, 0x02, 0x12, 0x40, + 0xeb, 0x7e, 0xb3, 0x3f, 0xf1, 0x60, 0x03, 0x12, 0x43, 0x79, 0x12, 0x6b, 0xde, 0xd2, 0xaf, 0x02, + 0x30, 0x00, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x60, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, + 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x94, 0x00, 0x7a, 0xb3, 0x2c, 0x35, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, + 0x93, 0x00, 0x89, 0x08, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x82, 0x7a, 0x1c, 0x00, 0x01, + 0x89, 0x18, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x93, 0x00, 0x89, 0x08, 0x7e, 0x08, 0x00, 0x20, 0x7e, + 0x44, 0x04, 0x00, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0x9d, 0x02, 0x73, 0x50, 0x7e, 0x08, 0x01, + 0x59, 0x7e, 0x44, 0x2a, 0xdd, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0xaf, 0x02, 0x73, 0x50, 0x7e, + 0x08, 0x00, 0x59, 0x7e, 0x44, 0x01, 0x00, 0x7e, 0x40, 0x53, 0x7e, 0xe4, 0x40, 0xc1, 0x02, 0x73, + 0x50, 0x75, 0x57, 0x01, 0x75, 0x56, 0x00, 0x7e, 0x04, 0x00, 0x08, 0x75, 0x54, 0x58, 0x75, 0x55, + 0x08, 0x75, 0x51, 0x08, 0x75, 0x53, 0x01, 0x75, 0x89, 0x01, 0x75, 0x8a, 0x01, 0x75, 0x8c, 0x00, + 0xd2, 0x8c, 0x7e, 0x04, 0x00, 0x02, 0x7a, 0x05, 0x42, 0x89, 0xf4, 0x75, 0xb7, 0x7f, 0x75, 0xb8, + 0x7f, 0x75, 0xb3, 0x01, 0x75, 0xb2, 0x01, 0xd2, 0xa9, 0x22, 0x75, 0xb0, 0xdf, 0xe4, 0xd5, 0xe0, + 0xfd, 0x75, 0xb0, 0xef, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x2e, 0x7e, 0xa0, 0x08, 0x19, 0xa2, + 0x00, 0x10, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf2, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x83, 0x0b, + 0x20, 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x74, 0xbf, 0x19, + 0xb0, 0x00, 0x0c, 0x74, 0x10, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x80, 0x19, 0xb0, 0x00, 0x0c, 0x7e, + 0x54, 0x00, 0x02, 0x19, 0xa0, 0x00, 0x04, 0x19, 0xb0, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb0, 0x00, + 0x0c, 0x74, 0x07, 0x20, 0x68, 0x02, 0x74, 0x0f, 0x19, 0xb0, 0x00, 0x04, 0x30, 0x6b, 0x17, 0x74, + 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0x28, 0x20, 0x68, 0x02, 0x74, 0x20, 0x19, 0xb0, 0x00, 0x04, + 0x74, 0x03, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x0c, 0x19, 0xb0, + 0x00, 0x10, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe4, 0x19, 0xb0, 0x00, 0x04, 0x09, 0xb0, + 0x00, 0x10, 0x54, 0x08, 0x19, 0xb0, 0x00, 0x10, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x22, 0x7c, + 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x41, 0xaa, 0x89, 0x24, 0x41, 0xba, 0x41, 0xd7, 0x41, 0xf4, + 0x42, 0x11, 0x42, 0x2e, 0x42, 0x4b, 0x42, 0x68, 0x42, 0x85, 0xc2, 0x10, 0xc2, 0x18, 0xc2, 0x08, + 0x7e, 0x04, 0x04, 0x2d, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x6d, 0x00, 0x7a, 0x07, + 0x01, 0x79, 0x7a, 0x07, 0x01, 0x89, 0x22, 0xc2, 0x11, 0xc2, 0x19, 0xc2, 0x09, 0x7e, 0x04, 0x08, + 0x2d, 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7b, 0x7a, + 0x07, 0x01, 0x8b, 0x22, 0xc2, 0x12, 0xc2, 0x1a, 0xc2, 0x0a, 0x7e, 0x04, 0x0c, 0x2d, 0x7a, 0x07, + 0x01, 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7d, 0x7a, 0x07, 0x01, 0x8d, + 0x22, 0xc2, 0x13, 0xc2, 0x1b, 0xc2, 0x0b, 0x7e, 0x04, 0x10, 0x2d, 0x7a, 0x07, 0x01, 0x5f, 0x7a, + 0x07, 0x01, 0x6f, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7f, 0x7a, 0x07, 0x01, 0x8f, 0x22, 0xc2, 0x14, + 0xc2, 0x1c, 0xc2, 0x0c, 0x7e, 0x04, 0x14, 0x2d, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, + 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x81, 0x7a, 0x07, 0x01, 0x91, 0x22, 0xc2, 0x15, 0xc2, 0x1d, 0xc2, + 0x0d, 0x7e, 0x04, 0x18, 0x2d, 0x7a, 0x07, 0x01, 0x63, 0x7a, 0x07, 0x01, 0x73, 0x6d, 0x00, 0x7a, + 0x07, 0x01, 0x83, 0x7a, 0x07, 0x01, 0x93, 0x22, 0xc2, 0x16, 0xc2, 0x1e, 0xc2, 0x0e, 0x7e, 0x04, + 0x1c, 0x2d, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x85, + 0x7a, 0x07, 0x01, 0x95, 0x22, 0xc2, 0x17, 0xc2, 0x1f, 0xc2, 0x0f, 0x7e, 0x04, 0x20, 0x2d, 0x7a, + 0x07, 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x87, 0x7a, 0x07, 0x01, + 0x97, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x42, 0xad, 0x89, 0x24, 0x42, 0xbd, 0x42, + 0xd4, 0x42, 0xeb, 0x43, 0x02, 0x43, 0x19, 0x43, 0x30, 0x43, 0x47, 0x43, 0x5e, 0x30, 0x40, 0x07, + 0x20, 0x58, 0x04, 0xc2, 0x28, 0x80, 0x0c, 0x30, 0x48, 0x07, 0x20, 0x50, 0x04, 0xc2, 0x28, 0x80, + 0x02, 0xd2, 0x28, 0x22, 0x30, 0x41, 0x07, 0x20, 0x59, 0x04, 0xc2, 0x29, 0x80, 0x0c, 0x30, 0x49, + 0x07, 0x20, 0x51, 0x04, 0xc2, 0x29, 0x80, 0x02, 0xd2, 0x29, 0x22, 0x30, 0x42, 0x07, 0x20, 0x5a, + 0x04, 0xc2, 0x2a, 0x80, 0x0c, 0x30, 0x4a, 0x07, 0x20, 0x52, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, + 0x2a, 0x22, 0x30, 0x43, 0x07, 0x20, 0x5b, 0x04, 0xc2, 0x2b, 0x80, 0x0c, 0x30, 0x4b, 0x07, 0x20, + 0x53, 0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2b, 0x22, 0x30, 0x44, 0x07, 0x20, 0x5c, 0x04, 0xc2, + 0x2c, 0x80, 0x0c, 0x30, 0x4c, 0x07, 0x20, 0x54, 0x04, 0xc2, 0x2c, 0x80, 0x02, 0xd2, 0x2c, 0x22, + 0x30, 0x45, 0x07, 0x20, 0x5d, 0x04, 0xc2, 0x2d, 0x80, 0x0c, 0x30, 0x4d, 0x07, 0x20, 0x55, 0x04, + 0xc2, 0x2d, 0x80, 0x02, 0xd2, 0x2d, 0x22, 0x30, 0x46, 0x07, 0x20, 0x5e, 0x04, 0xc2, 0x2e, 0x80, + 0x0c, 0x30, 0x4e, 0x07, 0x20, 0x56, 0x04, 0xc2, 0x2e, 0x80, 0x02, 0xd2, 0x2e, 0x22, 0x30, 0x47, + 0x07, 0x20, 0x5f, 0x04, 0xc2, 0x2f, 0x80, 0x0c, 0x30, 0x4f, 0x07, 0x20, 0x57, 0x04, 0xc2, 0x2f, + 0x80, 0x02, 0xd2, 0x2f, 0x22, 0x44, 0x66, 0x43, 0x8a, 0xbe, 0xb0, 0x02, 0x40, 0x01, 0x22, 0x23, + 0x0a, 0x5b, 0x49, 0x55, 0x43, 0x75, 0x99, 0x54, 0xd3, 0x22, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x94, + 0x00, 0x7a, 0xb3, 0x2c, 0x35, 0x12, 0x44, 0x7a, 0x7e, 0x04, 0x28, 0x2d, 0x7a, 0x07, 0x01, 0xc1, + 0x7a, 0x07, 0x01, 0xc3, 0x7e, 0x04, 0x24, 0x2d, 0x7a, 0x07, 0x01, 0xc7, 0x7a, 0x07, 0x01, 0xc9, + 0x7e, 0x04, 0x66, 0x7f, 0x7a, 0x05, 0x4b, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, + 0xb3, 0x91, 0x1c, 0x74, 0x12, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x07, 0x74, + 0x1e, 0x7a, 0xb3, 0x91, 0x10, 0x74, 0x48, 0x7a, 0xb3, 0x91, 0x12, 0x74, 0x10, 0x7a, 0xb3, 0x91, + 0x13, 0x74, 0x3f, 0x7a, 0xb3, 0x91, 0x14, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, + 0xb3, 0x91, 0x1c, 0x74, 0x14, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x07, 0x74, + 0x16, 0x7a, 0xb3, 0x91, 0x10, 0x74, 0x08, 0x7a, 0xb3, 0x91, 0x11, 0x74, 0x20, 0x7a, 0xb3, 0x91, + 0x13, 0x74, 0x3f, 0x7a, 0xb3, 0x91, 0x14, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, + 0xb3, 0x91, 0x1c, 0x74, 0x16, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x07, 0x74, + 0x2f, 0x7a, 0xb3, 0x91, 0x10, 0x74, 0x48, 0x7a, 0xb3, 0x91, 0x12, 0x74, 0x10, 0x7a, 0xb3, 0x91, + 0x13, 0x74, 0x3f, 0x7a, 0xb3, 0x91, 0x14, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x0f, 0x7a, + 0xb3, 0x91, 0x07, 0x12, 0x40, 0xfa, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x9f, 0x0b, 0x20, 0xbe, 0x21, + 0x2e, 0x78, 0xf6, 0xd2, 0xa8, 0x22, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x94, 0x00, 0x7a, 0xb3, 0x2c, + 0x35, 0x12, 0x44, 0x7a, 0x75, 0xb0, 0xdf, 0xc2, 0xa8, 0x22, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x06, + 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x07, 0x7e, 0x20, 0x04, 0x7c, 0xb2, 0xc2, 0xd7, 0x13, 0x13, 0x13, + 0x13, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x74, 0x02, 0x7a, 0xb3, 0x91, + 0x12, 0xa5, 0xda, 0xe5, 0x22, 0xca, 0x09, 0x12, 0x30, 0x0e, 0x10, 0x01, 0x34, 0xd5, 0x51, 0x40, + 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0xb3, 0x91, 0x07, + 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0xb3, 0x91, 0x07, 0x7e, 0xb3, 0x91, 0x14, 0x7e, 0xb3, + 0x91, 0x04, 0x63, 0x53, 0x01, 0x7e, 0x00, 0x54, 0x2e, 0x01, 0x53, 0xa5, 0xe6, 0xf5, 0x51, 0x80, + 0x12, 0x20, 0x02, 0x1d, 0x75, 0x53, 0x00, 0x85, 0x54, 0x51, 0xd2, 0x02, 0x74, 0x03, 0x80, 0x0d, + 0x30, 0x02, 0x0e, 0xc2, 0x02, 0x7e, 0x00, 0x56, 0x2e, 0x01, 0x53, 0xa5, 0xe6, 0x7a, 0xb3, 0x90, + 0x00, 0xda, 0x09, 0x32, 0x45, 0x6f, 0x45, 0x8b, 0x45, 0xa7, 0x45, 0xc3, 0x45, 0xdf, 0x45, 0xfb, + 0x46, 0x17, 0x46, 0x33, 0xc0, 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xc0, 0xf0, 0xca, 0x0b, 0xca, 0x1b, + 0xca, 0x2b, 0xd2, 0x01, 0x75, 0x2f, 0x89, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x90, 0x00, 0x60, 0x28, + 0x7e, 0x14, 0x80, 0x00, 0x7e, 0x00, 0x00, 0x13, 0x50, 0x13, 0xca, 0x0b, 0xca, 0x59, 0x7c, 0xb0, + 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x45, 0x04, 0x99, 0x24, 0xda, 0x59, 0xda, 0x0b, 0xa5, 0x0a, 0xa5, + 0x08, 0xbe, 0x01, 0x2e, 0x78, 0xe1, 0x80, 0xd2, 0x30, 0x04, 0x05, 0xc2, 0x04, 0x12, 0x64, 0x86, + 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0xd0, 0xf0, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x09, + 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 0x80, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, + 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x61, 0xab, 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, + 0xe0, 0x14, 0x75, 0x2f, 0x81, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, + 0x69, 0x52, 0x61, 0xeb, 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, + 0x82, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x62, 0x2b, + 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 0x83, 0x12, 0x73, 0x35, + 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x62, 0x6b, 0x89, 0x54, 0x22, 0x09, + 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 0x84, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, + 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x62, 0xab, 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, + 0xe0, 0x14, 0x75, 0x2f, 0x85, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, + 0x69, 0x52, 0x62, 0xeb, 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, + 0x86, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, 0x2b, + 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 0x87, 0x12, 0x73, 0x35, + 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, 0x6b, 0x89, 0x54, 0x22, 0x10, + 0x08, 0x01, 0x22, 0x20, 0x28, 0x03, 0xd2, 0x08, 0x22, 0x75, 0x2f, 0xa0, 0x12, 0x73, 0x35, 0x7e, + 0x14, 0x80, 0x00, 0x80, 0x06, 0x20, 0x28, 0x03, 0xd2, 0x08, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x49, 0x45, 0x30, 0x30, 0x06, 0x20, 0xe6, + 0x4f, 0xd2, 0x08, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x60, 0x7e, 0x37, 0x01, 0x79, 0x7e, 0x27, 0x01, + 0x99, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, + 0x79, 0x7e, 0x37, 0x01, 0x59, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x08, 0x2c, 0x38, 0x68, 0x7a, + 0x47, 0x01, 0x59, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, + 0x69, 0xf0, 0x10, 0x60, 0xc4, 0x22, 0xc2, 0x60, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, + 0x7e, 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x99, 0x28, 0x04, + 0x7e, 0x27, 0x01, 0x99, 0x7e, 0x37, 0x01, 0x79, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x32, 0x7a, + 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, 0x37, 0x01, 0x59, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, + 0x08, 0x2c, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x59, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, + 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, + 0x12, 0x73, 0x35, 0x9e, 0x44, 0x08, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x04, 0x2d, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x59, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, + 0x02, 0x46, 0xc2, 0x22, 0xd2, 0x08, 0x7e, 0x04, 0x04, 0x2d, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, + 0x01, 0x69, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, + 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, + 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xa9, 0x2e, 0x24, 0x00, 0x02, 0x2d, + 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, + 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, + 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x00, 0x00, 0x2e, 0x27, 0x01, 0xa9, 0x1b, 0x38, 0x20, + 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, + 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x38, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, + 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x00, 0x00, 0x2e, 0x67, 0x01, + 0xa9, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, + 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, + 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, + 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x00, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, + 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, + 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, + 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, + 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, + 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, + 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, + 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, + 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, + 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x48, 0x1e, 0x75, 0x2f, + 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x38, + 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0xda, 0xb8, + 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x48, 0x1e, 0xda, 0xb8, 0x02, 0x49, + 0x45, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, + 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, + 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x50, + 0x80, 0x02, 0xc2, 0x50, 0x12, 0x42, 0xbd, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, + 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, + 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, + 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, + 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x48, 0x72, 0x75, 0x2f, + 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x09, 0x01, 0x22, + 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x75, 0x2f, 0xa1, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x81, 0x00, + 0x80, 0x06, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, + 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x4c, 0x72, 0x30, 0x31, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x09, + 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x61, 0x7e, 0x37, 0x01, 0x7b, 0x7e, 0x27, 0x01, 0x9b, 0x9d, 0x32, + 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 0x7a, 0x37, 0x01, 0x7b, 0x7e, 0x37, + 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0c, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5b, + 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, + 0x61, 0xc4, 0x22, 0xc2, 0x61, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, + 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9b, 0x28, 0x04, 0x7e, 0x27, 0x01, + 0x9b, 0x7e, 0x37, 0x01, 0x7b, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 0x7a, + 0x37, 0x01, 0x7b, 0x7e, 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0c, 0x2c, 0x38, + 0x13, 0x7a, 0x47, 0x01, 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, + 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, + 0x9e, 0x44, 0x0c, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x08, 0x2d, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0x5b, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x49, 0xef, + 0x22, 0xd2, 0x09, 0x7e, 0x04, 0x08, 0x2d, 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 0x75, + 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, + 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, + 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xab, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, + 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, + 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, + 0x01, 0xc9, 0x7e, 0x24, 0x01, 0x00, 0x2e, 0x27, 0x01, 0xab, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, + 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, + 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x01, 0x00, 0x2e, 0x67, 0x01, 0xab, 0x9e, 0x24, + 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, + 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, + 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, + 0x0f, 0x23, 0x23, 0x23, 0x44, 0x01, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, + 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, + 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, + 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, + 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, + 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, + 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, + 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, + 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4b, 0x4b, 0x75, 0x2f, 0x99, 0x12, 0x73, + 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, + 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, + 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4b, 0x4b, 0xda, 0xb8, 0x02, 0x4c, 0x72, 0x09, 0xb1, + 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, + 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, + 0x80, 0x02, 0xc2, 0x59, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, + 0x51, 0x12, 0x42, 0xd4, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, + 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, + 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, + 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, + 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4b, 0x9f, 0x75, 0x2f, 0x95, 0x12, 0x73, + 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x0a, 0x01, 0x22, 0x20, 0x2a, 0x03, + 0xd2, 0x0a, 0x22, 0x75, 0x2f, 0xa2, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x82, 0x00, 0x80, 0x06, 0x20, + 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, + 0x68, 0x03, 0x12, 0x4f, 0x9f, 0x30, 0x32, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0a, 0x22, 0x30, 0xe6, + 0x02, 0xd2, 0x62, 0x7e, 0x37, 0x01, 0x7d, 0x7e, 0x27, 0x01, 0x9d, 0x9d, 0x32, 0x40, 0x31, 0x7d, + 0x02, 0x2e, 0x05, 0x36, 0x7a, 0x05, 0x36, 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, + 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x10, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, + 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 0x62, 0xc4, 0x22, + 0xc2, 0x62, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7d, 0xbe, 0x24, + 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9d, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9d, 0x7e, 0x37, + 0x01, 0x7d, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x36, 0x7a, 0x05, 0x36, 0x7a, 0x37, 0x01, 0x7d, + 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x10, 0x2c, 0x38, 0x13, 0x7a, 0x47, + 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, + 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x10, + 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x0c, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, + 0x01, 0x5d, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4d, 0x1c, 0x22, 0xd2, 0x0a, + 0x7e, 0x04, 0x0c, 0x2d, 0x7a, 0x07, 0x01, 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x75, 0x2f, 0x94, 0x12, + 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, + 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, + 0xcb, 0x7e, 0x27, 0x01, 0xad, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, + 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, + 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, + 0x24, 0x02, 0x00, 0x2e, 0x27, 0x01, 0xad, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, + 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, + 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, + 0x00, 0x10, 0xd2, 0x12, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, + 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x02, 0x00, 0x2e, 0x67, 0x01, 0xad, 0x9e, 0x24, 0x00, 0x02, 0x40, + 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, + 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, + 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, + 0x23, 0x44, 0x02, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, + 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, + 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, + 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, + 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, + 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, + 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, + 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, + 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4e, 0x78, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, + 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, + 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, + 0x07, 0xca, 0xb8, 0x12, 0x4e, 0x78, 0xda, 0xb8, 0x02, 0x4f, 0x9f, 0x09, 0xb1, 0x00, 0x18, 0x7e, + 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, + 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, + 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x12, 0x42, + 0xeb, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, + 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, + 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, + 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, + 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4e, 0xcc, 0x75, 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, + 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x0b, 0x01, 0x22, 0x20, 0x2b, 0x03, 0xd2, 0x0b, 0x22, + 0x75, 0x2f, 0xa3, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x83, 0x00, 0x80, 0x06, 0x20, 0x2b, 0x03, 0xd2, + 0x0b, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, + 0x52, 0xcc, 0x30, 0x33, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0b, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x63, + 0x7e, 0x37, 0x01, 0x7f, 0x7e, 0x27, 0x01, 0x9f, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, + 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 0x01, 0x5f, 0x7d, 0x43, 0x2d, 0x42, + 0xbe, 0x44, 0x14, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5f, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, + 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 0x63, 0xc4, 0x22, 0xc2, 0x63, 0x2d, + 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 0x68, + 0x6a, 0xbe, 0x27, 0x01, 0x9f, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9f, 0x7e, 0x37, 0x01, 0x7f, 0x9d, + 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 0x01, + 0x5f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x14, 0x2c, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5f, 0x75, + 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, + 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x14, 0x2d, 0x9d, 0x24, + 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x10, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5f, 0x12, + 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x50, 0x49, 0x22, 0xd2, 0x0b, 0x7e, 0x04, 0x10, + 0x2d, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, 0x01, 0x6f, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, + 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, + 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, + 0x01, 0xaf, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, + 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, + 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x03, 0x00, + 0x2e, 0x27, 0x01, 0xaf, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, + 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, + 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, + 0x13, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, + 0x7e, 0x64, 0x03, 0x00, 0x2e, 0x67, 0x01, 0xaf, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, + 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, + 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, + 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x03, + 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, + 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, + 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, + 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, + 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, + 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, + 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, + 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, + 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, + 0x78, 0xe7, 0x02, 0x51, 0xa5, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, + 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, + 0x00, 0x10, 0xd2, 0x13, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, + 0x12, 0x51, 0xa5, 0xda, 0xb8, 0x02, 0x52, 0xcc, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, + 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, + 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, + 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, 0x80, 0x02, 0xc2, 0x53, 0x12, 0x43, 0x02, 0x02, 0x61, + 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, + 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, + 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, + 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, + 0xdb, 0x22, 0x02, 0x51, 0xf9, 0x75, 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, + 0x73, 0x35, 0x22, 0x10, 0x0c, 0x01, 0x22, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x75, 0x2f, 0xa4, + 0x12, 0x73, 0x35, 0x7e, 0x14, 0x84, 0x00, 0x80, 0x06, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x09, + 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x55, 0xf9, 0x30, + 0x34, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0c, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x64, 0x7e, 0x37, 0x01, + 0x81, 0x7e, 0x27, 0x01, 0xa1, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, + 0x3a, 0x7a, 0x37, 0x01, 0x81, 0x7e, 0x37, 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x18, + 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x61, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, + 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 0x64, 0xc4, 0x22, 0xc2, 0x64, 0x2d, 0x23, 0x68, 0x78, + 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x81, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, + 0x01, 0xa1, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa1, 0x7e, 0x37, 0x01, 0x81, 0x9d, 0x32, 0x7d, 0x02, + 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, 0x37, 0x01, 0x81, 0x7e, 0x37, 0x01, 0x61, 0x7d, 0x43, + 0x2d, 0x42, 0xbe, 0x44, 0x18, 0x2c, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x61, 0x75, 0x2f, 0x94, 0x12, + 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, + 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x18, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, + 0x7e, 0x34, 0x14, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x61, 0x12, 0x69, 0xf0, 0xbe, + 0x25, 0x20, 0x78, 0x03, 0x02, 0x53, 0x76, 0x22, 0xd2, 0x0c, 0x7e, 0x04, 0x14, 0x2d, 0x7a, 0x07, + 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, + 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, + 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb1, 0x2e, + 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, + 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, + 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x04, 0x00, 0x2e, 0x27, 0x01, + 0xb1, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, + 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, + 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x14, 0x22, 0x80, + 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x04, + 0x00, 0x2e, 0x67, 0x01, 0xb1, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, + 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, + 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, + 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x04, 0x7a, 0x69, 0xb0, + 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, + 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, + 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, + 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, + 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, + 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, + 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, + 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, + 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, + 0x54, 0xd2, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, + 0x00, 0x04, 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, + 0x14, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x54, 0xd2, + 0xda, 0xb8, 0x02, 0x55, 0xf9, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, + 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, + 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 0x50, 0x80, + 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x12, 0x43, 0x19, 0x02, 0x61, 0x13, 0x75, 0x2f, + 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, + 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, + 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, + 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, + 0x55, 0x26, 0x75, 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, + 0x10, 0x0d, 0x01, 0x22, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x75, 0x2f, 0xa5, 0x12, 0x73, 0x35, + 0x7e, 0x14, 0x85, 0x00, 0x80, 0x06, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x09, 0xb1, 0x00, 0x14, + 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x59, 0x26, 0x30, 0x35, 0x06, 0x20, + 0xe6, 0x4f, 0xd2, 0x0d, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x65, 0x7e, 0x37, 0x01, 0x83, 0x7e, 0x27, + 0x01, 0xa3, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3c, 0x7a, 0x05, 0x3c, 0x7a, 0x37, + 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1c, 0x2c, 0x38, 0x68, + 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, + 0x12, 0x69, 0xf0, 0x10, 0x65, 0xc4, 0x22, 0xc2, 0x65, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, + 0x1a, 0x7e, 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa3, 0x28, + 0x04, 0x7e, 0x27, 0x01, 0xa3, 0x7e, 0x37, 0x01, 0x83, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3c, + 0x7a, 0x05, 0x3c, 0x7a, 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 0xbe, + 0x44, 0x1c, 0x2c, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, + 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, + 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x1c, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x18, + 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x63, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, + 0x03, 0x02, 0x56, 0xa3, 0x22, 0xd2, 0x0d, 0x7e, 0x04, 0x18, 0x2d, 0x7a, 0x07, 0x01, 0x63, 0x7a, + 0x07, 0x01, 0x73, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, + 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, + 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb3, 0x2e, 0x24, 0x00, 0x02, + 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, + 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, + 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x05, 0x00, 0x2e, 0x27, 0x01, 0xb3, 0x1b, 0x38, + 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, + 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, + 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0x80, 0x7f, 0x7a, 0x51, + 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x05, 0x00, 0x2e, 0x67, + 0x01, 0xb3, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, + 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, + 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, + 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x05, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, + 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, + 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, + 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, + 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, + 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, + 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, + 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, + 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, + 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x57, 0xff, 0x75, + 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, + 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0xda, + 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x57, 0xff, 0xda, 0xb8, 0x02, + 0x59, 0x26, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, + 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, + 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, + 0x55, 0x80, 0x02, 0xc2, 0x55, 0x12, 0x43, 0x30, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, + 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, + 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, + 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, + 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x58, 0x53, 0x75, + 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x0e, 0x01, + 0x22, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 0x75, 0x2f, 0xa6, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x86, + 0x00, 0x80, 0x06, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, + 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5c, 0x53, 0x30, 0x36, 0x06, 0x20, 0xe6, 0x4f, 0xd2, + 0x0e, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x66, 0x7e, 0x37, 0x01, 0x85, 0x7e, 0x27, 0x01, 0xa5, 0x9d, + 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, + 0x37, 0x01, 0x65, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x20, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, + 0x65, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, + 0x10, 0x66, 0xc4, 0x22, 0xc2, 0x66, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, + 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa5, 0x28, 0x04, 0x7e, 0x27, + 0x01, 0xa5, 0x7e, 0x37, 0x01, 0x85, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3e, 0x7a, 0x05, 0x3e, + 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, 0x65, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x20, 0x2c, + 0x38, 0x13, 0x7a, 0x47, 0x01, 0x65, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, + 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, + 0x35, 0x9e, 0x44, 0x20, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x1c, 0x2d, 0x7d, 0x24, + 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x65, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x59, + 0xd0, 0x22, 0xd2, 0x0e, 0x7e, 0x04, 0x1c, 0x2d, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, + 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, + 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, + 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb5, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, + 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, + 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, + 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x06, 0x00, 0x2e, 0x27, 0x01, 0xb5, 0x1b, 0x38, 0x20, 0x0b, 0x35, + 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, + 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, 0x10, + 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, + 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x06, 0x00, 0x2e, 0x67, 0x01, 0xb5, 0x9e, + 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, + 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, + 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, + 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x06, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, + 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, + 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, + 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, + 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, + 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, + 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, + 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, + 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, + 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5b, 0x2c, 0x75, 0x2f, 0x99, 0x12, + 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, + 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0xda, 0xb8, 0x30, 0xe0, + 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5b, 0x2c, 0xda, 0xb8, 0x02, 0x5c, 0x53, 0x09, + 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, + 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, + 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, 0x02, + 0xc2, 0x56, 0x12, 0x43, 0x47, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, + 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, + 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, + 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, + 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5b, 0x80, 0x75, 0x2f, 0x95, 0x12, + 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x0f, 0x01, 0x22, 0x20, 0x2f, + 0x03, 0xd2, 0x0f, 0x22, 0x75, 0x2f, 0xa7, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x87, 0x00, 0x80, 0x06, + 0x20, 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, + 0xb8, 0x68, 0x03, 0x12, 0x5f, 0x80, 0x30, 0x37, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0f, 0x22, 0x30, + 0xe6, 0x02, 0xd2, 0x67, 0x7e, 0x37, 0x01, 0x87, 0x7e, 0x27, 0x01, 0xa7, 0x9d, 0x32, 0x40, 0x31, + 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 0x01, 0x87, 0x7e, 0x37, 0x01, 0x67, + 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x24, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x67, 0x75, 0x2f, + 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 0x67, 0xc4, + 0x22, 0xc2, 0x67, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x87, 0xbe, + 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa7, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa7, 0x7e, + 0x37, 0x01, 0x87, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 0x01, + 0x87, 0x7e, 0x37, 0x01, 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x24, 0x2c, 0x38, 0x13, 0x7a, + 0x47, 0x01, 0x67, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, + 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, + 0x24, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x20, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, + 0x47, 0x01, 0x67, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5c, 0xfd, 0x22, 0xd2, + 0x0f, 0x7e, 0x04, 0x20, 0x2d, 0x7a, 0x07, 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x75, 0x2f, 0x94, + 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, + 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, + 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb7, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, + 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, + 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, + 0x7e, 0x24, 0x07, 0x00, 0x2e, 0x27, 0x01, 0xb7, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, + 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, + 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, + 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, + 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x07, 0x00, 0x2e, 0x67, 0x01, 0xb7, 0x9e, 0x24, 0x00, 0x02, + 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, + 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, + 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, + 0x23, 0x23, 0x44, 0x07, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, + 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, + 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, + 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, + 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, + 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, + 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, + 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, + 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, + 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5e, 0x59, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, + 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, + 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, + 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5e, 0x59, 0xda, 0xb8, 0x02, 0x5f, 0x80, 0x09, 0xb1, 0x00, 0x18, + 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, + 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, + 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x57, 0x80, 0x02, 0xc2, 0x57, 0x12, + 0x43, 0x5e, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, + 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, + 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, + 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, + 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5e, 0xad, 0x75, 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, + 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, + 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, + 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x50, 0x80, 0x02, 0xc2, 0x50, 0x02, 0x60, 0xff, + 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, + 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, + 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, + 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, + 0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x02, + 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, + 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, + 0x68, 0x04, 0xd2, 0x53, 0x80, 0x02, 0xc2, 0x53, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, + 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, + 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, + 0x54, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, + 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0xa5, 0xfd, 0x5e, + 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, 0x02, 0xc2, 0x55, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, + 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, + 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, + 0x02, 0xc2, 0x56, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, + 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, + 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x57, 0x80, 0x02, 0xc2, 0x57, 0x02, 0x60, 0xff, 0x54, + 0xf0, 0xc4, 0xa5, 0xff, 0xc4, 0xa5, 0x4f, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, + 0x73, 0x35, 0x22, 0xca, 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x2c, 0x2d, 0xca, 0x79, + 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x02, 0x7e, + 0x64, 0x00, 0x02, 0x02, 0x61, 0x5e, 0xca, 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x2c, + 0x2d, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0x7a, 0x79, 0x60, + 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x03, 0x7e, 0x64, 0x00, 0x03, 0x02, 0x61, 0x5e, 0xd2, 0x04, + 0x7e, 0x27, 0x01, 0xcb, 0x2d, 0x26, 0xbe, 0x24, 0x04, 0x00, 0x38, 0x2e, 0x7e, 0x07, 0x01, 0xc9, + 0x7e, 0x44, 0x28, 0x2d, 0x7e, 0x79, 0xa0, 0x7a, 0x09, 0xa0, 0x0b, 0x04, 0x0b, 0x74, 0xbd, 0x04, + 0x68, 0x23, 0xa5, 0xdb, 0xef, 0x7a, 0x27, 0x01, 0xcb, 0x7e, 0x25, 0x30, 0x2d, 0x26, 0x7a, 0x25, + 0x30, 0x7a, 0x07, 0x01, 0xc9, 0xda, 0x19, 0xc2, 0xd7, 0x22, 0x75, 0x2f, 0x9a, 0x12, 0x73, 0x35, + 0xda, 0x19, 0xd2, 0xd7, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xd7, 0x48, 0xf1, 0x46, 0x65, 0x47, + 0x5f, 0x49, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x48, 0x56, 0x45, 0x2a, 0x49, 0x6e, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x49, 0x75, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x4c, 0x1e, 0x49, 0x92, 0x4a, + 0x8c, 0x4c, 0x57, 0x45, 0x2a, 0x45, 0x2a, 0x4b, 0x83, 0x45, 0x2a, 0x4c, 0x9b, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x4c, 0xa2, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x4f, 0x4b, 0x4c, 0xbf, 0x4d, + 0xb9, 0x4f, 0x84, 0x45, 0x2a, 0x45, 0x2a, 0x4e, 0xb0, 0x45, 0x2a, 0x4f, 0xc8, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x4f, 0xcf, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x52, 0x78, 0x4f, 0xec, 0x50, + 0xe6, 0x52, 0xb1, 0x45, 0x2a, 0x45, 0x2a, 0x51, 0xdd, 0x45, 0x2a, 0x52, 0xf5, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x52, 0xfc, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x55, 0xa5, 0x53, 0x19, 0x54, + 0x13, 0x55, 0xde, 0x45, 0x2a, 0x45, 0x2a, 0x55, 0x0a, 0x45, 0x2a, 0x56, 0x22, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x56, 0x29, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x58, 0xd2, 0x56, 0x46, 0x57, + 0x40, 0x59, 0x0b, 0x45, 0x2a, 0x45, 0x2a, 0x58, 0x37, 0x45, 0x2a, 0x59, 0x4f, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x59, 0x56, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x5b, 0xff, 0x59, 0x73, 0x5a, + 0x6d, 0x5c, 0x38, 0x45, 0x2a, 0x45, 0x2a, 0x5b, 0x64, 0x45, 0x2a, 0x5c, 0x7c, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x5c, 0x83, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x5f, 0x2c, 0x5c, 0xa0, 0x5d, + 0x9a, 0x5f, 0x65, 0x45, 0x2a, 0x45, 0x2a, 0x5e, 0x91, 0x45, 0x2a, 0x5f, 0xa9, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x5f, 0xb0, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, + 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0xca, 0xb8, 0x75, 0x2f, 0x02, + 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x91, 0x03, 0x20, 0xe5, 0x20, 0x30, 0xe0, 0x05, 0x12, 0x6b, 0x05, + 0x80, 0x30, 0x30, 0xe1, 0x05, 0x12, 0x64, 0x86, 0x80, 0x28, 0x30, 0xe2, 0x05, 0x12, 0x63, 0xf5, + 0x80, 0x20, 0x30, 0xe3, 0x1d, 0x12, 0x65, 0x61, 0x80, 0x18, 0x7e, 0xb3, 0x91, 0x04, 0x30, 0xe1, + 0x03, 0x02, 0x67, 0x5f, 0x30, 0xe6, 0x05, 0x12, 0x6c, 0x6a, 0x80, 0x06, 0x20, 0xe2, 0x03, 0x02, + 0x00, 0x80, 0xda, 0xb8, 0x32, 0x75, 0x2f, 0x10, 0x12, 0x73, 0x35, 0xca, 0x0b, 0xca, 0x39, 0xca, + 0x59, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x1a, 0x6c, 0xaa, 0xbe, 0xb0, 0x40, + 0x28, 0x0a, 0x12, 0x64, 0x24, 0xda, 0x59, 0xda, 0x39, 0xda, 0x0b, 0x22, 0x74, 0x20, 0x7a, 0xb3, + 0x91, 0x14, 0x80, 0xf1, 0x7e, 0x37, 0x01, 0xc5, 0x2d, 0x35, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x2f, + 0x7a, 0x37, 0x01, 0xc5, 0x7e, 0x37, 0x01, 0xc3, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 0x44, 0x2c, 0x2c, + 0x38, 0x25, 0x7a, 0x47, 0x01, 0xc3, 0x75, 0x2f, 0x11, 0x12, 0x73, 0x35, 0x7a, 0xb1, 0x2f, 0x12, + 0x73, 0x35, 0x12, 0x67, 0x9f, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x12, 0x66, 0x30, 0x22, 0x75, + 0x2f, 0x16, 0x12, 0x73, 0x35, 0x80, 0xf4, 0x75, 0x2f, 0x12, 0x12, 0x73, 0x35, 0x7a, 0xb1, 0x2f, + 0x12, 0x73, 0x35, 0x9e, 0x44, 0x2c, 0x2d, 0x9d, 0x54, 0x12, 0x67, 0x9f, 0x7e, 0x34, 0x28, 0x2d, + 0x7d, 0x54, 0x2d, 0x43, 0x80, 0xbc, 0x75, 0x2f, 0x18, 0x12, 0x73, 0x35, 0xca, 0x09, 0xca, 0x39, + 0xca, 0x2b, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0x63, 0x91, 0x1a, 0x74, 0x10, 0x7a, 0xb3, + 0x91, 0x14, 0x7e, 0xb0, 0x80, 0x9c, 0xb6, 0x60, 0x38, 0x6c, 0xaa, 0x7e, 0x37, 0x01, 0xcb, 0x9d, + 0x35, 0x40, 0x37, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc7, 0x7d, 0x43, 0x2d, 0x45, 0xbe, + 0x44, 0x28, 0x2c, 0x38, 0x3b, 0x7a, 0x47, 0x01, 0xc7, 0x7d, 0x45, 0x12, 0x68, 0xd4, 0x7e, 0xb3, + 0x91, 0x1e, 0x20, 0xe5, 0x13, 0x75, 0x2f, 0x19, 0x12, 0x73, 0x35, 0x7a, 0x91, 0x2f, 0x12, 0x73, + 0x35, 0xda, 0x2b, 0xda, 0x39, 0xda, 0x09, 0x22, 0x80, 0x34, 0x2d, 0x53, 0x6d, 0x33, 0x60, 0x02, + 0x80, 0xc1, 0x7e, 0x04, 0x24, 0x2d, 0x7a, 0x07, 0x01, 0xc9, 0x7a, 0x07, 0x01, 0xc7, 0x80, 0xe1, + 0xca, 0x59, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x54, 0x12, 0x68, 0xd4, 0x7e, 0x34, 0x24, 0x2d, 0x7d, + 0x54, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc7, 0x12, 0x68, 0xd4, 0xda, 0x49, 0x80, 0xb0, 0x7e, 0x0f, + 0x2c, 0x3e, 0x0b, 0x0c, 0x7a, 0x0f, 0x2c, 0x3e, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x1e, 0x74, 0x60, + 0x7a, 0xb3, 0x91, 0x1c, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x12, 0x80, 0xa5, 0x7e, 0x2f, 0x2c, 0x5e, + 0x0b, 0x2c, 0x7a, 0x2f, 0x2c, 0x5e, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x1e, 0x74, 0x60, 0x7a, 0xb3, + 0x91, 0x1c, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x12, 0x80, 0x1f, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, + 0x22, 0x75, 0x2f, 0x28, 0x12, 0x73, 0x35, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0x74, 0x60, 0x7a, + 0xb3, 0x91, 0x00, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x14, 0x7e, 0xb3, 0x91, 0x1a, 0x70, 0xdb, 0x7e, + 0x0d, 0x30, 0x7e, 0x1d, 0x34, 0x7e, 0x2d, 0x38, 0x7e, 0x3d, 0x3c, 0x7e, 0x85, 0x40, 0x7d, 0x90, + 0x4d, 0x91, 0x4d, 0x92, 0x4d, 0x93, 0x4d, 0x94, 0x4d, 0x95, 0x4d, 0x96, 0x4d, 0x97, 0x4d, 0x98, + 0x68, 0xb8, 0x7a, 0x13, 0x91, 0x17, 0x7a, 0x03, 0x91, 0x17, 0x7a, 0x33, 0x91, 0x17, 0x7a, 0x23, + 0x91, 0x17, 0x7a, 0x53, 0x91, 0x17, 0x7a, 0x43, 0x91, 0x17, 0x7a, 0x73, 0x91, 0x17, 0x7a, 0x63, + 0x91, 0x17, 0x7a, 0x93, 0x91, 0x17, 0x7a, 0x83, 0x91, 0x17, 0x30, 0x73, 0x22, 0x7a, 0xb3, 0x91, + 0x17, 0x7a, 0xa3, 0x91, 0x17, 0x7a, 0xd3, 0x91, 0x17, 0x7a, 0xc3, 0x91, 0x17, 0x7a, 0xf3, 0x91, + 0x17, 0x7a, 0xe3, 0x91, 0x17, 0x7d, 0x78, 0x7a, 0xf3, 0x91, 0x17, 0x7a, 0xe3, 0x91, 0x17, 0x7e, + 0xb3, 0x91, 0x1e, 0x30, 0xe5, 0x03, 0x02, 0x65, 0x3c, 0x75, 0x2f, 0x29, 0x12, 0x73, 0x35, 0x20, + 0x73, 0x08, 0x75, 0x2f, 0x0a, 0x12, 0x73, 0x35, 0x80, 0x06, 0x75, 0x2f, 0x12, 0x12, 0x73, 0x35, + 0x74, 0x80, 0x7a, 0xb3, 0x91, 0x1e, 0x6d, 0x00, 0x7d, 0x10, 0x7a, 0x0d, 0x30, 0x7a, 0x0d, 0x34, + 0x7a, 0x0d, 0x38, 0x7a, 0x0d, 0x3c, 0x7a, 0x05, 0x40, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, + 0x7e, 0x37, 0x01, 0xc5, 0x4d, 0x33, 0x68, 0x3b, 0x7e, 0x07, 0x01, 0xc1, 0x7e, 0x54, 0x2c, 0x2d, + 0x9d, 0x50, 0xbd, 0x35, 0x40, 0x02, 0x7d, 0x35, 0xca, 0x39, 0x7e, 0x65, 0x4b, 0x99, 0x64, 0xda, + 0x39, 0x7e, 0x07, 0x01, 0xc5, 0x9d, 0x03, 0x7a, 0x07, 0x01, 0xc5, 0x2e, 0x37, 0x01, 0xc1, 0x7a, + 0x37, 0x01, 0xc1, 0xbe, 0x34, 0x2c, 0x2c, 0x28, 0xc7, 0x7e, 0x34, 0x28, 0x2d, 0x7a, 0x37, 0x01, + 0xc1, 0x80, 0xbd, 0x22, 0x75, 0x2f, 0x53, 0x12, 0x73, 0x35, 0x7e, 0x15, 0x4d, 0x80, 0x11, 0x75, + 0x2f, 0x51, 0x12, 0x73, 0x35, 0x0b, 0x08, 0x10, 0x0b, 0x05, 0x9e, 0x34, 0x00, 0x02, 0x28, 0x4d, + 0x7c, 0xb2, 0x20, 0xe7, 0x27, 0x54, 0x07, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x39, 0x1e, 0x7c, 0xb2, + 0x54, 0x78, 0x03, 0x03, 0x03, 0x7c, 0x2b, 0x9d, 0x13, 0x40, 0x1a, 0x68, 0x12, 0x7a, 0x15, 0x4d, + 0x7a, 0x25, 0x4f, 0x7e, 0x64, 0x67, 0x09, 0x7a, 0x65, 0x4b, 0x89, 0x24, 0x02, 0x67, 0x17, 0x7e, + 0x64, 0x66, 0x7f, 0x80, 0xf2, 0x2d, 0x13, 0x9d, 0x31, 0xca, 0x39, 0x7d, 0x31, 0x2d, 0x10, 0xca, + 0x19, 0xca, 0x29, 0x99, 0x24, 0xda, 0x29, 0xda, 0x09, 0xda, 0x39, 0x80, 0xa2, 0x7a, 0x15, 0x4d, + 0x7e, 0x64, 0x66, 0xf5, 0x4d, 0x33, 0x78, 0x09, 0x7c, 0xb2, 0x20, 0xe7, 0x2a, 0x7e, 0x64, 0x66, + 0x74, 0x7a, 0x65, 0x4b, 0x22, 0x75, 0x2f, 0x52, 0x12, 0x73, 0x35, 0x7e, 0x21, 0x4d, 0x7e, 0x09, + 0x30, 0x0b, 0x04, 0x1b, 0x34, 0x78, 0x89, 0x80, 0xd4, 0x75, 0x2f, 0x54, 0x12, 0x73, 0x35, 0x7e, + 0x15, 0x4d, 0x7e, 0x25, 0x4f, 0x80, 0x90, 0x5e, 0x20, 0x07, 0x54, 0x78, 0x7e, 0x44, 0x67, 0x7d, + 0x30, 0xe6, 0x16, 0x4d, 0x33, 0x68, 0x26, 0x1b, 0x34, 0x7e, 0x09, 0x40, 0x0b, 0x04, 0x7e, 0x44, + 0x34, 0xfa, 0x20, 0xe3, 0x04, 0x7e, 0x44, 0x67, 0x85, 0xca, 0x09, 0xca, 0x39, 0x99, 0x44, 0xda, + 0x39, 0xda, 0x09, 0x7e, 0x64, 0x66, 0x7f, 0x4d, 0x33, 0x68, 0xa6, 0x89, 0x64, 0x7a, 0x15, 0x4d, + 0xf5, 0x4f, 0x7e, 0x64, 0x67, 0x58, 0x80, 0x99, 0x7e, 0x15, 0x4d, 0xe5, 0x4f, 0x80, 0xc4, 0xc0, + 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xca, 0x19, 0x75, 0x2f, 0xfe, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x00, + 0x53, 0x02, 0x40, 0x52, 0xda, 0x19, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x03, 0xa5, 0xcb, + 0x19, 0xb1, 0x80, 0x00, 0x22, 0x22, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0x7e, 0xa0, 0x02, 0xa4, + 0x7e, 0x04, 0x68, 0xb1, 0x9d, 0x05, 0x7e, 0xb0, 0x28, 0x7a, 0xb3, 0x95, 0x00, 0x89, 0x04, 0xca, + 0x29, 0xb4, 0x80, 0xe2, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0x7e, 0x00, 0x28, 0x7a, 0x03, 0x95, + 0x00, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x95, 0x00, 0xda, 0x29, 0x22, 0x7e, 0x24, 0x00, 0x00, 0x7f, + 0xe1, 0x7e, 0xa0, 0x02, 0xa4, 0x7e, 0x04, 0x69, 0xe6, 0x9d, 0x05, 0x7e, 0xb0, 0x38, 0x7a, 0xb3, + 0x95, 0x00, 0x89, 0x04, 0xca, 0x29, 0xb4, 0x80, 0xe2, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0x7e, + 0x00, 0x38, 0x7a, 0x03, 0x95, 0x00, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x95, 0x00, 0xda, 0x29, 0x22, + 0xca, 0x29, 0xca, 0x19, 0xca, 0x58, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0xda, 0x58, 0x7e, 0x54, + 0x02, 0x20, 0x9c, 0xb5, 0xa4, 0x7e, 0x50, 0x30, 0x5e, 0x20, 0x07, 0x2c, 0x52, 0x7a, 0x53, 0x95, + 0x00, 0x2e, 0x54, 0x6a, 0x17, 0x89, 0x54, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, + 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x95, 0x00, 0xda, 0x19, + 0xda, 0x29, 0x22, 0xca, 0x19, 0xca, 0x58, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0xda, 0x58, 0x7e, + 0x54, 0x02, 0x38, 0x9c, 0xb5, 0xa4, 0x7e, 0x50, 0x20, 0x5e, 0x20, 0x07, 0x2c, 0x52, 0x7a, 0x53, + 0x95, 0x00, 0x2e, 0x54, 0x6a, 0x88, 0x89, 0x54, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, + 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x95, 0x00, 0xda, + 0x19, 0x22, 0x02, 0x6b, 0xa8, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xca, 0x3b, 0xca, 0x4b, 0xca, + 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x2c, + 0x7f, 0xb4, 0x00, 0x02, 0x80, 0x1c, 0xb4, 0x01, 0x19, 0x7e, 0xb3, 0x91, 0x14, 0x54, 0x14, 0x68, + 0x05, 0x12, 0x6b, 0x6c, 0x80, 0x23, 0x7e, 0xb3, 0x91, 0x14, 0x30, 0xe5, 0x1c, 0x12, 0x6c, 0xaa, + 0x80, 0x17, 0x7e, 0xb3, 0x91, 0x14, 0x30, 0xe5, 0x05, 0x12, 0x6c, 0xaa, 0x80, 0x0b, 0x7e, 0xb3, + 0x91, 0x14, 0x54, 0x14, 0x68, 0x03, 0x12, 0x6b, 0x6c, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, + 0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x20, 0xe4, 0x19, 0x75, + 0x2f, 0x0a, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x7e, 0x70, 0x0a, 0x7e, 0xb3, 0x2c, 0x7f, 0xb4, + 0x01, 0x1f, 0x02, 0x6c, 0x04, 0x02, 0x71, 0xf2, 0x75, 0x2f, 0x0b, 0x12, 0x73, 0x35, 0x74, 0x14, + 0x7a, 0xb3, 0x91, 0x14, 0x7e, 0xb3, 0x2c, 0x7f, 0xb4, 0x02, 0x0c, 0x12, 0x6b, 0xb4, 0x02, 0x6b, + 0xa8, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x2c, 0x7f, 0x7a, + 0x03, 0x2c, 0x80, 0x22, 0x7e, 0xb3, 0x2c, 0x76, 0x54, 0x60, 0x60, 0x05, 0xb4, 0x40, 0x1e, 0x80, + 0x1c, 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x05, 0x15, 0x75, 0x2f, 0x71, 0x12, 0x73, 0x35, 0x7e, 0xb3, + 0x2c, 0x79, 0x7e, 0xa0, 0x01, 0x7a, 0xa3, 0x91, 0x06, 0x7a, 0xb3, 0x91, 0x07, 0x22, 0x74, 0x00, + 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x12, 0x22, 0xbe, 0x57, 0x2c, 0x7c, 0x28, + 0x04, 0x7e, 0x57, 0x2c, 0x7c, 0x7a, 0x0f, 0x2c, 0x82, 0x7a, 0x57, 0x2c, 0x86, 0x74, 0x10, 0x7a, + 0xb3, 0x91, 0x12, 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x1a, 0x70, 0x53, + 0x7e, 0xb3, 0x91, 0x14, 0x20, 0xe4, 0x4c, 0x7e, 0xef, 0x2c, 0x82, 0x7e, 0xf7, 0x2c, 0x86, 0x7e, + 0x07, 0x2c, 0x86, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0xe0, 0x7a, 0xb3, 0x91, 0x17, 0xa3, + 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x06, 0xa5, 0xb8, 0x10, 0xf0, 0x80, 0x19, 0x7e, 0xb0, 0x00, 0x7a, + 0xb3, 0x2c, 0x7f, 0xbe, 0x00, 0x10, 0x68, 0x0d, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x2c, 0x7f, 0x74, + 0x80, 0x7a, 0xb3, 0x91, 0x1e, 0x7a, 0xef, 0x2c, 0x82, 0x7a, 0xf7, 0x2c, 0x86, 0x75, 0x2f, 0x06, + 0x12, 0x73, 0x35, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, + 0xca, 0x3b, 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0x75, 0x2f, 0x03, 0x12, + 0x73, 0x35, 0x74, 0x00, 0x7a, 0xb3, 0x2c, 0x7e, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x01, + 0x7a, 0xb3, 0x91, 0x12, 0x12, 0x6d, 0x19, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, 0x5b, 0xda, + 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x2f, 0x03, 0x12, 0x73, 0x35, + 0x7e, 0xb3, 0x2c, 0x80, 0xb4, 0x02, 0x11, 0x74, 0x00, 0x7a, 0xb3, 0x2c, 0x80, 0x7a, 0xb3, 0x2c, + 0x7f, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0xb4, 0x01, 0x46, 0x7e, 0xb3, 0x91, 0x04, 0x20, + 0xe6, 0x42, 0x7e, 0x23, 0x91, 0x1a, 0x7c, 0x32, 0x7e, 0x13, 0x2c, 0x81, 0x2c, 0x21, 0x7a, 0x23, + 0x2c, 0x81, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x2c, 0x88, 0x7e, 0xb3, 0x91, 0x16, 0x7a, 0x09, 0xb0, + 0x0b, 0x04, 0xa5, 0xdb, 0xf4, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x75, 0x2f, 0x70, 0x12, 0x73, + 0x35, 0x7e, 0xb3, 0x2c, 0x81, 0x7e, 0xa3, 0x2c, 0x7d, 0xbc, 0xab, 0x78, 0x03, 0x12, 0x6d, 0xb9, + 0x22, 0x02, 0x71, 0xf2, 0xda, 0x59, 0x02, 0x6c, 0x7c, 0x74, 0xe0, 0x7a, 0xb3, 0x91, 0x00, 0x7e, + 0x03, 0x91, 0x10, 0x7e, 0x13, 0x91, 0x11, 0x7e, 0x33, 0x91, 0x12, 0x7e, 0x23, 0x91, 0x13, 0x7e, + 0x53, 0x91, 0x14, 0x7e, 0x43, 0x91, 0x15, 0x7e, 0x73, 0x91, 0x16, 0x7e, 0x63, 0x91, 0x17, 0x7a, + 0x0f, 0x2c, 0x76, 0x7a, 0x1f, 0x2c, 0x7a, 0x75, 0x2f, 0x04, 0x12, 0x73, 0x35, 0x7a, 0x01, 0x2f, + 0x12, 0x73, 0x35, 0x7a, 0x11, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x21, 0x2f, 0x12, 0x73, 0x35, 0x7a, + 0x31, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x41, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, + 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x74, 0x00, 0x7a, + 0xb3, 0x91, 0x00, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x04, 0x12, 0x6d, 0x8d, 0x22, 0x6d, 0x00, 0x7e, + 0x14, 0x01, 0x02, 0x7a, 0x07, 0x2c, 0x86, 0x7a, 0x03, 0x2c, 0x81, 0x7e, 0xb3, 0x2c, 0x76, 0x20, + 0xe7, 0x0f, 0x7a, 0x23, 0x2c, 0x80, 0x7a, 0x33, 0x2c, 0x7f, 0xbe, 0x07, 0x2c, 0x7c, 0x68, 0x09, + 0x22, 0x7a, 0x33, 0x2c, 0x80, 0x7a, 0x23, 0x2c, 0x7f, 0x7e, 0xb3, 0x2c, 0x76, 0x54, 0xe3, 0x23, + 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 0x06, 0x30, 0xe4, + 0x03, 0x02, 0x71, 0xf2, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 0xf0, 0x90, 0x6d, + 0xe5, 0x75, 0x84, 0xff, 0x73, 0x02, 0x6f, 0xa0, 0x02, 0x6e, 0x2d, 0x02, 0x70, 0x39, 0x02, 0x70, + 0x54, 0x02, 0x6f, 0x37, 0x02, 0x6e, 0xc2, 0x02, 0x70, 0x85, 0x02, 0x70, 0x85, 0x02, 0x70, 0x88, + 0x02, 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, + 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 0x70, 0x8e, 0x02, 0x71, 0x60, 0x02, 0x70, 0x8b, 0x02, 0x70, + 0x8b, 0x02, 0x70, 0x8b, 0x02, 0x70, 0x8b, 0x02, 0x70, 0x8b, 0x02, 0x70, 0x8b, 0x74, 0x00, 0x7a, + 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x06, 0x2a, + 0x7e, 0xb3, 0x2c, 0x78, 0x60, 0x79, 0x7c, 0x0b, 0x7e, 0x13, 0x2c, 0x79, 0x7e, 0x17, 0x2c, 0x7a, + 0x75, 0x2f, 0x72, 0x12, 0x73, 0x35, 0x7a, 0x01, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x11, 0x2f, 0x12, + 0x73, 0x35, 0x12, 0x72, 0x37, 0x40, 0x58, 0x02, 0x6b, 0xeb, 0xb4, 0x08, 0x1c, 0x75, 0x2f, 0x74, + 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x3f, 0xf1, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0x7a, + 0x0b, 0xb0, 0x7e, 0x54, 0x00, 0x01, 0x02, 0x6b, 0xeb, 0xb4, 0x00, 0x33, 0x75, 0x2f, 0x75, 0x12, + 0x73, 0x35, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0x7e, 0xb3, 0x3f, 0xf2, + 0x30, 0xe0, 0x07, 0x74, 0x02, 0x7a, 0x0b, 0xb0, 0x80, 0x05, 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x0b, + 0x14, 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x7e, 0x54, 0x00, 0x02, 0xda, 0x0b, 0x02, 0x6b, 0xeb, 0x02, + 0x71, 0xf2, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 0xb3, + 0x2c, 0x77, 0xb4, 0x00, 0x5f, 0x75, 0x2f, 0x76, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x7b, 0x54, + 0x0f, 0xb4, 0x02, 0x05, 0x7e, 0xb0, 0x60, 0x80, 0x17, 0xb4, 0x00, 0x05, 0x7e, 0xb0, 0x00, 0x80, + 0x0f, 0x7e, 0xb3, 0x2c, 0x7b, 0x20, 0xe7, 0x05, 0x7e, 0xb0, 0x40, 0x80, 0x03, 0x7e, 0xb0, 0x20, + 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x11, 0x30, 0xe0, 0x04, 0x74, 0x01, 0x80, 0x02, 0x74, + 0x00, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0x7a, 0x0b, 0xb0, 0x0b, 0x14, + 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0x54, 0x00, 0x02, 0xda, + 0x0b, 0x02, 0x6b, 0xeb, 0x02, 0x71, 0xf2, 0x7e, 0xb3, 0x2c, 0x7b, 0x54, 0x0f, 0xb4, 0x02, 0x05, + 0x7e, 0xb0, 0x60, 0x80, 0x17, 0xb4, 0x00, 0x05, 0x7e, 0xb0, 0x00, 0x80, 0x0f, 0x7e, 0xb3, 0x2c, + 0x7b, 0x20, 0xe7, 0x05, 0x7e, 0xb0, 0x40, 0x80, 0x03, 0x7e, 0xb0, 0x20, 0x7a, 0xb3, 0x91, 0x00, + 0x7e, 0xb3, 0x2c, 0x79, 0xb4, 0x00, 0x26, 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x01, 0x0e, 0x75, 0x2f, + 0x77, 0x12, 0x73, 0x35, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x80, 0x1b, 0xb4, 0x03, 0x0e, 0x75, + 0x2f, 0x78, 0x12, 0x73, 0x35, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x11, 0x80, 0x0a, 0x74, 0x00, 0x7a, + 0xb3, 0x91, 0x00, 0x12, 0x71, 0xf2, 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x02, 0x6b, 0xde, + 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x09, 0x1f, 0x75, 0x2f, 0x79, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, + 0x79, 0xbe, 0xb3, 0x3f, 0xf1, 0x68, 0x0d, 0xca, 0xb8, 0x12, 0x43, 0x79, 0xda, 0xb8, 0x50, 0x76, + 0x7a, 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x2f, 0x7a, 0x12, 0x73, 0x35, 0x80, + 0x62, 0xb4, 0x03, 0x19, 0x75, 0x2f, 0x7b, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x79, 0xb4, 0x01, + 0x55, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 0xb4, 0x01, 0x19, + 0x75, 0x2f, 0x7c, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x79, 0xb4, 0x01, 0x39, 0x7e, 0xb3, 0x3f, + 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 0xb3, 0x2c, 0x78, + 0x60, 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x2c, 0x79, 0x7e, 0x17, 0x2c, 0x7a, 0x75, 0x2f, 0x73, 0x12, + 0x73, 0x35, 0x7a, 0x01, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x11, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x72, + 0x71, 0x40, 0x03, 0x02, 0x6b, 0xde, 0x02, 0x71, 0xf2, 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x0b, 0xf6, + 0x75, 0x2f, 0x7d, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x79, 0x7e, 0xa3, 0x2c, 0x7b, 0x4c, 0xab, + 0x78, 0xe4, 0x80, 0xdf, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, + 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x0a, 0xcf, 0x75, 0x2f, 0x7e, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, + 0x79, 0x70, 0xc3, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0x7a, 0x0b, 0xb0, 0x7e, 0x54, + 0x00, 0x01, 0x02, 0x6b, 0xeb, 0x02, 0x71, 0xf2, 0x02, 0x71, 0xf2, 0x02, 0x71, 0xf2, 0x7e, 0xb3, + 0x2c, 0x77, 0xb4, 0x04, 0x20, 0x75, 0x2f, 0xc3, 0x12, 0x73, 0x35, 0x7e, 0x04, 0x00, 0x01, 0x7e, + 0x17, 0x2c, 0x78, 0x7e, 0x18, 0x2c, 0x88, 0x7a, 0x1c, 0x00, 0x00, 0x7e, 0x47, 0x2c, 0x7c, 0x12, + 0x73, 0x41, 0x02, 0x71, 0x5a, 0xb4, 0x06, 0x42, 0x75, 0x2f, 0xc1, 0x12, 0x73, 0x35, 0x7e, 0x58, + 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, 0xd7, 0x2c, 0x78, 0x7e, 0x78, 0x2c, 0x88, + 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2c, 0x7c, 0x75, 0x2f, 0xc1, 0x12, 0x73, 0x35, 0xc0, 0xa8, + 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 0x73, 0x7a, 0x7e, 0x43, 0x2c, 0x35, + 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0x40, 0x65, 0x80, 0x60, 0xb4, 0x00, 0x24, 0xc2, 0xaf, 0x7e, + 0xb0, 0x01, 0x7a, 0xb3, 0x94, 0x00, 0x7a, 0xb3, 0x2c, 0x35, 0x12, 0x6b, 0xde, 0xe4, 0x8d, 0xef, + 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 0xca, 0x02, 0xff, 0xca, 0x06, 0x00, 0x00, + 0x32, 0xb4, 0x09, 0x20, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0x23, 0x91, 0x07, 0x7e, 0x57, + 0x2c, 0x78, 0x4d, 0x55, 0x68, 0x05, 0x4e, 0x20, 0x02, 0x80, 0x03, 0x5e, 0x20, 0xfd, 0x7a, 0x23, + 0x91, 0x07, 0x80, 0x16, 0xb4, 0x07, 0x16, 0xc2, 0xaf, 0x7e, 0x07, 0x2c, 0x7a, 0x7e, 0x17, 0x2c, + 0x78, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, 0xca, 0x28, 0x32, 0x02, 0x6b, 0xde, 0x02, 0x71, 0xf2, + 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 0xb3, 0x2c, 0x77, + 0xb4, 0x03, 0x15, 0x75, 0x2f, 0xc2, 0x12, 0x73, 0x35, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2c, + 0x78, 0x7e, 0x57, 0x2c, 0x7c, 0x02, 0x6b, 0xeb, 0xb4, 0x05, 0x41, 0x75, 0x2f, 0xc0, 0x12, 0x73, + 0x35, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x7e, 0x08, 0x2c, 0x88, + 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x2c, 0x78, 0x7e, 0x47, 0x2c, 0x7c, + 0x12, 0x73, 0x41, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0x7e, 0x08, 0x2c, + 0x88, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x2c, 0x7c, 0x02, 0x6b, 0xeb, 0xb4, 0x01, 0x20, 0x7e, + 0x00, 0x00, 0x7e, 0x10, 0x01, 0x75, 0x2f, 0x72, 0x12, 0x73, 0x35, 0x7a, 0x01, 0x2f, 0x12, 0x73, + 0x35, 0x7a, 0x11, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x72, 0x37, 0x40, 0x03, 0x02, 0x6b, 0xeb, 0x02, + 0x71, 0xf2, 0x75, 0x2f, 0x07, 0x12, 0x73, 0x35, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x74, + 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x15, 0x74, 0x01, 0x7a, 0xb3, 0x91, + 0x11, 0x7e, 0xb3, 0x91, 0x15, 0x54, 0x60, 0xbe, 0xb0, 0x40, 0x68, 0x08, 0x74, 0x20, 0x7a, 0xb3, + 0x91, 0x15, 0x80, 0xed, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, + 0x74, 0xff, 0x7a, 0xb3, 0x2c, 0x7e, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, + 0x94, 0x00, 0x12, 0x72, 0xbe, 0x40, 0x1f, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0xca, + 0x0b, 0xca, 0x49, 0x12, 0x73, 0x41, 0xda, 0x59, 0xda, 0x0b, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, + 0x94, 0x00, 0xd0, 0xa8, 0xc3, 0x22, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, + 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 0x72, 0xbe, 0x40, + 0x31, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7f, 0x61, 0x7e, 0x78, 0x2c, 0x88, 0x7a, + 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2c, 0x7c, 0xbd, 0x74, 0x78, 0x17, 0x75, 0x2f, 0xc1, 0x12, 0x73, + 0x35, 0x12, 0x73, 0x7a, 0x40, 0x0c, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, + 0xc3, 0x22, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, + 0x00, 0xfe, 0x7e, 0x34, 0x7f, 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, + 0x87, 0x7e, 0x34, 0x7f, 0xc2, 0x7e, 0x1b, 0xb0, 0x7e, 0x34, 0x7f, 0x03, 0xb4, 0x01, 0x04, 0x7e, + 0x34, 0x7f, 0xcc, 0x7e, 0x1b, 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, + 0x2d, 0x75, 0x0b, 0x3a, 0x30, 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, + 0x1b, 0x50, 0x30, 0x3e, 0x10, 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, + 0x1a, 0x30, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, + 0x90, 0x0a, 0x49, 0x4d, 0x44, 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, + 0xff, 0xc3, 0x22, 0xd3, 0x22, + +// Segment #16, Start Address 00ff7fc6, Length 4 +0xff,0x00,0xc6,0x7f,0x04,0x00, + 0x02, 0x00, 0x03, 0x00, + +// Segment #17, Start Address 00ff7335, Length 328 +0xff,0x00,0x35,0x73,0x48,0x01, + 0xca, 0x08, 0x7e, 0x01, 0x2f, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x7e, 0x1b, 0xc0, 0x7a, + 0x0b, 0xc0, 0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, + 0xfc, 0x7c, 0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, + 0x44, 0x00, 0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, + 0xfa, 0x7f, 0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, + 0x40, 0x9d, 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x73, 0xa4, + 0xda, 0x79, 0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x7e, + 0xc0, 0x03, 0x7e, 0xd0, 0x00, 0x7a, 0xd3, 0x90, 0x00, 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, + 0x55, 0x39, 0xb5, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb5, 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, + 0x70, 0x50, 0x06, 0x2d, 0x70, 0x7d, 0x07, 0x6d, 0x77, 0x7c, 0x31, 0x7e, 0x7b, 0x00, 0x7a, 0x6b, + 0x00, 0x0b, 0x7c, 0x0b, 0x6c, 0xa5, 0xd9, 0xf3, 0x7f, 0x16, 0x1b, 0x1c, 0x7e, 0x54, 0x27, 0x10, + 0x7e, 0x1b, 0x10, 0xbc, 0x10, 0x68, 0x06, 0x1b, 0x54, 0x78, 0xf5, 0x80, 0x2f, 0x6d, 0x00, 0x7c, + 0x20, 0x7f, 0x16, 0x9f, 0x10, 0x7f, 0x27, 0x9f, 0x20, 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, + 0x01, 0x78, 0x19, 0x0b, 0x2c, 0x0b, 0x1c, 0xa5, 0xdb, 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x06, 0x6c, + 0xdc, 0x7a, 0xd3, 0x90, 0x00, 0x4d, 0x77, 0x78, 0x90, 0xc2, 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x08, 0x10, + 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, 0x18, 0x7f, 0xbd, 0x7a, 0x1c, 0x00, + 0xfe, 0x0b, 0x1a, 0x00, 0x5e, 0x10, 0x1f, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, 0x51, 0x23, 0x7e, + 0x18, 0x74, 0x24, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 0x08, 0xa5, 0xb8, + 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, +}; + +static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = { + 2, 0, 3 }; // Major, Minor, Build + +#undef IMAGE_VERSION_NAME + +#undef IMAGE_ARRAY_NAME + diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_ionsp.h linux/drivers/usb/serial/io_ionsp.h --- v2.4.2/linux/drivers/usb/serial/io_ionsp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_ionsp.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,454 @@ +/************************************************************************ + * + * IONSP.H Definitions for I/O Networks Serial Protocol + * + * Copyright (c) 1997-1998 Inside Out Networks, 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. + * + * These definitions are used by both kernel-mode driver and the + * peripheral firmware and MUST be kept in sync. + * + ************************************************************************/ + +/************************************************************************ + +The data to and from all ports on the peripheral is multiplexed +through a single endpoint pair (EP1 since it supports 64-byte +MaxPacketSize). Therefore, the data, commands, and status for +each port must be preceeded by a short header identifying the +destination port. The header also identifies the bytes that follow +as data or as command/status info. + +Header format, first byte: + + CLLLLPPP + -------- + | | |------ Port Number: 0-7 + | |--------- Length: MSB bits of length + |----------- Data/Command: 0 = Data header + 1 = Cmd / Status (Cmd if OUT, Status if IN) + +This gives 2 possible formats: + + + Data header: 0LLLLPPP LLLLLLLL + ============ + + Where (LLLL,LLLLLLL) is 12-bit length of data that follows for + port number (PPP). The length is 0-based (0-FFF means 0-4095 + bytes). The ~4K limit allows the host driver (which deals in + transfer requests instead of individual packets) to write a + large chunk of data in a single request. Note, however, that + the length must always be <= the current TxCredits for a given + port due to buffering limitations on the peripheral. + + + Cmd/Status header: 1ccccPPP [ CCCCCCCC, Params ]... + ================== + + Where (cccc) or (cccc,CCCCCCCC) is the cmd or status identifier. + Frequently-used values are encoded as (cccc), longer ones using + (cccc,CCCCCCCC). Subsequent bytes are optional parameters and are + specific to the cmd or status code. This may include a length + for command and status codes that need variable-length parameters. + + +In addition, we use another interrupt pipe (endpoint) which the host polls +periodically for flow control information. The peripheral, when there has +been a change, sends the following 10-byte packet: + + RRRRRRRRRRRRRRRR + T0T0T0T0T0T0T0T0 + T1T1T1T1T1T1T1T1 + T2T2T2T2T2T2T2T2 + T3T3T3T3T3T3T3T3 + +The first field is the 16-bit RxBytesAvail field, which indicates the +number of bytes which may be read by the host from EP1. This is necessary: +(a) because OSR2.1 has a bug which causes data loss if the peripheral returns +fewer bytes than the host expects to read, and (b) because, on Microsoft +platforms at least, an outstanding read posted on EP1 consumes about 35% of +the CPU just polling the device for data. + +The next 4 fields are the 16-bit TxCredits for each port, which indicate how +many bytes the host is allowed to send on EP1 for transmit to a given port. +After an OPEN_PORT command, the Edgeport sends the initial TxCredits for that +port. + +All 16-bit fields are sent in little-endian (Intel) format. + +************************************************************************/ + +// +// Define format of InterruptStatus packet returned from the +// Interrupt pipe +// + +typedef struct _INT_STATUS_PKT { + __u16 RxBytesAvail; // Additional bytes available to + // be read from Bulk IN pipe + __u16 TxCredits[ MAX_RS232_PORTS ]; // Additional space available in + // given port's TxBuffer +} INT_STATUS_PKT, *PINT_STATUS_PKT; + + +#define GET_INT_STATUS_SIZE(NumPorts) (sizeof(__u16) + (sizeof(__u16) * (NumPorts))) + + + +// +// Define cmd/status header values and macros to extract them. +// +// Data: 0LLLLPPP LLLLLLLL +// Cmd/Stat: 1ccccPPP CCCCCCCC + +#define IOSP_DATA_HDR_SIZE 2 +#define IOSP_CMD_HDR_SIZE 2 + +#define IOSP_MAX_DATA_LENGTH 0x0FFF // 12 bits -> 4K + +#define IOSP_PORT_MASK 0x07 // Mask to isolate port number +#define IOSP_CMD_STAT_BIT 0x80 // If set, this is command/status header + +#define IS_CMD_STAT_HDR(Byte1) ((Byte1) & IOSP_CMD_STAT_BIT) +#define IS_DATA_HDR(Byte1) (! IS_CMD_STAT_HDR(Byte1)) + +#define IOSP_GET_HDR_PORT(Byte1) ((__u8) ((Byte1) & IOSP_PORT_MASK)) +#define IOSP_GET_HDR_DATA_LEN(Byte1, Byte2) ((__u16) ( ((__u16)((Byte1) & 0x78)) << 5) | (Byte2)) +#define IOSP_GET_STATUS_CODE(Byte1) ((__u8) (((Byte1) & 0x78) >> 3)) + + +// +// These macros build the 1st and 2nd bytes for a data header +// +#define IOSP_BUILD_DATA_HDR1(Port, Len) ((__u8) (((Port) | ((__u8) (((__u16) (Len)) >> 5) & 0x78 )))) +#define IOSP_BUILD_DATA_HDR2(Port, Len) ((__u8) (Len)) + + +// +// These macros build the 1st and 2nd bytes for a command header +// +#define IOSP_BUILD_CMD_HDR1(Port, Cmd) ((__u8) ( IOSP_CMD_STAT_BIT | (Port) | ((__u8) ((Cmd) << 3)) )) + + +//-------------------------------------------------------------- +// +// Define values for commands and command parameters +// (sent from Host to Edgeport) +// +// 1ccccPPP P1P1P1P1 [ P2P2P2P2P2 ]... +// +// cccc: 00-07 2-byte commands. Write UART register 0-7 with +// value in P1. See 16650.H for definitions of +// UART register numbers and contents. +// +// 08-0B 3-byte commands: ==== P1 ==== ==== P2 ==== +// 08 available for expansion +// 09 1-param commands Command Code Param +// 0A available for expansion +// 0B available for expansion +// +// 0C-0D 4-byte commands. P1 = extended cmd and P2,P3 = params +// Currently unimplemented. +// +// 0E-0F N-byte commands: P1 = num bytes after P1 (ie, TotalLen - 2) +// P2 = extended cmd, P3..Pn = parameters. +// Currently unimplemented. +// + +#define IOSP_WRITE_UART_REG(n) ((n) & 0x07) // UartReg[ n ] := P1 + +// Register numbers and contents +// defined in 16554.H. + +// 0x08 // Available for expansion. +#define IOSP_EXT_CMD 0x09 // P1 = Command code (defined below) + +// P2 = Parameter + +// +// Extended Command values, used with IOSP_EXT_CMD, may +// or may not use parameter P2. +// + +#define IOSP_CMD_OPEN_PORT 0x00 // Enable ints, init UART. (NO PARAM) +#define IOSP_CMD_CLOSE_PORT 0x01 // Disable ints, flush buffers. (NO PARAM) +#define IOSP_CMD_CHASE_PORT 0x02 // Wait for Edgeport TX buffers to empty. (NO PARAM) +#define IOSP_CMD_SET_RX_FLOW 0x03 // Set Rx Flow Control in Edgeport +#define IOSP_CMD_SET_TX_FLOW 0x04 // Set Tx Flow Control in Edgeport +#define IOSP_CMD_SET_XON_CHAR 0x05 // Set XON Character in Edgeport +#define IOSP_CMD_SET_XOFF_CHAR 0x06 // Set XOFF Character in Edgeport +#define IOSP_CMD_RX_CHECK_REQ 0x07 // Request Edgeport to insert a Checkpoint into + +// the receive data stream (Parameter = 1 byte sequence number) + +#define IOSP_CMD_SET_BREAK 0x08 // Turn on the BREAK (LCR bit 6) +#define IOSP_CMD_CLEAR_BREAK 0x09 // Turn off the BREAK (LCR bit 6) + + +// +// Define macros to simplify building of IOSP cmds +// + +#define MAKE_CMD_WRITE_REG(ppBuf, pLen, Port, Reg, Val) \ + do { \ + (*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1( (Port), IOSP_WRITE_UART_REG(Reg) ); \ + (*(ppBuf))[1] = (Val); \ + \ + *ppBuf += 2; \ + *pLen += 2; \ + } while (0) + +#define MAKE_CMD_EXT_CMD(ppBuf, pLen, Port, ExtCmd, Param) \ + do { \ + (*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1( (Port), IOSP_EXT_CMD ); \ + (*(ppBuf))[1] = (ExtCmd); \ + (*(ppBuf))[2] = (Param); \ + \ + *ppBuf += 3; \ + *pLen += 3; \ + } while (0) + + + +//-------------------------------------------------------------- +// +// Define format of flow control commands +// (sent from Host to Edgeport) +// +// 11001PPP FlowCmd FlowTypes +// +// Note that the 'FlowTypes' parameter is a bit mask; that is, +// more than one flow control type can be active at the same time. +// FlowTypes = 0 means 'no flow control'. +// + +// +// IOSP_CMD_SET_RX_FLOW +// +// Tells Edgeport how it can stop incoming UART data +// +// Example for Port 0 +// P0 = 11001000 +// P1 = IOSP_CMD_SET_RX_FLOW +// P2 = Bit mask as follows: + +#define IOSP_RX_FLOW_RTS 0x01 // Edgeport drops RTS to stop incoming data +#define IOSP_RX_FLOW_DTR 0x02 // Edgeport drops DTR to stop incoming data +#define IOSP_RX_FLOW_DSR_SENSITIVITY 0x04 // Ignores Rx data unless DSR high + +// Not currently implemented by firmware. +#define IOSP_RX_FLOW_XON_XOFF 0x08 // Edgeport sends XOFF char to stop incoming data. + +// Host must have previously programmed the +// XON/XOFF values with SET_XON/SET_XOFF +// before enabling this bit. + +// +// IOSP_CMD_SET_TX_FLOW +// +// Tells Edgeport what signal(s) will stop it from transmitting UART data +// +// Example for Port 0 +// P0 = 11001000 +// P1 = IOSP_CMD_SET_TX_FLOW +// P2 = Bit mask as follows: + +#define IOSP_TX_FLOW_CTS 0x01 // Edgeport stops Tx if CTS low +#define IOSP_TX_FLOW_DSR 0x02 // Edgeport stops Tx if DSR low +#define IOSP_TX_FLOW_DCD 0x04 // Edgeport stops Tx if DCD low +#define IOSP_TX_FLOW_XON_XOFF 0x08 // Edgeport stops Tx upon receiving XOFF char. + +// Host must have previously programmed the +// XON/XOFF values with SET_XON/SET_XOFF +// before enabling this bit. +#define IOSP_TX_FLOW_XOFF_CONTINUE 0x10 // If not set, Edgeport stops Tx when + +// sending XOFF in order to fix broken +// systems that interpret the next +// received char as XON. +// If set, Edgeport continues Tx +// normally after transmitting XOFF. +// Not currently implemented by firmware. +#define IOSP_TX_TOGGLE_RTS 0x20 // Edgeport drives RTS as a true half-duplex + +// Request-to-Send signal: it is raised before +// beginning transmission and lowered after +// the last Tx char leaves the UART. +// Not currently implemented by firmware. + +// +// IOSP_CMD_SET_XON_CHAR +// +// Sets the character which Edgeport transmits/interprets as XON. +// Note: This command MUST be sent before sending a SET_RX_FLOW or +// SET_TX_FLOW with the XON_XOFF bit set. +// +// Example for Port 0 +// P0 = 11001000 +// P1 = IOSP_CMD_SET_XON_CHAR +// P2 = 0x11 + + +// +// IOSP_CMD_SET_XOFF_CHAR +// +// Sets the character which Edgeport transmits/interprets as XOFF. +// Note: This command must be sent before sending a SET_RX_FLOW or +// SET_TX_FLOW with the XON_XOFF bit set. +// +// Example for Port 0 +// P0 = 11001000 +// P1 = IOSP_CMD_SET_XOFF_CHAR +// P2 = 0x13 + + +// +// IOSP_CMD_RX_CHECK_REQ +// +// This command is used to assist in the implementation of the +// IOCTL_SERIAL_PURGE Windows IOCTL. +// This IOSP command tries to place a marker at the end of the RX +// queue in the Edgeport. If the Edgeport RX queue is full then +// the Check will be discarded. +// It is up to the device driver to timeout waiting for the +// RX_CHECK_RSP. If a RX_CHECK_RSP is received, the driver is +// sure that all data has been received from the edgeport and +// may now purge any internal RX buffers. +// Note tat the sequence numbers may be used to detect lost +// CHECK_REQs. + +// Example for Port 0 +// P0 = 11001000 +// P1 = IOSP_CMD_RX_CHECK_REQ +// P2 = Sequence number + + +// Response will be: +// P1 = IOSP_EXT_RX_CHECK_RSP +// P2 = Request Sequence number + + + +//-------------------------------------------------------------- +// +// Define values for status and status parameters +// (received by Host from Edgeport) +// +// 1ssssPPP P1P1P1P1 [ P2P2P2P2P2 ]... +// +// ssss: 00-07 2-byte status. ssss identifies which UART register +// has changed value, and the new value is in P1. +// Note that the ssss values do not correspond to the +// 16554 register numbers given in 16554.H. Instead, +// see below for definitions of the ssss numbers +// used in this status message. +// +// 08-0B 3-byte status: ==== P1 ==== ==== P2 ==== +// 08 LSR_DATA: New LSR Errored byte +// 09 1-param responses Response Code Param +// 0A OPEN_RSP: InitialMsr TxBufferSize +// 0B available for expansion +// +// 0C-0D 4-byte status. P1 = extended status code and P2,P3 = params +// Not currently implemented. +// +// 0E-0F N-byte status: P1 = num bytes after P1 (ie, TotalLen - 2) +// P2 = extended status, P3..Pn = parameters. +// Not currently implemented. +// + +/**************************************************** + * SSSS values for 2-byte status messages (0-8) + ****************************************************/ + +#define IOSP_STATUS_LSR 0x00 // P1 is new value of LSR register. + +// Bits defined in 16554.H. Edgeport +// returns this in order to report +// line status errors (overrun, +// parity, framing, break). This form +// is used when a errored receive data +// character was NOT present in the +// UART when the LSR error occurred +// (ie, when LSR bit 0 = 0). + +#define IOSP_STATUS_MSR 0x01 // P1 is new value of MSR register. + +// Bits defined in 16554.H. Edgeport +// returns this in order to report +// changes in modem status lines +// (CTS, DSR, RI, CD) +// + +// 0x02 // Available for future expansion +// 0x03 // +// 0x04 // +// 0x05 // +// 0x06 // +// 0x07 // + + +/**************************************************** + * SSSS values for 3-byte status messages (8-A) + ****************************************************/ + +#define IOSP_STATUS_LSR_DATA 0x08 // P1 is new value of LSR register (same as STATUS_LSR) + +// P2 is errored character read from +// RxFIFO after LSR reported an error. + +#define IOSP_EXT_STATUS 0x09 // P1 is status/response code, param in P2. + + +// Response Codes (P1 values) for 3-byte status messages + +#define IOSP_EXT_STATUS_CHASE_RSP 0 // Reply to CHASE_PORT cmd. P2 is outcome: +#define IOSP_EXT_STATUS_CHASE_PASS 0 // P2 = 0: All Tx data drained successfully +#define IOSP_EXT_STATUS_CHASE_FAIL 1 // P2 = 1: Timed out (stuck due to flow + +// control from remote device). + +#define IOSP_EXT_STATUS_RX_CHECK_RSP 1 // Reply to RX_CHECK cmd. P2 is sequence number + + +#define IOSP_STATUS_OPEN_RSP 0x0A // Reply to OPEN_PORT cmd. + +// P1 is Initial MSR value +// P2 is encoded TxBuffer Size: +// TxBufferSize = (P2 + 1) * 64 + +// 0x0B // Available for future expansion + +#define GET_TX_BUFFER_SIZE(P2) (((P2) + 1) * 64) + + + + +/**************************************************** + * SSSS values for 4-byte status messages + ****************************************************/ + +#define IOSP_EXT4_STATUS 0x0C // Extended status code in P1, + +// Params in P2, P3 +// Currently unimplemented. + +// 0x0D // Currently unused, available. + + + +// +// Macros to parse status messages +// + +#define IOSP_GET_STATUS_LEN(code) ( (code) < 8 ? 2 : ((code) < 0x0A ? 3 : 4) ) + +#define IOSP_STATUS_IS_2BYTE(code) ( (code) < 0x08 ) +#define IOSP_STATUS_IS_3BYTE(code) ( ((code) >= 0x08) && ((code) <= 0x0B) ) +#define IOSP_STATUS_IS_4BYTE(code) ( ((code) >= 0x0C) && ((code) <= 0x0D) ) + diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_tables.h linux/drivers/usb/serial/io_tables.h --- v2.4.2/linux/drivers/usb/serial/io_tables.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_tables.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,444 @@ +/* + * IO Edgeport Driver tables + * + * Copyright (C) 2001 + * Greg Kroah-Hartman (greg@kroah.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. + * + */ + +static __devinitdata struct usb_device_id edgeport_4_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4)}, {} }; +static __devinitdata struct usb_device_id rapidport_4_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, {} }; +static __devinitdata struct usb_device_id edgeport_4t_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, {} }; +static __devinitdata struct usb_device_id edgeport_2_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, {} }; +static __devinitdata struct usb_device_id edgeport_4i_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, {} }; +static __devinitdata struct usb_device_id edgeport_2i_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, {} }; +static __devinitdata struct usb_device_id edgeport_prl_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) }, {} }; +static __devinitdata struct usb_device_id edgeport_421_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, {} }; +static __devinitdata struct usb_device_id edgeport_21_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, {} }; +static __devinitdata struct usb_device_id edgeport_8dual_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, {} }; +static __devinitdata struct usb_device_id edgeport_8_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, {} }; +static __devinitdata struct usb_device_id edgeport_2din_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, {} }; +static __devinitdata struct usb_device_id edgeport_4din_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, {} }; +static __devinitdata struct usb_device_id edgeport_16dual_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, {} }; +static __devinitdata struct usb_device_id edgeport_compat_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, {} }; +static __devinitdata struct usb_device_id edgeport_8i_id_table [] = {{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, {} }; + + +/* Devices that this driver supports */ +static __devinitdata struct usb_device_id id_table_combined [] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, id_table_combined); + + +/* build up the list of devices that this driver supports */ +struct usb_serial_device_type edgeport_4_device = { + name: "Edgeport 4", + id_table: edgeport_4_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 4, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type rapidport_4_device = { + name: "Rapidport 4", + id_table: rapidport_4_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 4, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_4t_device = { + name: "Edgeport 4t", + id_table: edgeport_4t_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 4, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_2_device = { + name: "Edgeport 2", + id_table: edgeport_2_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 2, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_4i_device = { + name: "Edgeport 4i", + id_table: edgeport_4i_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 4, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_2i_device = { + name: "Edgeport 2i", + id_table: edgeport_2i_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 2, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_prl_device = { + name: "Edgeport Parallel", + id_table: edgeport_prl_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_421_device = { + name: "Edgeport 421", + id_table: edgeport_421_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 2, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_21_device = { + name: "Edgeport 21", + id_table: edgeport_21_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 2, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_8dual_device = { + name: "Edgeport 8 dual cpu", + id_table: edgeport_8dual_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 4, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_8_device = { + name: "Edgeport 8", + id_table: edgeport_8_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 8, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_2din_device = { + name: "Edgeport 2din", + id_table: edgeport_2din_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 2, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_4din_device = { + name: "Edgeport 4din", + id_table: edgeport_4din_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 4, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_16dual_device = { + name: "Edgeport 16 dual cpu", + id_table: edgeport_16dual_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 8, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + +struct usb_serial_device_type edgeport_compat_id_device = { + name: "Edgeport Compatible", + id_table: edgeport_compat_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 4, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + + +struct usb_serial_device_type edgeport_8i_device = { + name: "Edgeport 8i", + id_table: edgeport_8i_id_table, + needs_interrupt_in: MUST_HAVE, + needs_bulk_in: MUST_HAVE, + needs_bulk_out: MUST_HAVE, + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 8, + open: edge_open, + close: edge_close, + throttle: edge_throttle, + unthrottle: edge_unthrottle, + startup: edge_startup, + shutdown: edge_shutdown, + ioctl: edge_ioctl, + set_termios: edge_set_termios, + write: edge_write, + write_room: edge_write_room, + chars_in_buffer: edge_chars_in_buffer, + break_ctl: edge_break, +}; + + + + diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_usbvend.h linux/drivers/usb/serial/io_usbvend.h --- v2.4.2/linux/drivers/usb/serial/io_usbvend.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/serial/io_usbvend.h Mon Mar 19 17:21:54 2001 @@ -0,0 +1,374 @@ +/************************************************************************ + * + * USBVEND.H Vendor-specific USB definitions + * + * NOTE: This must be kept in sync with the Edgeport firmware and + * must be kept backward-compatible with older firmware. + * + ************************************************************************ + * + * Copyright (c) 1998 Inside Out Networks, 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. + * + ************************************************************************/ + +#if !defined(_USBVEND_H) +#define _USBVEND_H + +#ifndef __KERNEL__ +#include "ionprag.h" /* Extra I/O Networks pragmas */ + +#include + +#include "iondef.h" /* Standard I/O Networks definitions */ +#endif + +/************************************************************************ + * + * D e f i n e s / T y p e d e f s + * + ************************************************************************/ + +// +// Definitions of USB product IDs +// + +#define USB_VENDOR_ID_ION 0x1608 // Our VID + +// +// Definitions of USB product IDs (PID) +// We break the USB-defined PID into an OEM Id field (upper 6 bits) +// and a Device Id (bottom 10 bits). The Device Id defines what +// device this actually is regardless of what the OEM wants to +// call it. +// + +// ION-device OEM IDs +#define ION_OEM_ID_ION 0 // 00h Inside Out Networks +#define ION_OEM_ID_NLYNX 1 // 01h NLynx Systems +#define ION_OEM_ID_GENERIC 2 // 02h Generic OEM +#define ION_OEM_ID_MAC 3 // 03h Mac Version +#define ION_OEM_ID_MEGAWOLF 4 // 04h Lupusb OEM Mac version (MegaWolf) +#define ION_OEM_ID_MULTITECH 5 // 05h Multitech Rapidports + + +// ION-device Device IDs +// Product IDs - assigned to match middle digit of serial number + + +// The ION_DEVICE_ID_GENERATION_2 bit (0x20) will be ORed into the existing edgeport +// PIDs to identify 80251+Netchip hardware. This will guarantee that if a second +// generation edgeport device is plugged into a PC with an older (pre 2.0) driver, +// it will not enumerate. + +#define ION_DEVICE_ID_GENERATION_2 0x020 // This bit is set in the PID if this edgeport hardware + // is based on the 80251+Netchip. + +#define EDGEPORT_DEVICE_ID_MASK 0x3df // Not including GEN_2 bit + +#define ION_DEVICE_ID_UNCONFIGURED_EDGE_DEVICE 0x000 // In manufacturing only +#define ION_DEVICE_ID_EDGEPORT_4 0x001 // Edgeport/4 RS232 +// ION_DEVICE_ID_HUBPORT_7 0x002 // Hubport/7 (Placeholder, not used by software) +#define ION_DEVICE_ID_RAPIDPORT_4 0x003 // Rapidport/4 +#define ION_DEVICE_ID_EDGEPORT_4T 0x004 // Edgeport/4 RS232 for Telxon (aka "Fleetport") +#define ION_DEVICE_ID_EDGEPORT_2 0x005 // Edgeport/2 RS232 +#define ION_DEVICE_ID_EDGEPORT_4I 0x006 // Edgeport/4 RS422 +#define ION_DEVICE_ID_EDGEPORT_2I 0x007 // Edgeport/2 RS422/RS485 +// ION_DEVICE_ID_HUBPORT_4 0x008 // Hubport/4 (Placeholder, not used by software) +// ION_DEVICE_ID_EDGEPORT_8_HANDBUILT 0x009 // Hand-built Edgeport/8 (Placeholder, used in middle digit of serial number only!) +// ION_DEVICE_ID_MULTIMODEM_4X56 0x00A // MultiTech version of RP/4 (Placeholder, used in middle digit of serial number only!) +#define ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT 0x00B // Edgeport/(4)21 Parallel port (USS720) +#define ION_DEVICE_ID_EDGEPORT_421 0x00C // Edgeport/421 Hub+RS232+Parallel +#define ION_DEVICE_ID_EDGEPORT_21 0x00D // Edgeport/21 RS232+Parallel +#define ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU 0x00E // Half of an Edgeport/8 (the kind with 2 EP/4s on 1 PCB) +#define ION_DEVICE_ID_EDGEPORT_8 0x00F // Edgeport/8 (single-CPU) +#define ION_DEVICE_ID_EDGEPORT_2_DIN 0x010 // Edgeport/2 RS232 with Apple DIN connector +#define ION_DEVICE_ID_EDGEPORT_4_DIN 0x011 // Edgeport/4 RS232 with Apple DIN connector +#define ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU 0x012 // Half of an Edgeport/16 (the kind with 2 EP/8s) +#define ION_DEVICE_ID_EDGEPORT_COMPATIBLE 0x013 // Edgeport Compatible, for NCR, Axiohm etc. testing +#define ION_DEVICE_ID_EDGEPORT_8I 0x014 // Edgeport/8 RS422 (single-CPU) + +// These IDs are used by the Edgeport.exe program for uninstalling. +// +#define EDGEPORT_DEVICE_IDS {0x001, 0x003, 0x004, 0x005, 0x006, 0x007, 0x00B, \ + 0x00C, 0x00D, 0x00E, 0x00F, 0x010, 0x011, 0x012, \ + 0x013, 0x014 } + + +#define MAKE_USB_PRODUCT_ID( OemId, DeviceId ) \ + ( (__u16) (((OemId) << 10) || (DeviceId)) ) + +#define DEVICE_ID_FROM_USB_PRODUCT_ID( ProductId ) \ + ( (__u16) ((ProductId) & (EDGEPORT_DEVICE_ID_MASK)) ) + +#define OEM_ID_FROM_USB_PRODUCT_ID( ProductId ) \ + ( (__u16) (((ProductId) >> 10) & 0x3F) ) + +// +// Definitions of parameters for download code. Note that these are +// specific to a given version of download code and must change if the +// corresponding download code changes. +// + +// TxCredits value below which driver won't bother sending (to prevent too many small writes). +// Send only if above 25% +#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit) (max( ((InitialCredit) / 4), EDGE_FW_BULK_MAX_PACKET_SIZE )) + +#define EDGE_FW_BULK_MAX_PACKET_SIZE 64 // Max Packet Size for Bulk In Endpoint (EP1) +#define EDGE_FW_BULK_READ_BUFFER_SIZE 1024 // Size to use for Bulk reads + +#define EDGE_FW_INT_MAX_PACKET_SIZE 32 // Max Packet Size for Interrupt In Endpoint + // Note that many units were shipped with MPS=16, we + // force an upgrade to this value). +#define EDGE_FW_INT_INTERVAL 2 // 2ms polling on IntPipe + + +// +// Definitions of I/O Networks vendor-specific requests +// for default endpoint +// +// bmRequestType = 00100000 Set vendor-specific, to device +// bmRequestType = 10100000 Get vendor-specific, to device +// +// These are the definitions for the bRequest field for the +// above bmRequestTypes. +// +// For the read/write Edgeport memory commands, the parameters +// are as follows: +// wValue = 16-bit address +// wIndex = unused (though we could put segment 00: or FF: here) +// wLength = # bytes to read/write (max 64) +// + +#define USB_REQUEST_ION_RESET_DEVICE 0 // Warm reboot Edgeport, retaining USB address +#define USB_REQUEST_ION_GET_EPIC_DESC 1 // Get Edgeport Compatibility Descriptor +// unused 2 // Unused, available +#define USB_REQUEST_ION_READ_RAM 3 // Read EdgePort RAM at specified addr +#define USB_REQUEST_ION_WRITE_RAM 4 // Write EdgePort RAM at specified addr +#define USB_REQUEST_ION_READ_ROM 5 // Read EdgePort ROM at specified addr +#define USB_REQUEST_ION_WRITE_ROM 6 // Write EdgePort ROM at specified addr +#define USB_REQUEST_ION_EXEC_DL_CODE 7 // Begin execution of RAM-based download + // code by jumping to address in wIndex:wValue +// 8 // Unused, available +#define USB_REQUEST_ION_ENABLE_SUSPEND 9 // Enable/Disable suspend feature + // (wValue != 0: Enable; wValue = 0: Disable) + + +// +// Define parameter values for our vendor-specific commands +// + + +// Values for iDownloadFile +#define EDGE_DOWNLOAD_FILE_NONE 0 // No download requested +#define EDGE_DOWNLOAD_FILE_INTERNAL 0xFF // Download the file compiled into driver (930 version) +#define EDGE_DOWNLOAD_FILE_I930 0xFF // Download the file compiled into driver (930 version) +#define EDGE_DOWNLOAD_FILE_80251 0xFE // Download the file compiled into driver (80251 version) + + + +/* + * Special addresses for READ/WRITE_RAM/ROM + */ + +// Version 1 (original) format of DeviceParams +#define EDGE_MANUF_DESC_ADDR_V1 0x00FF7F00 +#define EDGE_MANUF_DESC_LEN_V1 sizeof(EDGE_MANUF_DESCRIPTOR_V1) + +// Version 2 format of DeviceParams. This format is longer (3C0h) +// and starts lower in memory, at the uppermost 1K in ROM. +#define EDGE_MANUF_DESC_ADDR 0x00FF7C00 +#define EDGE_MANUF_DESC_LEN sizeof(EDGE_MANUF_DESCRIPTOR) + +// Boot params descriptor +#define EDGE_BOOT_DESC_ADDR 0x00FF7FC0 +#define EDGE_BOOT_DESC_LEN sizeof(EDGE_BOOT_DESCRIPTOR) + +// Define the max block size that may be read or written +// in a read/write RAM/ROM command. +#define MAX_SIZE_REQ_ION_READ_MEM ( (__u16) 64 ) +#define MAX_SIZE_REQ_ION_WRITE_MEM ( (__u16) 64 ) + + +// +// Notes for the following two ION vendor-specific param descriptors: +// +// 1. These have a standard USB descriptor header so they look like a +// normal descriptor. +// 2. Any strings in the structures are in USB-defined string +// descriptor format, so that they may be separately retrieved, +// if necessary, with a minimum of work on the 930. This also +// requires them to be in UNICODE format, which, for English at +// least, simply means extending each UCHAR into a USHORT. +// 3. For all fields, 00 means 'uninitialized'. +// 4. All unused areas should be set to 00 for future expansion. +// + +// This structure is ver 2 format. It contains ALL USB descriptors as +// well as the configuration parameters that were in the original V1 +// structure. It is NOT modified when new boot code is downloaded; rather, +// these values are set or modified by manufacturing. It is located at +// xC00-xFBF (length 3C0h) in the ROM. +// This structure is a superset of the v1 structure and is arranged so +// that all of the v1 fields remain at the same address. We are just +// adding more room to the front of the structure to hold the descriptors. +// +// The actual contents of this structure are defined in a 930 assembly +// file, converted to a binary image, and then written by the serialization +// program. The C definition of this structure just defines a dummy +// area for general USB descriptors and the descriptor tables (the root +// descriptor starts at xC00). At the bottom of the structure are the +// fields inherited from the v1 structure. + +#define MAX_SERIALNUMBER_LEN 12 +#define MAX_ASSEMBLYNUMBER_LEN 14 + +typedef struct _EDGE_MANUF_DESCRIPTOR { + + __u16 RootDescTable[0x10]; // C00 Root of descriptor tables (just a placeholder) + __u8 DescriptorArea[0x2E0]; // C20 Descriptors go here, up to 2E0h (just a placeholder) + + // Start of v1-compatible section + __u8 Length; // F00 Desc length for what follows, per USB (= C0h ) + __u8 DescType; // F01 Desc type, per USB (=DEVICE type) + __u8 DescVer; // F02 Desc version/format (currently 2) + __u8 NumRootDescEntries; // F03 # entries in RootDescTable + + __u8 RomSize; // F04 Size of ROM/E2PROM in K + __u8 RamSize; // F05 Size of external RAM in K + __u8 CpuRev; // F06 CPU revision level (chg only if s/w visible) + __u8 BoardRev; // F07 PCB revision level (chg only if s/w visible) + + __u8 NumPorts; // F08 Number of ports + __u8 DescDate[3]; // F09 MM/DD/YY when descriptor template was compiler, + // so host can track changes to USB-only descriptors. + + __u8 SerNumLength; // F0C USB string descriptor len + __u8 SerNumDescType; // F0D USB descriptor type (=STRING type) + __u16 SerialNumber[MAX_SERIALNUMBER_LEN]; // F0E "01-01-000100" Unicode Serial Number + + __u8 AssemblyNumLength; // F26 USB string descriptor len + __u8 AssemblyNumDescType; // F27 USB descriptor type (=STRING type) + __u16 AssemblyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F28 "350-1000-01-A " assembly number + + __u8 OemAssyNumLength; // F44 USB string descriptor len + __u8 OemAssyNumDescType; // F45 USB descriptor type (=STRING type) + __u16 OemAssyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F46 "xxxxxxxxxxxxxx" OEM assembly number + + __u8 ManufDateLength; // F62 USB string descriptor len + __u8 ManufDateDescType; // F63 USB descriptor type (=STRING type) + __u16 ManufDate[6]; // F64 "MMDDYY" manufacturing date + + __u8 Reserved3[0x4D]; // F70 -- unused, set to 0 -- + + __u8 UartType; // FBD Uart Type + __u8 IonPid; // FBE Product ID, == LSB of USB DevDesc.PID + // (Note: Edgeport/4s before 11/98 will have + // 00 here instead of 01) + __u8 IonConfig; // FBF Config byte for ION manufacturing use + // FBF end of structure, total len = 3C0h + +} EDGE_MANUF_DESCRIPTOR, *PEDGE_MANUF_DESCRIPTOR; + + +#define MANUF_DESC_VER_1 1 // Original definition of MANUF_DESC +#define MANUF_DESC_VER_2 2 // Ver 2, starts at xC00h len 3C0h + + +// Uart Types +// Note: Since this field was added only recently, all Edgeport/4 units +// shipped before 11/98 will have 00 in this field. Therefore, +// both 00 and 01 values mean '654. +#define MANUF_UART_EXAR_654_EARLY 0 // Exar 16C654 in Edgeport/4s before 11/98 +#define MANUF_UART_EXAR_654 1 // Exar 16C654 +#define MANUF_UART_EXAR_2852 2 // Exar 16C2852 + +// +// Note: The CpuRev and BoardRev values do not conform to manufacturing +// revisions; they are to be incremented only when the CPU or hardware +// changes in a software-visible way, such that the 930 software or +// the host driver needs to handle the hardware differently. +// + +// Values of bottom 5 bits of CpuRev & BoardRev for +// Implementation 0 (ie, 930-based) +#define MANUF_CPU_REV_AD4 1 // 930 AD4, with EP1 Rx bug (needs RXSPM) +#define MANUF_CPU_REV_AD5 2 // 930 AD5, with above bug (supposedly) fixed +#define MANUF_CPU_80251 0x20 // Intel 80251 + + +#define MANUF_BOARD_REV_A 1 // Original version, == Manuf Rev A +#define MANUF_BOARD_REV_B 2 // Manuf Rev B, wakeup interrupt works +#define MANUF_BOARD_REV_C 3 // Manuf Rev C, 2/4 ports, rs232/rs422 +#define MANUF_BOARD_REV_GENERATION_2 0x20 // Second generaiton edgeport + + + + +// Values of bottom 5 bits of CpuRev & BoardRev for +// Implementation 1 (ie, 251+Netchip-based) +#define MANUF_CPU_REV_1 1 // C251TB Rev 1 (Need actual Intel rev here) + +#define MANUF_BOARD_REV_A 1 // First rev of 251+Netchip design + + + +#define MANUF_SERNUM_LENGTH sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->SerialNumber) +#define MANUF_ASSYNUM_LENGTH sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->AssemblyNumber) +#define MANUF_OEMASSYNUM_LENGTH sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->OemAssyNumber) +#define MANUF_MANUFDATE_LENGTH sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->ManufDate) + +#define MANUF_ION_CONFIG_MASTER 0x80 // 1=Master mode, 0=Normal +#define MANUF_ION_CONFIG_DIAG 0x40 // 1=Run h/w diags, 0=norm +#define MANUF_ION_CONFIG_DIAG_NO_LOOP 0x20 // As above but no ext loopback test + + +// +// This structure describes parameters for the boot code, and +// is programmed along with new boot code. These are values +// which are specific to a given build of the boot code. It +// is exactly 64 bytes long and is fixed at address FF:xFC0 +// - FF:xFFF. Note that the 930-mandated UCONFIG bytes are +// included in this structure. +// +typedef struct _EDGE_BOOT_DESCRIPTOR { + __u8 Length; // C0 Desc length, per USB (= 40h) + __u8 DescType; // C1 Desc type, per USB (= DEVICE type) + __u8 DescVer; // C2 Desc version/format + __u8 Reserved1; // C3 -- unused, set to 0 -- + + __u16 BootCodeLength; // C4 Boot code goes from FF:0000 to FF:(len-1) + // (LE format) + + __u8 MajorVersion; // C6 Firmware version: xx. + __u8 MinorVersion; // C7 yy. + __u16 BuildNumber; // C8 zzzz (LE format) + + __u16 EnumRootDescTable; // CA Root of ROM-based descriptor table + __u8 NumDescTypes; // CC Number of supported descriptor types + + __u8 Reserved4; // CD Fix Compiler Packing + + __u16 Capabilities; // CE-CF Capabilities flags (LE format) + __u8 Reserved2[0x28]; // D0 -- unused, set to 0 -- + __u8 UConfig0; // F8 930-defined CPU configuration byte 0 + __u8 UConfig1; // F9 930-defined CPU configuration byte 1 + __u8 Reserved3[6]; // FA -- unused, set to 0 -- + // FF end of structure, total len = 80 + +} EDGE_BOOT_DESCRIPTOR, *PEDGE_BOOT_DESCRIPTOR; + + +#define BOOT_DESC_VER_1 1 // Original definition of BOOT_PARAMS +#define BOOT_DESC_VER_2 2 // 2nd definition, descriptors not included in boot + + + // Capabilities flags + +#define BOOT_CAP_RESET_CMD 0x0001 // If set, boot correctly supports ION_RESET_DEVICE + +#endif // if !defined() + 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/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c --- v2.4.2/linux/drivers/usb/serial/mct_u232.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/mct_u232.c Fri Mar 23 11:50:01 2001 @@ -346,8 +346,8 @@ mct_u232_close (&serial->port[i], NULL); } /* My special items, the standard routines free my urbs */ - if (serial->port->private) - kfree(serial->port->private); + if (serial->port[i].private) + kfree(serial->port[i].private); } } /* mct_u232_shutdown */ diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c --- v2.4.2/linux/drivers/usb/serial/omninet.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/omninet.c Sun Mar 25 18:14:21 2001 @@ -160,7 +160,7 @@ od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); if( !od ) { - err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct omninet_data)); + err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data)); --port->open_count; port->active = 0; spin_unlock_irqrestore (&port->port_lock, flags); @@ -305,8 +305,6 @@ return (0); } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); - spin_lock_irqsave (&port->port_lock, flags); count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; @@ -318,6 +316,7 @@ memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count); } + usb_serial_debug_data (__FILE__, __FUNCTION__, count, wport->write_urb->transfer_buffer); header->oh_seq = od->od_outseq++; header->oh_len = count; diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.4.2/linux/drivers/usb/serial/usbserial.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/usbserial.c Fri Mar 23 11:50:01 2001 @@ -827,8 +827,6 @@ spin_lock_irqsave (&port->port_lock, flags); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); - if (from_user) { copy_from_user(port->write_urb->transfer_buffer, buf, count); } @@ -836,6 +834,8 @@ memcpy (port->write_urb->transfer_buffer, buf, count); } + usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); + /* set up our urb */ FILL_BULK_URB(port->write_urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), @@ -1211,6 +1211,7 @@ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */ max_endpoints = MAX(num_bulk_in, num_bulk_out); max_endpoints = MAX(max_endpoints, num_interrupt_in); + max_endpoints = MAX(max_endpoints, serial->num_ports); dbg (__FUNCTION__ " - setting up %d port structures for this device", max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = &serial->port[i]; diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c --- v2.4.2/linux/drivers/usb/serial/visor.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/visor.c Mon Mar 19 17:21:54 2001 @@ -159,7 +159,7 @@ #define NUM_URBS 24 -#define URB_TRANSFER_BUFFER_SIZE 64 +#define URB_TRANSFER_BUFFER_SIZE 768 static struct urb *write_urb_pool[NUM_URBS]; static spinlock_t write_urb_pool_lock; static int bytes_in; diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c --- v2.4.2/linux/drivers/usb/serial/whiteheat.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/serial/whiteheat.c Fri Mar 23 11:50:01 2001 @@ -1,7 +1,7 @@ /* * USB ConnectTech WhiteHEAT driver * - * Copyright (C) 1999, 2000 + * Copyright (C) 1999 - 2001 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify @@ -11,6 +11,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * 2001_Mar_19 gkh + * Fixed MOD_INC and MOD_DEC logic, the ability to open a port more + * than once, and the got the proper usb_device_id table entries so + * the driver works again. + * * (11/01/2000) Adam J. Richter * usb_device_id table support * @@ -93,7 +98,7 @@ }; static __devinitdata struct usb_device_id id_table_prerenumeration [] = { - { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) }, + { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) }, { } /* Terminating entry */ }; @@ -289,43 +294,44 @@ dbg(__FUNCTION__" - port %d", port->number); - if (port->active) { - dbg (__FUNCTION__ " - device already open"); - return -EINVAL; - } - port->active = 1; - - /* set up some stuff for our command port */ - command_port = &port->serial->port[COMMAND_PORT]; - if (command_port->private == NULL) { - info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL); - if (info == NULL) { - err(__FUNCTION__ " - out of memory"); - return -ENOMEM; + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + port->active = 1; + + /* set up some stuff for our command port */ + command_port = &port->serial->port[COMMAND_PORT]; + if (command_port->private == NULL) { + info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL); + if (info == NULL) { + err(__FUNCTION__ " - out of memory"); + return -ENOMEM; + } + + init_waitqueue_head(&info->wait_command); + command_port->private = info; + command_port->write_urb->complete = command_port_write_callback; + command_port->read_urb->complete = command_port_read_callback; + command_port->read_urb->dev = port->serial->dev; + command_port->tty = port->tty; /* need this to "fake" our our sanity check macros */ + usb_submit_urb (command_port->read_urb); } - init_waitqueue_head(&info->wait_command); - command_port->private = info; - command_port->write_urb->complete = command_port_write_callback; - command_port->read_urb->complete = command_port_read_callback; - command_port->read_urb->dev = port->serial->dev; - command_port->tty = port->tty; /* need this to "fake" our our sanity check macros */ - usb_submit_urb (command_port->read_urb); - } + /* Start reading from the device */ + port->read_urb->dev = port->serial->dev; + result = usb_submit_urb(port->read_urb); + if (result) + err(__FUNCTION__ " - failed submitting read urb, error %d", result); + + /* send an open port command */ + /* firmware uses 1 based port numbering */ + open_command.port = port->number - port->serial->minor + 1; + whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command)); - /* Start reading from the device */ - port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb); - if (result) - err(__FUNCTION__ " - failed submitting read urb, error %d", result); - - /* send an open port command */ - /* firmware uses 1 based port numbering */ - open_command.port = port->number - port->serial->minor + 1; - whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command)); - - /* Need to do device specific setup here (control lines, baud rate, etc.) */ - /* FIXME!!! */ + /* Need to do device specific setup here (control lines, baud rate, etc.) */ + /* FIXME!!! */ + } dbg(__FUNCTION__ " - exit"); @@ -339,18 +345,23 @@ dbg(__FUNCTION__ " - port %d", port->number); - /* send a close command to the port */ - /* firmware uses 1 based port numbering */ - close_command.port = port->number - port->serial->minor + 1; - whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command)); + --port->open_count; - /* Need to change the control lines here */ - /* FIXME */ + if (port->open_count <= 0) { + /* send a close command to the port */ + /* firmware uses 1 based port numbering */ + close_command.port = port->number - port->serial->minor + 1; + whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command)); - /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - port->active = 0; + /* Need to change the control lines here */ + /* FIXME */ + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); + port->active = 0; + } + MOD_DEC_USE_COUNT; } @@ -548,8 +559,16 @@ static void whiteheat_shutdown (struct usb_serial *serial) { struct usb_serial_port *command_port; + int i; dbg(__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + whiteheat_close (&serial->port[i], NULL); + } + } /* free up our private data for our command port */ command_port = &serial->port[COMMAND_PORT]; 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 Mon Mar 26 15:49:54 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/uhci.c linux/drivers/usb/uhci.c --- v2.4.2/linux/drivers/usb/uhci.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/uhci.c Fri Mar 23 11:50:01 2001 @@ -66,6 +66,10 @@ static int uhci_unlink_generic(struct urb *urb); static int uhci_unlink_urb(struct urb *urb); +static int ports_active(struct uhci *uhci); +static void suspend_hc(struct uhci *uhci); +static void wakeup_hc(struct uhci *uhci); + #define min(a,b) (((a)<(b))?(a):(b)) /* If a transfer is still active after this much time, turn off FSBR */ @@ -1767,6 +1771,10 @@ } nested_unlock(&uhci->urblist_lock, flags); + /* enter global suspend if nothing connected */ + if (!uhci->is_suspended && !ports_active(uhci)) + suspend_hc(uhci); + rh_init_int_timer(urb); } @@ -2037,19 +2045,21 @@ return; outw(status, io_addr + USBSTS); - if (status & ~(USBSTS_USBINT | USBSTS_ERROR)) { - if (status & USBSTS_RD) - printk(KERN_INFO "uhci: resume detected, not implemented\n"); + if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & USBSTS_HSE) printk(KERN_ERR "uhci: host system error, PCI problems?\n"); if (status & USBSTS_HCPE) printk(KERN_ERR "uhci: host controller process error. something bad happened\n"); - if (status & USBSTS_HCH) { + if ((status & USBSTS_HCH) && !uhci->is_suspended) { printk(KERN_ERR "uhci: host controller halted. very bad\n"); /* FIXME: Reset the controller, fix the offending TD */ } } + if (status & USBSTS_RD) { + wakeup_hc(uhci); + } + uhci_free_pending_qhs(uhci); spin_lock(&uhci->urb_remove_lock); @@ -2093,6 +2103,49 @@ wait_ms(50); outw(0, io_addr + USBCMD); wait_ms(10); +} + +static void suspend_hc(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + + dbg("suspend_hc"); + + outw(USBCMD_EGSM, io_addr + USBCMD); + + uhci->is_suspended = 1; +} + +static void wakeup_hc(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + unsigned int status; + + dbg("wakeup_hc"); + + outw(0, io_addr + USBCMD); + + /* wait for EOP to be sent */ + status = inw(io_addr + USBCMD); + while (status & USBCMD_FGR) + status = inw(io_addr + USBCMD); + + uhci->is_suspended = 0; + + /* Run and mark it configured with a 64-byte max packet */ + outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); +} + +static int ports_active(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + int connection = 0; + int i; + + for (i = 0; i < uhci->rh.numports; i++) + connection |= (inw(io_addr + USBPORTSC1 + i * 2) & 0x1); + + return connection; } static void start_hc(struct uhci *uhci) diff -u --recursive --new-file v2.4.2/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h --- v2.4.2/linux/drivers/usb/uhci.h Thu Jan 4 14:52:32 2001 +++ linux/drivers/usb/uhci.h Mon Mar 26 15:50:12 2001 @@ -321,6 +321,7 @@ spinlock_t framelist_lock; struct uhci_framelist *fl; /* Frame list */ int fsbr; /* Full speed bandwidth reclamation */ + int is_suspended; spinlock_t qh_remove_lock; struct list_head qh_remove_list; diff -u --recursive --new-file v2.4.2/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.4.2/linux/drivers/usb/usb-ohci.c Wed Feb 21 18:20:36 2001 +++ linux/drivers/usb/usb-ohci.c Fri Mar 23 11:50:01 2001 @@ -12,6 +12,7 @@ * * History: * + * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam) * 2000/09/26 fixed races in removing the private portion of the urb * 2000/09/07 disable bulk and control lists when unlinking the last * endpoint descriptor in order to avoid unrecoverable errors on @@ -208,7 +209,7 @@ __u32 * ed_p; for (i= 0; i < 32; i++) { j = 5; - ed_p = &(ohci->hcca.int_table [i]); + ed_p = &(ohci->hcca->int_table [i]); if (*ed_p == 0) continue; printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i); @@ -371,7 +372,7 @@ ohci_dump_status (controller); if (verbose) ep_print_int_eds (controller, "hcca"); - dbg ("hcca frame #%04x", controller->hcca.frame_no); + dbg ("hcca frame #%04x", controller->hcca->frame_no); ohci_dump_roothub (controller, 1); } @@ -555,7 +556,7 @@ if (urb->transfer_flags & USB_ISO_ASAP) { urb->start_frame = ((ed->state == ED_OPER) ? (ed->last_iso + 1) - : (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff; + : (le16_to_cpu (ohci->hcca->frame_no) + 10)) & 0xffff; } /* FALLTHROUGH */ case PIPE_INTERRUPT: @@ -751,7 +752,7 @@ * the controller won't ever be touching * these lists again!! dl_del_list (ohci, - le16_to_cpu (ohci->hcca.frame_no) & 1); + le16_to_cpu (ohci->hcca->frame_no) & 1); */ warn ("TD leak, %d", cnt); @@ -795,7 +796,7 @@ { ohci_t * ohci = usb_dev->bus->hcpriv; - return le16_to_cpu (ohci->hcca.frame_no); + return le16_to_cpu (ohci->hcca->frame_no); } /*-------------------------------------------------------------------------*/ @@ -914,7 +915,7 @@ for (i = 0; i < ep_rev (6, interval); i += inter) { inter = 1; - for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]); + for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]); (*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval >= interval); ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); @@ -935,7 +936,7 @@ } else { for ( i = 0; i < 32; i += inter) { inter = 1; - for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); + for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); *ed_p != 0; ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); @@ -1009,7 +1010,7 @@ interval = ed->int_interval; for (i = 0; i < ep_rev (6, interval); i += inter) { - for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]), inter = 1; + for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]), inter = 1; (*ed_p != 0) && (*ed_p != ed->hwNextED); ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED), inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval)) { @@ -1036,7 +1037,7 @@ ed->ed_prev->hwNextED = ed->hwNextED; } else { for (i = 0; i < 32; i++) { - for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); + for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); *ed_p != 0; ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) { // inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); @@ -1148,7 +1149,7 @@ } } - frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1; + frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1; ed->ed_rm_list = ohci->ed_rm_list[frame]; ohci->ed_rm_list[frame] = ed; @@ -1361,8 +1362,8 @@ spin_lock_irqsave (&usb_ed_lock, flags); - td_list_hc = le32_to_cpup (&ohci->hcca.done_head) & 0xfffffff0; - ohci->hcca.done_head = 0; + td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0; + ohci->hcca->done_head = 0; while (td_list_hc) { td_list = (td_t *) bus_to_virt (td_list_hc); @@ -2018,7 +2019,7 @@ writel (0, &ohci->regs->ed_controlhead); writel (0, &ohci->regs->ed_bulkhead); - writel (virt_to_bus (&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */ + writel (ohci->hcca_dma, &ohci->regs->hcca); /* a reset clears this */ fminterval = 0x2edf; writel ((fminterval * 9) / 10, &ohci->regs->periodicstart); @@ -2075,13 +2076,13 @@ struct ohci_regs * regs = ohci->regs; int ints; - if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 0x01)) { + if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { ints = OHCI_INTR_WDH; } else if ((ints = (readl (®s->intrstatus) & readl (®s->intrenable))) == 0) { return; } - // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no)); + // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); if (ints & OHCI_INTR_UE) { ohci->disabled++; @@ -2111,7 +2112,7 @@ } if (ints & OHCI_INTR_SF) { - unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1; + unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1; writel (OHCI_INTR_SF, ®s->intrdisable); if (ohci->ed_rm_list[!frame] != NULL) { dl_del_list (ohci, !frame); @@ -2139,7 +2140,15 @@ return NULL; memset (ohci, 0, sizeof (ohci_t)); - + + ohci->hcca = pci_alloc_consistent (dev, sizeof *ohci->hcca, + &ohci->hcca_dma); + if (!ohci->hcca) { + kfree (ohci); + return NULL; + } + memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); + ohci->disabled = 1; ohci->irq = -1; ohci->regs = mem_base; @@ -2192,7 +2201,9 @@ /* unmap the IO address space */ iounmap (ohci->regs); - + + pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca, + ohci->hcca, ohci->hcca_dma); kfree (ohci); } @@ -2290,7 +2301,7 @@ /* empty the interrupt branches */ for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0; - for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0; + for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0; /* no EDs to remove */ ohci->ed_rm_list [0] = NULL; @@ -2320,6 +2331,13 @@ unsigned long mem_resource, mem_len; void *mem_base; + /* blacklisted hardware? */ + if (id->driver_data) { + info ("%s (%s): %s", dev->slot_name, + dev->name, (char *) id->driver_data); + return -ENODEV; + } + if (pci_enable_device(dev) < 0) return -ENODEV; @@ -2484,6 +2502,20 @@ /*-------------------------------------------------------------------------*/ static const struct pci_device_id __devinitdata ohci_pci_ids [] = { { + + /* + * AMD-756 [Viper] USB has a serious erratum when used with + * lowspeed devices like mice; oopses have been seen. The + * vendor workaround needs an NDA ... for now, blacklist it. + */ + vendor: 0x1022, + device: 0x740c, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + + driver_data: (unsigned long) "blacklisted, erratum #4", + +} , { /* handle any USB OHCI controller */ class: ((PCI_CLASS_SERIAL_USB << 8) | 0x10), diff -u --recursive --new-file v2.4.2/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h --- v2.4.2/linux/drivers/usb/usb-ohci.h Wed Oct 18 15:28:18 2000 +++ linux/drivers/usb/usb-ohci.h Mon Mar 19 17:21:54 2001 @@ -346,7 +346,8 @@ typedef struct ohci { - struct ohci_hcca hcca; /* hcca */ + struct ohci_hcca *hcca; /* hcca */ + u32 hcca_dma; int irq; int disabled; /* e.g. got a UE, we're hung */ 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 Sun Mar 25 18:14:21 2001 @@ -39,11 +39,6 @@ #endif #include -#define DEVNUM_ROUND_ROBIN /***** OPTION *****/ -#ifdef DEVNUM_ROUND_ROBIN -static int devnum_next = 1; -#endif - static const int usb_bandwidth_option = #ifdef CONFIG_USB_BANDWIDTH 1; @@ -153,7 +148,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 +346,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. * @@ -364,6 +362,10 @@ memset(&bus->devmap, 0, sizeof(struct usb_devmap)); +#ifdef DEVNUM_ROUND_ROBIN + bus->devnum_next = 1; +#endif /* DEVNUM_ROUND_ROBIN */ + bus->op = op; bus->root_hub = NULL; bus->hcpriv = NULL; @@ -382,6 +384,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 +398,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 +419,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 +512,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 +850,7 @@ call_policy (char *verb, struct usb_device *dev) { } -#endif /* KMOD */ +#endif /* CONFIG_HOTPLUG */ /* @@ -1639,7 +1662,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); } } } @@ -1681,14 +1706,12 @@ #ifndef DEVNUM_ROUND_ROBIN devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); #else /* round_robin alloc of devnums */ - /* Try to allocate the next devnum beginning at devnum_next. */ - devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, devnum_next); + /* Try to allocate the next devnum beginning at bus->devnum_next. */ + devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next); if (devnum >= 128) devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); - devnum_next = devnum + 1; - if (devnum_next >= 128) - devnum_next = 1; + dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); #endif /* round_robin alloc of devnums */ if (devnum < 128) { @@ -2123,7 +2146,7 @@ if (err < 0) err("unable to get device descriptor (error=%d)", err); else - err("USB device descriptor short read (expected %i, got %i)", + err("USB device descriptor short read (expected %Zi, got %i)", sizeof(dev->descriptor), err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); diff -u --recursive --new-file v2.4.2/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c --- v2.4.2/linux/drivers/usb/uss720.c Thu Jan 4 13:15:32 2001 +++ linux/drivers/usb/uss720.c Sun Mar 25 18:14:21 2001 @@ -366,7 +366,7 @@ return 0; i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, HZ*20); if (i) - printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %u\n", buf, length, rlen); + printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buf, length, rlen); change_mode(pp, ECR_PS2); return rlen; #endif @@ -427,7 +427,7 @@ return 0; i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, HZ*20); if (i) - printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %u\n", buffer, len, rlen); + printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen); change_mode(pp, ECR_PS2); return rlen; } @@ -445,7 +445,7 @@ return 0; i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, HZ*20); if (i) - printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %u rlen %u\n", buffer, len, rlen); + printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %Zu rlen %u\n", buffer, len, rlen); change_mode(pp, ECR_PS2); return rlen; } @@ -478,7 +478,7 @@ return 0; i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, HZ*20); if (i) - printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %u\n", buffer, len, rlen); + printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen); change_mode(pp, ECR_PS2); return rlen; } 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/creatorfb.c linux/drivers/video/creatorfb.c --- v2.4.2/linux/drivers/video/creatorfb.c Wed Feb 21 18:20:37 2001 +++ linux/drivers/video/creatorfb.c Sun Mar 25 18:14:20 2001 @@ -1,4 +1,4 @@ -/* $Id: creatorfb.c,v 1.33 2001/02/13 01:17:14 davem Exp $ +/* $Id: creatorfb.c,v 1.34 2001/03/16 10:22:02 davem Exp $ * creatorfb.c: Creator/Creator3D frame buffer driver * * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz) @@ -751,6 +751,36 @@ static char idstring[60] __initdata = { 0 }; +static int __init creator_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs) +{ + struct linux_prom64_ranges ranges[PROMREG_MAX]; + char name[128]; + int len, i; + + prom_getproperty(parent, "name", name, sizeof(name)); + if (strcmp(name, "upa") != 0) + return 0; + + len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges)); + if (len <= 0) + return 1; + + len /= sizeof(struct linux_prom64_ranges); + for (i = 0; i < len; i++) { + struct linux_prom64_ranges *rng = &ranges[i]; + u64 phys_addr = regs->phys_addr; + + if (phys_addr >= rng->ot_child_base && + phys_addr < (rng->ot_child_base + rng->or_size)) { + regs->phys_addr -= rng->ot_child_base; + regs->phys_addr += rng->ot_parent_base; + return 0; + } + } + + return 1; +} + char __init *creatorfb_init(struct fb_info_sbusfb *fb) { struct fb_fix_screeninfo *fix = &fb->fix; @@ -764,6 +794,9 @@ struct fb_ops *fbops; if (prom_getproperty(fb->prom_node, "reg", (void *) regs, sizeof(regs)) <= 0) + return NULL; + + if (creator_apply_upa_parent_ranges(fb->prom_parent, ®s[0])) return NULL; disp->dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL); 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/sbusfb.c linux/drivers/video/sbusfb.c --- v2.4.2/linux/drivers/video/sbusfb.c Wed Feb 21 18:20:38 2001 +++ linux/drivers/video/sbusfb.c Sun Mar 25 18:14:20 2001 @@ -1179,6 +1179,33 @@ return FBTYPE_NOTYPE; } +#ifdef CONFIG_FB_CREATOR +static void creator_fb_scan_siblings(int root) +{ + int node, child; + + child = prom_getchild(root); + for (node = prom_searchsiblings(child, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) + sbusfb_init_fb(node, root, FBTYPE_CREATOR, NULL); + for (node = prom_searchsiblings(child, "SUNW,afb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb")) + sbusfb_init_fb(node, root, FBTYPE_CREATOR, NULL); +} + +static void creator_fb_scan(void) +{ + int root; + + creator_fb_scan_siblings(prom_root_node); + + root = prom_getchild(prom_root_node); + for (root = prom_searchsiblings(root, "upa"); root; + root = prom_searchsiblings(prom_getsibling(root), "upa")) + creator_fb_scan_siblings(root); +} +#endif + int __init sbusfb_init(void) { int type; @@ -1190,16 +1217,7 @@ if (!con_is_present()) return -ENXIO; #ifdef CONFIG_FB_CREATOR - { - int root, node; - root = prom_getchild(prom_root_node); - for (node = prom_searchsiblings(root, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) - sbusfb_init_fb(node, prom_root_node, FBTYPE_CREATOR, NULL); - for (node = prom_searchsiblings(root, "SUNW,afb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb")) - sbusfb_init_fb(node, prom_root_node, FBTYPE_CREATOR, NULL); - } + creator_fb_scan(); #endif #ifdef CONFIG_SUN4 sbusfb_init_fb(0, 0, FBTYPE_SUN2BW, NULL); 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 Mon Mar 19 12:34:56 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; } @@ -377,24 +377,24 @@ goto beyond_if; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (error != N_TXTADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; @@ -476,12 +476,12 @@ goto out; } /* Now use mmap to map the library into memory. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); retval = error; if (error != start_addr) goto out; diff -u --recursive --new-file v2.4.2/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.4.2/linux/fs/binfmt_elf.c Wed Feb 21 18:20:38 2001 +++ linux/fs/binfmt_elf.c Mon Mar 19 17:05:16 2001 @@ -214,11 +214,11 @@ { unsigned long map_addr; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); map_addr = do_mmap(filep, ELF_PAGESTART(addr), eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return(map_addr); } @@ -732,10 +732,10 @@ Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ /* N.B. Shouldn't the size here be PAGE_SIZE?? */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } #ifdef ELF_PLAT_INIT @@ -816,7 +816,7 @@ while (elf_phdata->p_type != PT_LOAD) elf_phdata++; /* Now use mmap to map the library into memory. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(file, ELF_PAGESTART(elf_phdata->p_vaddr), (elf_phdata->p_filesz + @@ -825,7 +825,7 @@ MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, (elf_phdata->p_offset - ELF_PAGEOFFSET(elf_phdata->p_vaddr))); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) goto out_free_ph; @@ -1203,15 +1203,15 @@ pte_t *pte; pgd = pgd_offset(vma->vm_mm, addr); - pmd = pmd_alloc(pgd, addr); + pmd = pmd_offset(pgd, addr); if (!pmd) - goto end_coredump; - pte = pte_alloc(pmd, addr); + goto nextpage_coredump; + pte = pte_offset(pmd, addr); if (!pte) - goto end_coredump; - if (!pte_present(*pte) && - pte_none(*pte)) { + goto nextpage_coredump; + if (pte_none(*pte)) { +nextpage_coredump: DUMP_SEEK (file->f_pos + PAGE_SIZE); } else { DUMP_WRITE((void*)addr, PAGE_SIZE); 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 Sat Mar 24 19:31:58 2001 @@ -1880,8 +1880,8 @@ iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); page = grab_cache_page(mapping, index); - err = PTR_ERR(page); - if (IS_ERR(page)) + err = -ENOMEM; + if (!page) goto out; if (!page->buffers) @@ -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/exec.c linux/fs/exec.c --- v2.4.2/linux/fs/exec.c Wed Feb 21 18:20:39 2001 +++ linux/fs/exec.c Thu Mar 22 09:26:18 2001 @@ -252,6 +252,8 @@ /* * This routine is used to map in a page into an address space: needed by * execve() for the initial stack and environment pages. + * + * tsk->mmap_sem is held for writing. */ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address) { @@ -262,27 +264,29 @@ if (page_count(page) != 1) printk("mem_map disagrees with %p at %08lx\n", page, address); pgd = pgd_offset(tsk->mm, address); - pmd = pmd_alloc(pgd, address); - if (!pmd) { - __free_page(page); - force_sig(SIGKILL, tsk); - return; - } - pte = pte_alloc(pmd, address); - if (!pte) { - __free_page(page); - force_sig(SIGKILL, tsk); - return; - } - if (!pte_none(*pte)) { - pte_ERROR(*pte); - __free_page(page); - return; - } + + spin_lock(&tsk->mm->page_table_lock); + pmd = pmd_alloc(tsk->mm, pgd, address); + if (!pmd) + goto out; + pte = pte_alloc(tsk->mm, pmd, address); + if (!pte) + goto out; + if (!pte_none(*pte)) + goto out; flush_dcache_page(page); flush_page_to_ram(page); set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY)))); -/* no need for flush_tlb */ + tsk->mm->rss++; + spin_unlock(&tsk->mm->page_table_lock); + + /* no need for flush_tlb */ + return; +out: + spin_unlock(&tsk->mm->page_table_lock); + __free_page(page); + force_sig(SIGKILL, tsk); + return; } int setup_arg_pages(struct linux_binprm *bprm) @@ -302,7 +306,7 @@ if (!mpnt) return -ENOMEM; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; @@ -321,12 +325,11 @@ struct page *page = bprm->page[i]; if (page) { bprm->page[i] = NULL; - current->mm->rss++; put_dirty_page(current,page,stack_base); } stack_base += PAGE_SIZE; } - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return 0; } diff -u --recursive --new-file v2.4.2/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v2.4.2/linux/fs/ext2/ialloc.c Fri Dec 8 17:35:54 2000 +++ linux/fs/ext2/ialloc.c Fri Mar 23 12:15:07 2001 @@ -442,6 +442,7 @@ inode->u.ext2_i.i_file_acl = 0; inode->u.ext2_i.i_dir_acl = 0; inode->u.ext2_i.i_dtime = 0; + inode->u.ext2_i.i_prealloc_count = 0; inode->u.ext2_i.i_block_group = i; if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) inode->i_flags |= S_SYNC; diff -u --recursive --new-file v2.4.2/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.4.2/linux/fs/ext2/inode.c Fri Dec 29 14:36:44 2000 +++ linux/fs/ext2/inode.c Fri Mar 23 12:15:29 2001 @@ -1047,6 +1047,7 @@ inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; } inode->i_generation = le32_to_cpu(raw_inode->i_generation); + inode->u.ext2_i.i_prealloc_count = 0; inode->u.ext2_i.i_block_group = block_group; /* 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 Thu Mar 22 11:04:13 2001 @@ -133,7 +133,7 @@ if (sb) { /* Don't do this for I_DIRTY_PAGES - that doesn't actually dirty the inode itself */ - if (flags & (I_DIRTY | I_DIRTY_SYNC)) { + if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { if (sb->s_op && sb->s_op->dirty_inode) sb->s_op->dirty_inode(inode); } @@ -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/iobuf.c linux/fs/iobuf.c --- v2.4.2/linux/fs/iobuf.c Wed Feb 21 18:20:39 2001 +++ linux/fs/iobuf.c Mon Mar 26 18:11:36 2001 @@ -55,7 +55,7 @@ return -ENOMEM; } kiobuf_init(iobuf); - *bufp++ = iobuf; + bufp[i] = iobuf; } return 0; 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/namei.c linux/fs/namei.c --- v2.4.2/linux/fs/namei.c Fri Dec 29 14:07:23 2000 +++ linux/fs/namei.c Thu Mar 22 11:07:58 2001 @@ -1013,7 +1013,7 @@ error = -ELOOP; if (flag & O_NOFOLLOW) goto exit_dput; - do __follow_down(&nd->mnt,&dentry); while(d_mountpoint(dentry)); + while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry)); } error = -ENOENT; if (!dentry->d_inode) @@ -1927,13 +1927,11 @@ * bloody create() on broken symlinks. Furrfu... */ name = __getname(); - if (IS_ERR(name)) - goto fail_name; + if (!name) + return -ENOMEM; strcpy(name, nd->last.name); nd->last.name = name; return 0; -fail_name: - link = name; fail: path_release(nd); return PTR_ERR(link); 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 Thu Mar 15 09:56:07 2001 @@ -321,7 +321,7 @@ desc->page = NULL; } - page = page_cache_alloc(); + page = alloc_page(GFP_HIGHUSER); if (!page) { status = -ENOMEM; goto out; @@ -1097,6 +1097,10 @@ if (!NFS_PROTO(inode)->access) goto out; + + if (error == -EROFS) + goto out; + /* * Trust UNIX mode bits except: * 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/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.4.2/linux/fs/nfsd/nfssvc.c Wed Feb 21 18:20:40 2001 +++ linux/fs/nfsd/nfssvc.c Thu Mar 15 09:56:07 2001 @@ -149,12 +149,8 @@ /* Lock module and set up kernel thread */ MOD_INC_USE_COUNT; lock_kernel(); - exit_mm(current); - current->session = 1; - current->pgrp = 1; + daemonize(); sprintf(current->comm, "nfsd"); - current->fs->umask = 0; - current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; nfsdstats.th_cnt++; 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/array.c linux/fs/proc/array.c --- v2.4.2/linux/fs/proc/array.c Tue Nov 14 11:22:36 2000 +++ linux/fs/proc/array.c Mon Mar 19 12:34:55 2001 @@ -181,7 +181,7 @@ unsigned long data = 0, stack = 0; unsigned long exec = 0, lib = 0; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); for (vma = mm->mmap; vma; vma = vma->vm_next) { unsigned long len = (vma->vm_end - vma->vm_start) >> 10; if (!vma->vm_file) { @@ -212,7 +212,7 @@ mm->rss << (PAGE_SHIFT-10), data - stack, stack, exec - lib, lib); - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return buffer; } @@ -321,7 +321,7 @@ task_unlock(task); if (mm) { struct vm_area_struct *vma; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = mm->mmap; while (vma) { vsize += vma->vm_end - vma->vm_start; @@ -329,7 +329,7 @@ } eip = KSTK_EIP(task); esp = KSTK_ESP(task); - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); } wchan = get_wchan(task); @@ -484,7 +484,7 @@ task_unlock(task); if (mm) { struct vm_area_struct * vma; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = mm->mmap; while (vma) { pgd_t *pgd = pgd_offset(mm, vma->vm_start); @@ -505,7 +505,7 @@ drs += pages; vma = vma->vm_next; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); } return sprintf(buffer,"%d %d %d %d %d %d %d\n", @@ -582,7 +582,7 @@ column = *ppos & (MAPS_LINE_LENGTH-1); /* quickly go to line lineno */ - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++) continue; @@ -644,9 +644,7 @@ i = len-column; if (i > count) i = count; - up(&mm->mmap_sem); copy_to_user(destptr, line+column, i); /* may have slept */ - down(&mm->mmap_sem); destptr += i; count -= i; column += i; @@ -665,7 +663,7 @@ if (volatile_task) break; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* encode f_pos */ *ppos = (lineno << MAPS_LINE_SHIFT) + column; diff -u --recursive --new-file v2.4.2/linux/fs/proc/base.c linux/fs/proc/base.c --- v2.4.2/linux/fs/proc/base.c Thu Nov 16 13:18:26 2000 +++ linux/fs/proc/base.c Mon Mar 19 12:34:55 2001 @@ -64,7 +64,7 @@ task_unlock(task); if (!mm) goto out; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = mm->mmap; while (vma) { if ((vma->vm_flags & VM_EXECUTABLE) && @@ -76,7 +76,7 @@ } vma = vma->vm_next; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); out: return result; 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/proc/proc_misc.c linux/fs/proc/proc_misc.c --- v2.4.2/linux/fs/proc/proc_misc.c Tue Nov 7 11:08:09 2000 +++ linux/fs/proc/proc_misc.c Fri Mar 23 11:45:28 2001 @@ -293,8 +293,8 @@ "page %u %u\n" "swap %u %u\n" "intr %u", - kstat.pgpgin, - kstat.pgpgout, + kstat.pgpgin >> 1, + kstat.pgpgout >> 1, kstat.pswpin, kstat.pswpout, sum 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 Mon Mar 26 10:54:03 2001 @@ -304,6 +304,7 @@ char * p = NULL; int chars; int ret ; + int done = 0 ; unsigned long offset ; // prepare the key to look for the 'block'-th block of file @@ -355,6 +356,14 @@ return -ENOENT; } + /* if we've got a direct item, and the buffer was uptodate, + ** we don't want to pull data off disk again. skip to the + ** end, where we map the buffer and return + */ + if (buffer_uptodate(bh_result)) { + goto finished ; + } + // read file tail into part of page offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1) ; fs_gen = get_generation(inode->i_sb) ; @@ -375,8 +384,24 @@ if (!is_direct_le_ih (ih)) { BUG (); } - chars = le16_to_cpu (ih->ih_item_len) - path.pos_in_item; + /* make sure we don't read more bytes than actually exist in + ** the file. This can happen in odd cases where i_size isn't + ** correct, and when direct item padding results in a few + ** extra bytes at the end of the direct item + */ + if ((le_ih_k_offset(ih) + path.pos_in_item) > inode->i_size) + break ; + if ((le_ih_k_offset(ih) - 1 + ih_item_len(ih)) > inode->i_size) { + chars = inode->i_size - (le_ih_k_offset(ih) - 1) - path.pos_in_item; + done = 1 ; + } else { + chars = le16_to_cpu (ih->ih_item_len) - path.pos_in_item; + } memcpy (p, B_I_PITEM (bh, ih) + path.pos_in_item, chars); + + if (done) + break ; + p += chars; if (PATH_LAST_POSITION (&path) != (B_NR_ITEMS (bh) - 1)) @@ -395,16 +420,14 @@ ih = get_ih (&path); } while (1); +finished: pathrelse (&path); - - // FIXME: b_blocknr == 0 here. but b_data contains correct data - // from tail. ll_rw_block will skip uptodate buffers bh_result->b_blocknr = 0 ; bh_result->b_dev = inode->i_dev; mark_buffer_uptodate (bh_result, 1); bh_result->b_state |= (1UL << BH_Mapped); + flush_dcache_page(bh_result->b_page) ; kunmap(bh_result->b_page) ; - return 0; } @@ -476,8 +499,8 @@ index = tail_offset >> PAGE_CACHE_SHIFT ; if (index != hole_page->index) { tail_page = grab_cache_page(inode->i_mapping, index) ; - retval = PTR_ERR(tail_page) ; - if (IS_ERR(tail_page)) { + retval = -ENOMEM; + if (!tail_page) { goto out ; } } else { @@ -771,6 +794,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 +1284,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 +1320,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) { @@ -1486,8 +1510,8 @@ return -ENOENT ; } page = grab_cache_page(p_s_inode->i_mapping, index) ; - error = PTR_ERR(page) ; - if (IS_ERR(page)) { + error = -ENOMEM ; + if (!page) { goto out ; } /* start within the page of the last block in the file */ @@ -1566,8 +1590,9 @@ /* so, if page != NULL, we have a buffer head for the offset at ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0, ** then we have an unformatted node. Otherwise, we have a direct item, - ** and no zeroing is required. We zero after the truncate, because the - ** truncate might pack the item anyway (it will unmap bh if it packs). + ** and no zeroing is required on disk. We zero after the truncate, + ** because the truncate might pack the item anyway + ** (it will unmap bh if it packs). */ prevent_flush_page_lock(page, p_s_inode) ; journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; @@ -1577,7 +1602,7 @@ journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; allow_flush_page_lock(page, p_s_inode) ; - if (page && buffer_mapped(bh) && bh->b_blocknr != 0) { + if (page) { length = offset & (blocksize - 1) ; /* if we are not on a block boundary */ if (length) { @@ -1585,14 +1610,14 @@ memset((char *)kmap(page) + offset, 0, length) ; flush_dcache_page(page) ; kunmap(page) ; - mark_buffer_dirty(bh) ; + if (buffer_mapped(bh) && bh->b_blocknr != 0) { + mark_buffer_dirty(bh) ; + } } - } - - if (page) { UnlockPage(page) ; page_cache_release(page) ; } + return ; } @@ -1645,6 +1670,7 @@ goto out ; } set_block_dev_mapped(bh_result, le32_to_cpu(item[pos_in_item]), inode); + mark_buffer_uptodate(bh_result, 1); } else if (is_direct_le_ih(ih)) { char *p ; p = page_address(bh_result->b_page) ; @@ -1664,6 +1690,7 @@ journal_mark_dirty(&th, inode->i_sb, bh) ; bytes_copied += copy_size ; set_block_dev_mapped(bh_result, 0, inode); + mark_buffer_uptodate(bh_result, 1); /* are there still bytes left? */ if (bytes_copied < bh_result->b_size && diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/ioctl.c linux/fs/reiserfs/ioctl.c --- v2.4.2/linux/fs/reiserfs/ioctl.c Sat Feb 3 19:51:31 2001 +++ linux/fs/reiserfs/ioctl.c Wed Mar 21 20:28:56 2001 @@ -77,8 +77,8 @@ */ index = inode->i_size >> PAGE_CACHE_SHIFT ; page = grab_cache_page(inode->i_mapping, index) ; - retval = PTR_ERR(page) ; - if (IS_ERR(page)) { + retval = -ENOMEM; + if (!page) { goto out ; } retval = reiserfs_prepare_write(NULL, page, write_from, blocksize) ; 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 Fri Mar 23 11:50:52 2001 @@ -48,6 +48,7 @@ UnlockPage(page); page_cache_release(page); out: + return; } /* @@ -71,47 +72,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 +82,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 +127,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 +142,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 +154,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/super.c linux/fs/super.c --- v2.4.2/linux/fs/super.c Wed Feb 21 18:20:40 2001 +++ linux/fs/super.c Sun Mar 25 18:17:00 2001 @@ -1412,6 +1412,8 @@ return retval; fail: + if (fstype->fs_flags & FS_SINGLE) + put_filesystem(fstype); if (list_empty(&sb->s_mounts)) kill_super(sb, 0); goto unlock_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 Mon Mar 26 15:48:10 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 Mon Mar 26 15:48:11 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 Mon Mar 26 15:48:44 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/pgalloc-2level.h linux/include/asm-i386/pgalloc-2level.h --- v2.4.2/linux/include/asm-i386/pgalloc-2level.h Sat Nov 20 10:09:05 1999 +++ linux/include/asm-i386/pgalloc-2level.h Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -#ifndef _I386_PGALLOC_2LEVEL_H -#define _I386_PGALLOC_2LEVEL_H - -/* - * traditional i386 two-level paging, page table allocation routines: - */ - -extern __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} - -extern __inline__ void free_pmd_fast(pmd_t *pmd) { } -extern __inline__ void free_pmd_slow(pmd_t *pmd) { } - -extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) -{ - if (!pgd) - BUG(); - return (pmd_t *) pgd; -} - -#endif /* _I386_PGALLOC_2LEVEL_H */ diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pgalloc-3level.h linux/include/asm-i386/pgalloc-3level.h --- v2.4.2/linux/include/asm-i386/pgalloc-3level.h Fri Dec 3 11:12:23 1999 +++ linux/include/asm-i386/pgalloc-3level.h Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -#ifndef _I386_PGALLOC_3LEVEL_H -#define _I386_PGALLOC_3LEVEL_H - -/* - * Intel Physical Address Extension (PAE) Mode - three-level page - * tables on PPro+ CPUs. Page-table allocation routines. - * - * Copyright (C) 1999 Ingo Molnar - */ - -extern __inline__ pmd_t *get_pmd_slow(void) -{ - pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL); - - if (ret) - memset(ret, 0, PAGE_SIZE); - return ret; -} - -extern __inline__ pmd_t *get_pmd_fast(void) -{ - unsigned long *ret; - - if ((ret = pmd_quicklist) != NULL) { - pmd_quicklist = (unsigned long *)(*ret); - ret[0] = 0; - pgtable_cache_size--; - } else - ret = (unsigned long *)get_pmd_slow(); - return (pmd_t *)ret; -} - -extern __inline__ void free_pmd_fast(pmd_t *pmd) -{ - *(unsigned long *)pmd = (unsigned long) pmd_quicklist; - pmd_quicklist = (unsigned long *) pmd; - pgtable_cache_size++; -} - -extern __inline__ void free_pmd_slow(pmd_t *pmd) -{ - free_page((unsigned long)pmd); -} - -extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) -{ - if (!pgd) - BUG(); - address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *page = get_pmd_fast(); - - if (!page) - page = get_pmd_slow(); - if (page) { - if (pgd_none(*pgd)) { - set_pgd(pgd, __pgd(1 + __pa(page))); - __flush_tlb(); - return page + address; - } else - free_pmd_fast(page); - } else - return NULL; - } - return (pmd_t *)pgd_page(*pgd) + address; -} - -#endif /* _I386_PGALLOC_3LEVEL_H */ diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h --- v2.4.2/linux/include/asm-i386/pgalloc.h Thu Jan 4 14:50:46 2001 +++ linux/include/asm-i386/pgalloc.h Mon Mar 26 15:48:11 2001 @@ -11,35 +11,56 @@ #define pte_quicklist (current_cpu_data.pte_quick) #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) -#if CONFIG_X86_PAE -# include -#else -# include -#endif +#define pmd_populate(mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) /* - * Allocate and free page tables. The xxx_kernel() versions are - * used to allocate a kernel page table - this turns on ASN bits - * if any. + * Allocate and free page tables. */ +#if CONFIG_X86_PAE + +extern void *kmalloc(size_t, int); +extern void kfree(const void *); + extern __inline__ pgd_t *get_pgd_slow(void) { - pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); + int i; + pgd_t *pgd = kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); + + if (pgd) { + for (i = 0; i < USER_PTRS_PER_PGD; i++) { + unsigned long pmd = __get_free_page(GFP_KERNEL); + if (!pmd) + goto out_oom; + clear_page(pmd); + set_pgd(pgd + i, __pgd(1 + __pa(pmd))); + } + memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + return pgd; +out_oom: + for (i--; i >= 0; i--) + free_page((unsigned long)__va(pgd_val(pgd[i])-1)); + kfree(pgd); + return NULL; +} - if (ret) { -#if CONFIG_X86_PAE - int i; - for (i = 0; i < USER_PTRS_PER_PGD; i++) - __pgd_clear(ret + i); #else - memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); -#endif - memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + +extern __inline__ pgd_t *get_pgd_slow(void) +{ + pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL); + + if (pgd) { + memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); + memcpy(pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); } - return ret; + return pgd; } +#endif + extern __inline__ pgd_t *get_pgd_fast(void) { unsigned long *ret; @@ -62,17 +83,32 @@ extern __inline__ void free_pgd_slow(pgd_t *pgd) { +#if CONFIG_X86_PAE + int i; + + for (i = 0; i < USER_PTRS_PER_PGD; i++) + free_page((unsigned long)__va(pgd_val(pgd[i])-1)); + kfree(pgd); +#else free_page((unsigned long)pgd); +#endif } -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; -extern __inline__ pte_t *get_pte_fast(void) + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pte) + clear_page(pte); + return pte; +} + +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; - if((ret = (unsigned long *)pte_quicklist) != NULL) { + if ((ret = (unsigned long *)pte_quicklist) != NULL) { pte_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; pgtable_cache_size--; @@ -80,75 +116,34 @@ return (pte_t *)ret; } -extern __inline__ void free_pte_fast(pte_t *pte) +extern __inline__ void pte_free_fast(pte_t *pte) { *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -extern __inline__ void free_pte_slow(pte_t *pte) +extern __inline__ void pte_free_slow(pte_t *pte) { free_page((unsigned long)pte); } -#define pte_free_kernel(pte) free_pte_slow(pte) -#define pte_free(pte) free_pte_slow(pte) -#define pgd_free(pgd) free_pgd_slow(pgd) -#define pgd_alloc() get_pgd_fast() - -extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) -{ - if (!pmd) - BUG(); - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t * page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_kernel_slow(pmd, address); - set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(page))); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - - if (pmd_none(*pmd)) - goto getnew; - if (pmd_bad(*pmd)) - goto fix; - return (pte_t *)pmd_page(*pmd) + address; -getnew: -{ - unsigned long page = (unsigned long) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(page))); - return (pte_t *)page + address; -} -fix: - __handle_bad_pmd(pmd); - return NULL; -} +#define pte_free(pte) pte_free_slow(pte) +#define pgd_free(pgd) free_pgd_slow(pgd) +#define pgd_alloc() get_pgd_fast() /* * allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. - * (In the PAE case we free the page.) + * (In the PAE case we free the pmds as part of the pgd.) */ -#define pmd_free(pmd) free_pmd_slow(pmd) -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc +#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free_slow(x) do { } while (0) +#define pmd_free_fast(x) do { } while (0) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() extern int do_check_pgt_cache(int, int); diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pgtable-3level.h linux/include/asm-i386/pgtable-3level.h --- v2.4.2/linux/include/asm-i386/pgtable-3level.h Wed Oct 18 14:25:46 2000 +++ linux/include/asm-i386/pgtable-3level.h Sun Mar 25 17:38:31 2001 @@ -33,17 +33,9 @@ #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pgd_val(e)) -/* - * Subtle, in PAE mode we cannot have zeroes in the top level - * page directory, the CPU enforces this. (ie. the PGD entry - * always has to have the present bit set.) The CPU caches - * the 4 pgd entries internally, so there is no extra memory - * load on TLB miss, despite one more level of indirection. - */ -#define EMPTY_PGD (__pa(empty_zero_page) + 1) -#define pgd_none(x) (pgd_val(x) == EMPTY_PGD) +extern inline int pgd_none(pgd_t pgd) { return 0; } extern inline int pgd_bad(pgd_t pgd) { return 0; } -extern inline int pgd_present(pgd_t pgd) { return !pgd_none(pgd); } +extern inline int pgd_present(pgd_t pgd) { return 1; } /* Rules for using set_pte: the pte being assigned *must* be * either not present or in a state where the hardware will @@ -63,21 +55,12 @@ set_64bit((unsigned long long *)(pgdptr),pgd_val(pgdval)) /* - * Pentium-II errata A13: in PAE mode we explicitly have to flush - * the TLB via cr3 if the top-level pgd is changed... This was one tough - * thing to find out - guess i should first read all the documentation - * next time around ;) + * Pentium-II erratum A13: in PAE mode we explicitly have to flush + * the TLB via cr3 if the top-level pgd is changed... + * We do not let the generic code free and clear pgd entries due to + * this erratum. */ -extern inline void __pgd_clear (pgd_t * pgd) -{ - set_pgd(pgd, __pgd(EMPTY_PGD)); -} - -extern inline void pgd_clear (pgd_t * pgd) -{ - __pgd_clear(pgd); - __flush_tlb(); -} +extern inline void pgd_clear (pgd_t * pgd) { } #define pgd_page(pgd) \ ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h --- v2.4.2/linux/include/asm-i386/pgtable.h Sat Feb 3 19:51:31 2001 +++ linux/include/asm-i386/pgtable.h Mon Mar 26 15:48:11 2001 @@ -243,12 +243,6 @@ /* page table for 0-4MB for everybody */ extern unsigned long pg0[1024]; -/* - * Handling allocation failures during page table setup. - */ -extern void __handle_bad_pmd(pmd_t * pmd); -extern void __handle_bad_pmd_kernel(pmd_t * pmd); - #define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE)) #define pte_clear(xp) do { set_pte(xp, __pte(0)); } while (0) 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 Mon Mar 26 15:48:10 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 Mon Mar 26 15:48:10 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); } @@ -549,10 +542,10 @@ { if (!size) return addr; - __asm__("repnz; scasb - jnz 1f - dec %%edi -1: " + __asm__("repnz; scasb\n\t" + "jnz 1f\n\t" + "dec %%edi\n" + "1:" : "=D" (addr), "=c" (size) : "0" (addr), "1" (size), "a" (c)); return addr; diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.4.2/linux/include/asm-i386/system.h Sat Feb 3 19:51:31 2001 +++ linux/include/asm-i386/system.h Mon Mar 26 15:48:11 2001 @@ -144,16 +144,17 @@ extern inline void __set_64bit (unsigned long long * ptr, unsigned int low, unsigned int high) { -__asm__ __volatile__ ( - "1: movl (%0), %%eax; - movl 4(%0), %%edx; - cmpxchg8b (%0); - jnz 1b" - :: "D"(ptr), + __asm__ __volatile__ ( + "\n1:\t" + "movl (%0), %%eax\n\t" + "movl 4(%0), %%edx\n\t" + "cmpxchg8b (%0)\n\t" + "jnz 1b" + : /* no outputs */ + : "D"(ptr), "b"(low), "c"(high) - : - "ax","dx","memory"); + : "ax","dx","memory"); } extern void inline __set_64bit_constant (unsigned long long *ptr, 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/pgalloc.h linux/include/asm-ppc/pgalloc.h --- v2.4.2/linux/include/asm-ppc/pgalloc.h Sat Nov 11 18:23:11 2000 +++ linux/include/asm-ppc/pgalloc.h Mon Mar 26 14:05:23 2001 @@ -52,48 +52,12 @@ extern void __bad_pte(pmd_t *pmd); -/* We don't use pmd cache, so this is a dummy routine */ -extern __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} - -extern __inline__ void free_pmd_fast(pmd_t *pmd) -{ -} - -extern __inline__ void free_pmd_slow(pmd_t *pmd) -{ -} - -/* - * allocating and freeing a pmd is trivial: the 1-entry pmd is - * inside the pgd, so has no extra memory associated with it. - */ -extern inline void pmd_free(pmd_t * pmd) -{ -} - -extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address) -{ - return (pmd_t *) pgd; -} - -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc -#define pte_alloc_kernel pte_alloc - extern __inline__ pgd_t *get_pgd_slow(void) { - pgd_t *ret, *init; - /*if ( (ret = (pgd_t *)get_zero_page_fast()) == NULL )*/ - if ( (ret = (pgd_t *)__get_free_page(GFP_KERNEL)) != NULL ) - memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - if (ret) { - init = pgd_offset(&init_mm, 0); - memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - } + pgd_t *ret; + + if ((ret = (pgd_t *)__get_free_page(GFP_KERNEL)) != NULL) + clear_page(ret); return ret; } @@ -122,9 +86,34 @@ free_page((unsigned long)pgd); } -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); +#define pgd_free(pgd) free_pgd_fast(pgd) +#define pgd_alloc() get_pgd_fast() + +/* + * We don't have any real pmd's, and this code never triggers because + * the pgd will always be present.. + */ +#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); }) +#define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free(x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() + +static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + extern int mem_init_done; + extern void *early_get_page(void); + + if (mem_init_done) + pte = (pte_t *) __get_free_page(GFP_KERNEL); + else + pte = (pte_t *) early_get_page(); + if (pte != NULL) + clear_page(pte); + return pte; +} -extern __inline__ pte_t *get_pte_fast(void) +static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; @@ -136,40 +125,21 @@ return (pte_t *)ret; } -extern __inline__ void free_pte_fast(pte_t *pte) +extern __inline__ void pte_free_fast(pte_t *pte) { *(unsigned long **)pte = pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; } -extern __inline__ void free_pte_slow(pte_t *pte) +extern __inline__ void pte_free_slow(pte_t *pte) { free_page((unsigned long)pte); } -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) -#define pgd_free(pgd) free_pgd_fast(pgd) -#define pgd_alloc() get_pgd_fast() - -extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t * page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - pmd_val(*pmd) = (unsigned long) page; - return page + address; - } - if (pmd_bad(*pmd)) { - __bad_pte(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; -} +#define pte_free(pte) pte_free_slow(pte) + +#define pmd_populate(mm, pmd, pte) (pmd_val(*(pmd)) = (unsigned long) (pte)) extern int do_check_pgt_cache(int, int); 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 Fri Mar 23 22:42:31 2001 @@ -119,20 +119,21 @@ #endif }; -#define __RWSEM_INITIALIZER(name, rd, wr) \ +#define RW_LOCK_BIAS 2 /* XXX bogus */ +#define __RWSEM_INITIALIZER(name, count) \ { \ SPIN_LOCK_UNLOCKED, \ - (rd), (wr), \ + (count) == 1, (count) == 0, \ __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ __SEM_DEBUG_INIT(name) \ } -#define __DECLARE_RWSEM_GENERIC(name, rd, wr) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name, rd, wr) +#define __DECLARE_RWSEM_GENERIC(name, count) \ + struct rw_semaphore name = __RWSEM_INITIALIZER(name, count) -#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(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS) +#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, RW_LOCK_BIAS-1) +#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0) 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/atomic.h linux/include/asm-sparc/atomic.h --- v2.4.2/linux/include/asm-sparc/atomic.h Mon Jan 1 10:37:41 2001 +++ linux/include/asm-sparc/atomic.h Sun Mar 25 18:14:21 2001 @@ -1,6 +1,7 @@ /* atomic.h: These still suck, but the I-cache hit rate is higher. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au) */ #ifndef __ARCH_SPARC_ATOMIC__ @@ -47,51 +48,12 @@ #define atomic_set(v, i) (((v)->counter) = ((i) << 8)) #endif -/* Make sure gcc doesn't try to be clever and move things around - * on us. We need to use _exactly_ the address the user gave us, - * not some alias that contains the same information. - */ -#define __atomic_fool_gcc(x) ((struct { int a[100]; } *)x) - -static __inline__ void atomic_add(int i, atomic_t *v) -{ - register atomic_t *ptr asm("g1"); - register int increment asm("g2"); - ptr = (atomic_t *) __atomic_fool_gcc(v); - increment = i; - - __asm__ __volatile__(" - mov %%o7, %%g4 - call ___atomic_add - add %%o7, 8, %%o7 -" : "=&r" (increment) - : "0" (increment), "r" (ptr) - : "g3", "g4", "g7", "memory", "cc"); -} - -static __inline__ void atomic_sub(int i, atomic_t *v) +static __inline__ int __atomic_add(int i, atomic_t *v) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); register int increment asm("g2"); - ptr = (atomic_t *) __atomic_fool_gcc(v); - increment = i; - - __asm__ __volatile__(" - mov %%o7, %%g4 - call ___atomic_sub - add %%o7, 8, %%o7 -" : "=&r" (increment) - : "0" (increment), "r" (ptr) - : "g3", "g4", "g7", "memory", "cc"); -} - -static __inline__ int atomic_add_return(int i, atomic_t *v) -{ - register atomic_t *ptr asm("g1"); - register int increment asm("g2"); - - ptr = (atomic_t *) __atomic_fool_gcc(v); + ptr = &v->counter; increment = i; __asm__ __volatile__(" @@ -105,12 +67,12 @@ return increment; } -static __inline__ int atomic_sub_return(int i, atomic_t *v) +static __inline__ int __atomic_sub(int i, atomic_t *v) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); register int increment asm("g2"); - ptr = (atomic_t *) __atomic_fool_gcc(v); + ptr = &v->counter; increment = i; __asm__ __volatile__(" @@ -124,16 +86,19 @@ return increment; } -#define atomic_dec_return(v) atomic_sub_return(1,(v)) -#define atomic_inc_return(v) atomic_add_return(1,(v)) +#define atomic_add(i, v) ((void)__atomic_add((i), (v))) +#define atomic_sub(i, v) ((void)__atomic_sub((i), (v))) + +#define atomic_dec_return(v) __atomic_sub(1, (v)) +#define atomic_inc_return(v) __atomic_add(1, (v)) -#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) -#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) +#define atomic_sub_and_test(i, v) (__atomic_sub((i), (v)) == 0) +#define atomic_dec_and_test(v) (__atomic_sub(1, (v)) == 0) -#define atomic_inc(v) atomic_add(1,(v)) -#define atomic_dec(v) atomic_sub(1,(v)) +#define atomic_inc(v) ((void)__atomic_add(1, (v))) +#define atomic_dec(v) ((void)__atomic_sub(1, (v))) -#define atomic_add_negative(i, v) (atomic_add_return((i), (v)) < 0) +#define atomic_add_negative(i, v) (__atomic_add((i), (v)) < 0) #endif /* !(__KERNEL__) */ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc/semaphore.h linux/include/asm-sparc/semaphore.h --- v2.4.2/linux/include/asm-sparc/semaphore.h Mon Jan 1 10:37:41 2001 +++ linux/include/asm-sparc/semaphore.h Sun Mar 25 18:14:21 2001 @@ -64,14 +64,14 @@ static inline void down(struct semaphore * sem) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); register int increment asm("g2"); #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - ptr = (atomic_t *) __atomic_fool_gcc(sem); + ptr = &(sem->count.counter); increment = 1; __asm__ __volatile__(" @@ -99,14 +99,14 @@ static inline int down_interruptible(struct semaphore * sem) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); register int increment asm("g2"); #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - ptr = (atomic_t *) __atomic_fool_gcc(sem); + ptr = &(sem->count.counter); increment = 1; __asm__ __volatile__(" @@ -137,14 +137,14 @@ static inline int down_trylock(struct semaphore * sem) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); register int increment asm("g2"); #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - ptr = (atomic_t *) __atomic_fool_gcc(sem); + ptr = &(sem->count.counter); increment = 1; __asm__ __volatile__(" @@ -175,14 +175,14 @@ static inline void up(struct semaphore * sem) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); register int increment asm("g2"); #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - ptr = (atomic_t *) __atomic_fool_gcc(sem); + ptr = &(sem->count.counter); increment = 1; __asm__ __volatile__(" @@ -284,13 +284,13 @@ static inline void down_read(struct rw_semaphore *sem) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - ptr = (atomic_t *) __atomic_fool_gcc(sem); + ptr = &sem->count; __asm__ __volatile__(" mov %%o7, %%g4 @@ -310,13 +310,13 @@ static inline void down_write(struct rw_semaphore *sem) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif - ptr = (atomic_t *) __atomic_fool_gcc(sem); + ptr = &sem->count; __asm__ __volatile__(" mov %%o7, %%g4 @@ -344,9 +344,9 @@ */ static inline void __up_read(struct rw_semaphore *sem) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); - ptr = (atomic_t *) __atomic_fool_gcc(sem); + ptr = &sem->count; __asm__ __volatile__(" mov %%o7, %%g4 @@ -362,9 +362,9 @@ */ static inline void __up_write(struct rw_semaphore *sem) { - register atomic_t *ptr asm("g1"); + register volatile int *ptr asm("g1"); - ptr = (atomic_t *) __atomic_fool_gcc(sem); + ptr = &sem->count; __asm__ __volatile__(" mov %%o7, %%g4 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: asi.h,v 1.1 1996/11/20 12:59:45 davem Exp $ */ +/* $Id: asi.h,v 1.4 2001/03/15 02:08:46 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_BYPASS_EC_E 0x15 /* PADDR, 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_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, 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_W 0x77 /* 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 */ @@ -72,7 +95,8 @@ #define ASI_UDBL_ERROR_R 0x7f /* External UDB error registers read low */ #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_R 0x7f /* 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/bbc.h linux/include/asm-sparc64/bbc.h --- v2.4.2/linux/include/asm-sparc64/bbc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/bbc.h Sun Mar 25 18:14:21 2001 @@ -0,0 +1,225 @@ +/* $Id: bbc.h,v 1.1 2001/03/24 06:03:03 davem Exp $ + * bbc.h: Defines for BootBus Controller found on UltraSPARC-III + * systems. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +#ifndef _SPARC64_BBC_H +#define _SPARC64_BBC_H + +/* Register sizes are indicated by "B" (Byte, 1-byte), + * "H" (Half-word, 2 bytes), "W" (Word, 4 bytes) or + * "Q" (Quad, 8 bytes) inside brackets. + */ + +#define BBC_AID 0x00 /* [B] Agent ID */ +#define BBC_DEVP 0x01 /* [B] Device Present */ +#define BBC_ARB 0x02 /* [B] Arbitration */ +#define BBC_QUIESCE 0x03 /* [B] Quiesce */ +#define BBC_WDACTION 0x04 /* [B] Watchdog Action */ +#define BBC_SPG 0x06 /* [B] Soft POR Gen */ +#define BBC_SXG 0x07 /* [B] Soft XIR Gen */ +#define BBC_PSRC 0x08 /* [W] POR Source */ +#define BBC_XSRC 0x0c /* [B] XIR Source */ +#define BBC_CSC 0x0d /* [B] Clock Synthesizers Control*/ +#define BBC_ES_CTRL 0x0e /* [H] Energy Star Control */ +#define BBC_ES_ACT 0x10 /* [W] E* Assert Change Time */ +#define BBC_ES_DACT 0x14 /* [B] E* De-Assert Change Time */ +#define BBC_ES_DABT 0x15 /* [B] E* De-Assert Bypass Time */ +#define BBC_ES_ABT 0x16 /* [H] E* Assert Bypass Time */ +#define BBC_ES_PST 0x18 /* [W] E* PLL Settle Time */ +#define BBC_ES_FSL 0x1c /* [W] E* Frequency Switch Latency*/ +#define BBC_EBUST 0x20 /* [Q] EBUS Timing */ +#define BBC_JTAG_CMD 0x28 /* [W] JTAG+ Command */ +#define BBC_JTAG_CTRL 0x2c /* [B] JTAG+ Control */ +#define BBC_I2C_SEL 0x2d /* [B] I2C Selection */ +#define BBC_I2C_0_S1 0x2e /* [B] I2C ctrlr-0 reg S1 */ +#define BBC_I2C_0_S0 0x2f /* [B] I2C ctrlr-0 regs S0,S0',S2,S3*/ +#define BBC_I2C_1_S1 0x30 /* [B] I2C ctrlr-1 reg S1 */ +#define BBC_I2C_1_S0 0x31 /* [B] I2C ctrlr-1 regs S0,S0',S2,S3*/ +#define BBC_KBD_BEEP 0x32 /* [B] Keyboard Beep */ +#define BBC_KBD_BCNT 0x34 /* [W] Keyboard Beep Counter */ + +#define BBC_REGS_SIZE 0x40 + +/* There is a 2K scratch ram area at offset 0x80000 but I doubt + * we will use it for anything. + */ + +/* Agent ID register. This register shows the Safari Agent ID + * for the processors. The value returned depends upon which + * cpu is reading the register. + */ +#define BBC_AID_ID 0x07 /* Safari ID */ +#define BBC_AID_RESV 0xf8 /* Reserved */ + +/* Device Present register. One can determine which cpus are actually + * present in the machine by interrogating this register. + */ +#define BBC_DEVP_CPU0 0x01 /* Processor 0 present */ +#define BBC_DEVP_CPU1 0x02 /* Processor 1 present */ +#define BBC_DEVP_CPU2 0x04 /* Processor 2 present */ +#define BBC_DEVP_CPU3 0x08 /* Processor 3 present */ +#define BBC_DEVP_RESV 0xf0 /* Reserved */ + +/* Arbitration register. This register is used to block access to + * the BBC from a particular cpu. + */ +#define BBC_ARB_CPU0 0x01 /* Enable cpu 0 BBC arbitratrion */ +#define BBC_ARB_CPU1 0x02 /* Enable cpu 1 BBC arbitratrion */ +#define BBC_ARB_CPU2 0x04 /* Enable cpu 2 BBC arbitratrion */ +#define BBC_ARB_CPU3 0x08 /* Enable cpu 3 BBC arbitratrion */ +#define BBC_ARB_RESV 0xf0 /* Reserved */ + +/* Quiesce register. Bus and BBC segments for cpus can be disabled + * with this register, ie. for hot plugging. + */ +#define BBC_QUIESCE_S02 0x01 /* Quiesce Safari segment for cpu 0 and 2 */ +#define BBC_QUIESCE_S13 0x02 /* Quiesce Safari segment for cpu 1 and 3 */ +#define BBC_QUIESCE_B02 0x04 /* Quiesce BBC segment for cpu 0 and 2 */ +#define BBC_QUIESCE_B13 0x08 /* Quiesce BBC segment for cpu 1 and 3 */ +#define BBC_QUIESCE_FD0 0x10 /* Disable Fatal_Error[0] reporting */ +#define BBC_QUIESCE_FD1 0x20 /* Disable Fatal_Error[1] reporting */ +#define BBC_QUIESCE_FD2 0x40 /* Disable Fatal_Error[2] reporting */ +#define BBC_QUIESCE_FD3 0x80 /* Disable Fatal_Error[3] reporting */ + +/* Watchdog Action register. When the watchdog device timer expires + * a line is enabled to the BBC. The action BBC takes when this line + * is asserted can be controlled by this regiser. + */ +#define BBC_WDACTION_RST 0x01 /* When set, watchdog causes system reset. + * When clear, all cpus receive XIR reset. + */ +#define BBC_WDACTION_RESV 0xfe /* Reserved */ + +/* Soft_POR_GEN register. The POR (Power On Reset) signal may be asserted + * for specific processors or all processors via this register. + */ +#define BBC_SPG_CPU0 0x01 /* Assert POR for processor 0 */ +#define BBC_SPG_CPU1 0x02 /* Assert POR for processor 1 */ +#define BBC_SPG_CPU2 0x04 /* Assert POR for processor 2 */ +#define BBC_SPG_CPU3 0x08 /* Assert POR for processor 3 */ +#define BBC_SPG_CPUALL 0x10 /* Reset all processors and reset + * the entire system. + */ +#define BBC_SPG_RESV 0xe0 /* Reserved */ + +/* Soft_XIR_GEN register. The XIR (eXternally Initiated Reset) signal + * may be asserted to specific processors via this register. + */ +#define BBC_SXG_CPU0 0x01 /* Assert XIR for processor 0 */ +#define BBC_SXG_CPU1 0x02 /* Assert XIR for processor 1 */ +#define BBC_SXG_CPU2 0x04 /* Assert XIR for processor 2 */ +#define BBC_SXG_CPU3 0x08 /* Assert XIR for processor 3 */ +#define BBC_SXG_RESV 0xf0 /* Reserved */ + +/* POR Source register. One may identify the cause of the most recent + * reset by reading this register. + */ +#define BBC_PSRC_SPG0 0x0001 /* CPU 0 reset via BBC_SPG register */ +#define BBC_PSRC_SPG1 0x0002 /* CPU 1 reset via BBC_SPG register */ +#define BBC_PSRC_SPG2 0x0004 /* CPU 2 reset via BBC_SPG register */ +#define BBC_PSRC_SPG3 0x0008 /* CPU 3 reset via BBC_SPG register */ +#define BBC_PSRC_SPGSYS 0x0010 /* System reset via BBC_SPG register */ +#define BBC_PSRC_JTAG 0x0020 /* System reset via JTAG+ */ +#define BBC_PSRC_BUTTON 0x0040 /* System reset via push-button dongle */ +#define BBC_PSRC_PWRUP 0x0080 /* System reset via power-up */ +#define BBC_PSRC_FE0 0x0100 /* CPU 0 reported Fatal_Error */ +#define BBC_PSRC_FE1 0x0200 /* CPU 1 reported Fatal_Error */ +#define BBC_PSRC_FE2 0x0400 /* CPU 2 reported Fatal_Error */ +#define BBC_PSRC_FE3 0x0800 /* CPU 3 reported Fatal_Error */ +#define BBC_PSRC_FE4 0x1000 /* Schizo reported Fatal_Error */ +#define BBC_PSRC_FE5 0x2000 /* Safari device 5 reported Fatal_Error */ +#define BBC_PSRC_FE6 0x4000 /* CPMS reported Fatal_Error */ +#define BBC_PSRC_SYNTH 0x8000 /* System reset when on-board clock synthesizers + * were updated. + */ +#define BBC_PSRC_WDT 0x10000 /* System reset via Super I/O watchdog */ +#define BBC_PSRC_RSC 0x20000 /* System reset via RSC remote monitoring + * device + */ + +/* XIR Source register. The source of an XIR event sent to a processor may + * be determined via this register. + */ +#define BBC_XSRC_SXG0 0x01 /* CPU 0 received XIR via Soft_XIR_GEN reg */ +#define BBC_XSRC_SXG1 0x02 /* CPU 1 received XIR via Soft_XIR_GEN reg */ +#define BBC_XSRC_SXG2 0x04 /* CPU 2 received XIR via Soft_XIR_GEN reg */ +#define BBC_XSRC_SXG3 0x08 /* CPU 3 received XIR via Soft_XIR_GEN reg */ +#define BBC_XSRC_JTAG 0x10 /* All CPUs received XIR via JTAG+ */ +#define BBC_XSRC_W_OR_B 0x20 /* All CPUs received XIR either because: + * a) Super I/O watchdog fired, or + * b) XIR push button was activated + */ +#define BBC_XSRC_RESV 0xc0 /* Reserved */ + +/* Clock Synthesizers Control register. This register provides the big-bang + * programming interface to the two clock synthesizers of the machine. + */ +#define BBC_CSC_SLOAD 0x01 /* Directly connected to S_LOAD pins */ +#define BBC_CSC_SDATA 0x02 /* Directly connected to S_DATA pins */ +#define BBC_CSC_SCLOCK 0x04 /* Directly connected to S_CLOCK pins */ +#define BBC_CSC_RESV 0x78 /* Reserved */ +#define BBC_CSC_RST 0x80 /* Generate system reset when S_LOAD==1 */ + +/* Energy Star Control register. This register is used to generate the + * clock frequency change trigger to the main system devices (Schizo and + * the processors). The transition occurs when bits in this register + * go from 0 to 1, only one bit must be set at once else no action + * occurs. Basically the sequence of events is: + * a) Choose new frequency: full, 1/2 or 1/32 + * b) Program this desired frequency into the cpus and Schizo. + * c) Set the same value in this register. + * d) 16 system clocks later, clear this register. + */ +#define BBC_ES_CTRL_1_1 0x01 /* Full frequency */ +#define BBC_ES_CTRL_1_2 0x02 /* 1/2 frequency */ +#define BBC_ES_CTRL_1_32 0x20 /* 1/32 frequency */ +#define BBC_ES_RESV 0xdc /* Reserved */ + +/* Energy Star Assert Change Time register. This determines the number + * of BBC clock cycles (which is half the system frequency) between + * the detection of FREEZE_ACK being asserted and the assertion of + * the CLK_CHANGE_L[2:0] signals. + */ +#define BBC_ES_ACT_VAL 0xff + +/* Energy Star Assert Bypass Time register. This determines the number + * of BBC clock cycles (which is half the system frequency) between + * the assertion of the CLK_CHANGE_L[2:0] signals and the assertion of + * the ESTAR_PLL_BYPASS signal. + */ +#define BBC_ES_ABT_VAL 0xffff + +/* Energy Star PLL Settle Time register. This determines the number of + * BBC clock cycles (which is half the system frequency) between the + * de-assertion of CLK_CHANGE_L[2:0] and the de-assertion of the FREEZE_L + * signal. + */ +#define BBC_ES_PST_VAL 0xffffffff + +/* Energy Star Frequency Switch Latency register. This is the number of + * BBC clocks between the de-assertion of CLK_CHANGE_L[2:0] and the first + * edge of the Safari clock at the new frequency. + */ +#define BBC_ES_FSL_VAL 0xffffffff + +/* Keyboard Beep control register. This is a simple enabler for the audio + * beep sound. + */ +#define BBC_KBD_BEEP_ENABLE 0x01 /* Enable beep */ +#define BBC_KBD_BEEP_RESV 0xfe /* Reserved */ + +/* Keyboard Beep Counter register. There is a free-running counter inside + * the BBC which runs at half the system clock. The bit set in this register + * determines when the audio sound is generated. So for example if bit + * 10 is set, the audio beep will oscillate at 1/(2**12). The keyboard beep + * generator automatically selects a different bit to use if the system clock + * is changed via Energy Star. + */ +#define BBC_KBD_BCNT_BITS 0x0007fc00 +#define BBC_KBC_BCNT_RESV 0xfff803ff + +#endif /* _SPARC64_BBC_H */ + 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 Sun Mar 25 18:14:21 2001 @@ -0,0 +1,13 @@ +/* $Id: dcr.h,v 1.4 2001/03/09 17:56:37 davem Exp $ */ +#ifndef _SPARC64_DCR_H +#define _SPARC64_DCR_H + +/* UltraSparc-III Dispatch Control Register, ASR 0x12 */ +#define DCR_OBS 0x0000000000000fc0 /* Observability Bus Controls */ +#define DCR_BPE 0x0000000000000020 /* Branch Predict Enable */ +#define DCR_RPE 0x0000000000000010 /* Return Address Prediction Enable */ +#define DCR_SI 0x0000000000000008 /* Single Instruction Disable */ +#define DCR_IFPOE 0x0000000000000002 /* IRQ FP Operation Enable */ +#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/ebus.h linux/include/asm-sparc64/ebus.h --- v2.4.2/linux/include/asm-sparc64/ebus.h Tue Aug 31 11:23:30 1999 +++ linux/include/asm-sparc64/ebus.h Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: ebus.h,v 1.9 1999/08/30 10:14:37 davem Exp $ +/* $Id: ebus.h,v 1.10 2001/03/14 05:00:55 davem Exp $ * ebus.h: PCI to Ebus pseudo driver software state. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -41,6 +41,7 @@ struct pci_pbm_info *parent; struct pci_dev *self; int index; + int is_rio; int prom_node; char prom_name[64]; struct linux_prom_ebus_ranges ebus_ranges[PROMREG_MAX]; diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h --- v2.4.2/linux/include/asm-sparc64/elf.h Wed Jul 12 16:45:30 2000 +++ linux/include/asm-sparc64/elf.h Mon Mar 26 11:00:29 2001 @@ -1,4 +1,4 @@ -/* $Id: elf.h,v 1.25 2000/07/12 01:27:08 davem Exp $ */ +/* $Id: elf.h,v 1.28 2001/03/24 09:36:02 davem Exp $ */ #ifndef __ASM_SPARC64_ELF_H #define __ASM_SPARC64_ELF_H @@ -56,9 +56,10 @@ instruction set this cpu supports. */ /* On Ultra, we support all of the v8 capabilities. */ -#define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \ - HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \ - HWCAP_SPARC_V9) +#define ELF_HWCAP ((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \ + HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \ + HWCAP_SPARC_V9) | \ + ((tlb_type == cheetah) ? HWCAP_SPARC_ULTRA3 : 0)) /* This yields a string that ld.so will use to load implementation specific libraries for optimization. This is more specific in @@ -78,16 +79,16 @@ if (flags & SPARC_FLAG_32BIT) { \ pgd_t *pgd0 = ¤t->mm->pgd[0]; \ if (pgd_none (*pgd0)) { \ - pmd_t *page = get_pmd_fast(); \ + pmd_t *page = pmd_alloc_one_fast(NULL, 0); \ if (!page) \ - (void) get_pmd_slow(pgd0, 0); \ - else \ - pgd_set(pgd0, page); \ + page = pmd_alloc_one(NULL, 0); \ + pgd_set(pgd0, page); \ } \ pgd_cache = pgd_val(*pgd0) << 11UL; \ } \ __asm__ __volatile__( \ - "stxa\t%0, [%1] %2" \ + "stxa\t%0, [%1] %2\n\t" \ + "membar #Sync" \ : /* no outputs */ \ : "r" (pgd_cache), \ "r" (TSB_REG), \ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h --- v2.4.2/linux/include/asm-sparc64/floppy.h Fri Feb 18 15:07:20 2000 +++ linux/include/asm-sparc64/floppy.h Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: floppy.h,v 1.28 2000/02/18 13:50:54 davem Exp $ +/* $Id: floppy.h,v 1.29 2001/03/24 00:07:23 davem Exp $ * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -565,6 +565,24 @@ #endif /* CONFIG_PCI */ +#ifdef CONFIG_PCI +static int __init ebus_fdthree_p(struct linux_ebus_device *edev) +{ + if (!strcmp(edev->prom_name, "fdthree")) + return 1; + if (!strcmp(edev->prom_name, "floppy")) { + char compat[16]; + prom_getstring(edev->prom_node, + "compatible", + compat, sizeof(compat)); + compat[15] = '\0'; + if (!strcmp(compat, "fdthree")) + return 1; + } + return 0; +} +#endif + static unsigned long __init sun_floppy_init(void) { char state[128]; @@ -592,7 +610,7 @@ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "fdthree")) + if (ebus_fdthree_p(edev)) goto ebus_done; } } diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/iommu.h linux/include/asm-sparc64/iommu.h --- v2.4.2/linux/include/asm-sparc64/iommu.h Mon Dec 20 22:05:52 1999 +++ linux/include/asm-sparc64/iommu.h Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: iommu.h,v 1.9 1999/09/21 14:39:39 davem Exp $ +/* $Id: iommu.h,v 1.10 2001/03/08 09:55:56 davem Exp $ * iommu.h: Definitions for the sun5 IOMMU. * * Copyright (C) 1996, 1999 David S. Miller (davem@caip.rutgers.edu) @@ -12,7 +12,7 @@ #define IOPTE_STBUF 0x1000000000000000 /* DVMA can use streaming buffer */ #define IOPTE_INTRA 0x0800000000000000 /* SBUS slot-->slot direct transfer */ #define IOPTE_CONTEXT 0x07ff800000000000 /* Context number */ -#define IOPTE_PAGE 0x00007fffffffe000 /* Physical page number (PA[40:13]) */ +#define IOPTE_PAGE 0x00007fffffffe000 /* Physical page number (PA[42:13]) */ #define IOPTE_CACHE 0x0000000000000010 /* Cached (in UPA E-cache) */ #define IOPTE_WRITE 0x0000000000000002 /* Writeable */ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/irq.h linux/include/asm-sparc64/irq.h --- v2.4.2/linux/include/asm-sparc64/irq.h Wed Jul 5 12:14:54 2000 +++ linux/include/asm-sparc64/irq.h Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.h,v 1.19 2000/06/26 19:40:27 davem Exp $ +/* $Id: irq.h,v 1.20 2001/03/09 01:31:40 davem Exp $ * irq.h: IRQ registers on the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -77,7 +77,9 @@ /* IMAP/ICLR register defines */ #define IMAP_VALID 0x80000000 /* IRQ Enabled */ -#define IMAP_TID 0x7c000000 /* UPA TargetID */ +#define IMAP_TID_UPA 0x7c000000 /* UPA TargetID */ +#define IMAP_AID_SAFARI 0x7c000000 /* Safari AgentID */ +#define IMAP_NID_SAFARI 0x03e00000 /* Safari NodeID */ #define IMAP_IGN 0x000007c0 /* IRQ Group Number */ #define IMAP_INO 0x0000003f /* IRQ Number */ #define IMAP_INR 0x000007ff /* Full interrupt number*/ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/mc146818rtc.h linux/include/asm-sparc64/mc146818rtc.h --- v2.4.2/linux/include/asm-sparc64/mc146818rtc.h Tue Jul 18 23:05:09 2000 +++ linux/include/asm-sparc64/mc146818rtc.h Sun Mar 25 18:14:21 2001 @@ -7,8 +7,13 @@ #include #ifndef RTC_PORT -#define RTC_PORT(x) (0x70 + (x)) -#define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */ +#ifdef CONFIG_PCI +extern unsigned long ds1287_regs; +#else +#define ds1287_regs (0UL) +#endif +#define RTC_PORT(x) (ds1287_regs + (x)) +#define RTC_ALWAYS_BCD 0 #endif /* diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h --- v2.4.2/linux/include/asm-sparc64/mmu_context.h Sat Aug 12 12:08:50 2000 +++ linux/include/asm-sparc64/mmu_context.h Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: mmu_context.h,v 1.45 2000/08/12 13:25:52 davem Exp $ */ +/* $Id: mmu_context.h,v 1.47 2001/03/22 07:26:04 davem Exp $ */ #ifndef __SPARC64_MMU_CONTEXT_H #define __SPARC64_MMU_CONTEXT_H @@ -72,6 +72,7 @@ "mov %3, %%g4\n\t" \ "mov %0, %%g7\n\t" \ "stxa %1, [%%g4] %2\n\t" \ + "membar #Sync\n\t" \ "wrpr %%g0, 0x096, %%pstate" \ : /* no outputs */ \ : "r" (paddr), "r" (pgd_cache),\ @@ -84,18 +85,9 @@ "flush %%g6" \ : /* No outputs */ \ : "r" (CTX_HWBITS((__mm)->context)), \ - "r" (0x10), "i" (0x58)) + "r" (0x10), "i" (ASI_DMMU)) -/* Clean out potential stale TLB entries due to previous - * users of this TLB context. We flush TLB contexts - * lazily on sparc64. - */ -#define clean_secondary_context() \ - __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" \ - "stxa %%g0, [%0] %2\n\t" \ - "flush %%g6" \ - : /* No outputs */ \ - : "r" (0x50), "i" (0x5f), "i" (0x57)) +extern void __flush_tlb_mm(unsigned long, unsigned long); /* Switch the current MM context. */ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu) @@ -127,7 +119,7 @@ */ if (!ctx_valid || !(mm->cpu_vm_mask & vm_mask)) { mm->cpu_vm_mask |= vm_mask; - clean_secondary_context(); + __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT); } } spin_unlock(&mm->page_table_lock); @@ -147,7 +139,7 @@ spin_unlock(&mm->page_table_lock); load_secondary_context(mm); - clean_secondary_context(); + __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT); reload_tlbmiss_state(current, mm); } diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/openprom.h linux/include/asm-sparc64/openprom.h --- v2.4.2/linux/include/asm-sparc64/openprom.h Sun Aug 13 12:01:54 2000 +++ linux/include/asm-sparc64/openprom.h Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: openprom.h,v 1.8 2000/08/12 19:55:25 anton Exp $ */ +/* $Id: openprom.h,v 1.9 2001/03/16 10:22:02 davem Exp $ */ #ifndef __SPARC64_OPENPROM_H #define __SPARC64_OPENPROM_H @@ -202,6 +202,12 @@ unsigned int ot_parent_space; unsigned int ot_parent_base; /* CPU looks from here */ unsigned int or_size; +}; + +struct linux_prom64_ranges { + unsigned long ot_child_base; /* Bus feels this */ + unsigned long ot_parent_base; /* CPU looks from here */ + unsigned long or_size; }; /* Ranges and reg properties are a bit different for PCI. */ diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/parport.h linux/include/asm-sparc64/parport.h --- v2.4.2/linux/include/asm-sparc64/parport.h Thu Mar 16 11:20:33 2000 +++ linux/include/asm-sparc64/parport.h Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: parport.h,v 1.9 2000/03/16 07:47:27 davem Exp $ +/* $Id: parport.h,v 1.10 2001/03/24 00:18:57 davem Exp $ * parport.h: sparc64 specific parport initialization and dma. * * Copyright (C) 1999 Eddie C. Dost (ecd@skynet.be) @@ -99,6 +99,25 @@ return res; } +static int ebus_ecpp_p(struct linux_ebus_device *edev) +{ + if (!strcmp(edev->prom_name, "ecpp")) + return 1; + if (!strcmp(edev->prom_name, "parallel")) { + char compat[19]; + prom_getstring(edev->prom_node, + "compatible", + compat, sizeof(compat)); + compat[18] = '\0'; + if (!strcmp(compat, "ecpp")) + return 1; + if (!strcmp(compat, "ns87317-ecpp") && + !strcmp(compat + 13, "ecpp")) + return 1; + } + return 0; +} + static int parport_pc_find_nonpci_ports (int autoirq, int autodma) { struct linux_ebus *ebus; @@ -110,7 +129,7 @@ for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, "ecpp")) { + if (ebus_ecpp_p(edev)) { unsigned long base = edev->resource[0].start; unsigned long config = edev->resource[1].start; 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 Mon Mar 26 11:03:48 2001 @@ -1,4 +1,4 @@ -/* $Id: pgalloc.h,v 1.14 2000/12/09 04:15:24 anton Exp $ */ +/* $Id: pgalloc.h,v 1.18 2001/03/24 09:36:01 davem Exp $ */ #ifndef _SPARC64_PGALLOC_H #define _SPARC64_PGALLOC_H @@ -22,18 +22,22 @@ #define flush_page_to_ram(page) do { } while (0) /* - * icache doesnt snoop local stores and we don't use block commit stores - * (which invalidate icache lines) during module load, so we need this. + * On spitfire, the icache doesn't snoop local stores and we don't + * use block commit stores (which invalidate icache lines) during + * module load, so we need this. */ extern void flush_icache_range(unsigned long start, unsigned long end); extern void __flush_dcache_page(void *addr, int flush_icache); #define flush_dcache_page(page) \ -do { if ((page)->mapping && !(page)->mapping->i_mmap && !(page)->mapping->i_mmap_shared) \ +do { if ((page)->mapping && \ + !((page)->mapping->i_mmap) && \ + !((page)->mapping->i_mmap_shared)) \ set_bit(PG_dcache_dirty, &(page)->flags); \ else \ __flush_dcache_page((page)->virtual, \ - (page)->mapping != NULL); \ + ((tlb_type == spitfire) && \ + (page)->mapping != NULL)); \ } while(0) extern void __flush_dcache_range(unsigned long start, unsigned long end); @@ -93,14 +97,18 @@ #endif /* ! CONFIG_SMP */ -/* This will change for Cheetah and later chips. */ -#define VPTE_BASE 0xfffffffe00000000 +#define VPTE_BASE_SPITFIRE 0xfffffffe00000000 +#if 1 +#define VPTE_BASE_CHEETAH VPTE_BASE_SPITFIRE +#else +#define VPTE_BASE_CHEETAH 0xffe0000000000000 +#endif 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,10 +118,15 @@ 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))); } +#undef VPTE_BASE_SPITFIRE +#undef VPTE_BASE_CHEETAH /* Page table allocation/freeing. */ #ifdef CONFIG_SMP @@ -214,9 +227,17 @@ #endif /* CONFIG_SMP */ -extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked); +#define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) + +extern __inline__ pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *pmd = (pmd_t *)__get_free_page(GFP_KERNEL); + if (pmd) + memset(pmd, 0, PAGE_SIZE); + return pmd; +} -extern __inline__ pmd_t *get_pmd_fast(void) +extern __inline__ pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address) { unsigned long *ret; int color = 0; @@ -246,11 +267,13 @@ free_page((unsigned long)pmd); } -extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted, - unsigned long color); +#define pmd_populate(MM, PMD, PTE) pmd_set(PMD, PTE) + +extern pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address); -extern __inline__ pte_t *get_pte_fast(unsigned long color) +extern __inline__ pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) { + unsigned long color = (address >> (PAGE_SHIFT + 10)) & 0x1UL; unsigned long *ret; if((ret = (unsigned long *)pte_quicklist[color]) != NULL) { @@ -274,45 +297,10 @@ free_page((unsigned long)pte); } -#define pte_free_kernel(pte) free_pte_fast(pte) #define pte_free(pte) free_pte_fast(pte) -#define pmd_free_kernel(pmd) free_pmd_fast(pmd) #define pmd_free(pmd) free_pmd_fast(pmd) #define pgd_free(pgd) free_pgd_fast(pgd) #define pgd_alloc() get_pgd_fast() - -extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - /* Be careful, address can be just about anything... */ - unsigned long color = (((unsigned long)pmd)>>2UL) & 0x1UL; - pte_t *page = get_pte_fast(color); - - if (!page) - return get_pte_slow(pmd, address, color); - pmd_set(pmd, page); - return page + address; - } - return (pte_t *) pmd_page(*pmd) + address; -} - -extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address) -{ - address = (address >> PMD_SHIFT) & (REAL_PTRS_PER_PMD - 1); - if (pgd_none(*pgd)) { - pmd_t *page = get_pmd_fast(); - - if (!page) - return get_pmd_slow(pgd, address); - pgd_set(pgd, page); - return page + address; - } - return (pmd_t *) pgd_page(*pgd) + address; -} - -#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr) -#define pmd_alloc_kernel(pgd, addr) pmd_alloc(pgd, addr) extern int do_check_pgt_cache(int, int); 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.135 2000/11/08 04:49:24 davem Exp $ +/* $Id: pgtable.h,v 1.138 2001/03/08 09:55:56 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -27,6 +27,11 @@ */ #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) +/* XXX All of this needs to be rethought so we can take advantage + * XXX cheetah's full 64-bit virtual address space, ie. no more hole + * XXX in the middle like on spitfire. -DaveM + */ + /* PMD_SHIFT determines the size of the area a second-level page table can map */ #define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3)) #define PMD_SIZE (1UL << PMD_SHIFT) @@ -70,7 +75,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 +84,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 /* (Cheetah) 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/processor.h linux/include/asm-sparc64/processor.h --- v2.4.2/linux/include/asm-sparc64/processor.h Mon Jan 1 10:37:41 2001 +++ linux/include/asm-sparc64/processor.h Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.68 2000/12/31 10:05:43 davem Exp $ +/* $Id: processor.h,v 1.69 2001/03/08 22:08:51 davem Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -60,8 +60,7 @@ /* D$ line 2, 3, 4 */ struct pt_regs *kregs; unsigned long *utraps; - unsigned char gsr[7]; - unsigned char __pad3; + unsigned long gsr[7]; unsigned long xfsr[7]; struct reg_window reg_window[NSWINS]; @@ -97,8 +96,8 @@ 0, 0, 0, 0, \ /* fault_address, fpsaved, __pad2, kregs, */ \ 0, { 0 }, 0, 0, \ -/* utraps, gsr, __pad3, xfsr, */ \ - 0, { 0 }, 0, { 0 }, \ +/* utraps, gsr, xfsr, */ \ + 0, { 0 }, { 0 }, \ /* reg_window */ \ { { { 0, }, { 0, } }, }, \ /* rwbuf_stkptrs */ \ 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 Sun Mar 25 18:14:21 2001 @@ -10,6 +10,7 @@ #include #include #include +#include #ifndef __ASSEMBLY__ /* PROM provided per-processor information we need @@ -60,6 +61,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. @@ -83,7 +85,13 @@ extern __inline__ int hard_smp_processor_id(void) { - if(this_is_starfire != 0) { + if (tlb_type == cheetah) { + unsigned long safari_config; + __asm__ __volatile__("ldxa [%%g0] %1, %0" + : "=r" (safari_config) + : "i" (ASI_SAFARI_CONFIG)); + return ((safari_config >> 17) & 0x3ff); + } else if (this_is_starfire != 0) { return starfire_hard_smp_processor_id(); } else { unsigned long upaconfig; 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 Sun Mar 25 18:14:21 2001 @@ -1,4 +1,4 @@ -/* $Id: spitfire.h,v 1.10 2000/10/06 13:10:29 anton Exp $ +/* $Id: spitfire.h,v 1.14 2001/03/22 07:26:04 davem Exp $ * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -29,6 +29,23 @@ #ifndef __ASSEMBLY__ +enum ultra_tlb_layout { + spitfire = 0, + cheetah = 1 +}; + +extern enum ultra_tlb_layout tlb_type; + +#define SPARC64_USE_STICK (tlb_type == cheetah) + +#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; @@ -61,13 +78,17 @@ extern __inline__ void spitfire_put_isfsr(unsigned long sfsr) { - __asm__ __volatile__("stxa %0, [%1] %2" : + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ : "r" (sfsr), "r" (TLB_SFSR), "i" (ASI_IMMU)); } extern __inline__ void spitfire_put_dsfsr(unsigned long sfsr) { - __asm__ __volatile__("stxa %0, [%1] %2" : + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ : "r" (sfsr), "r" (TLB_SFSR), "i" (ASI_DMMU)); } @@ -83,11 +104,12 @@ extern __inline__ void spitfire_set_primary_context(unsigned long ctx) { - __asm__ __volatile__("stxa %0, [%1] %2" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : /* No outputs */ : "r" (ctx & 0x3ff), "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU)); - membar("#Sync"); + __asm__ __volatile__ ("membar #Sync" : : : "memory"); } extern __inline__ unsigned long spitfire_get_secondary_context(void) @@ -102,11 +124,12 @@ extern __inline__ void spitfire_set_secondary_context(unsigned long ctx) { - __asm__ __volatile__("stxa %0, [%1] %2" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : /* No outputs */ : "r" (ctx & 0x3ff), "r" (SECONDARY_CONTEXT), "i" (ASI_DMMU)); - membar("#Sync"); + __asm__ __volatile__ ("membar #Sync" : : : "memory"); } /* The data cache is write through, so this just invalidates the @@ -114,10 +137,11 @@ */ extern __inline__ void spitfire_put_dcache_tag(unsigned long addr, unsigned long tag) { - __asm__ __volatile__("stxa %0, [%1] %2" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : /* No outputs */ : "r" (tag), "r" (addr), "i" (ASI_DCACHE_TAG)); - membar("#Sync"); + __asm__ __volatile__ ("membar #Sync" : : : "memory"); } /* The instruction cache lines are flushed with this, but note that @@ -128,7 +152,8 @@ */ extern __inline__ void spitfire_put_icache_tag(unsigned long addr, unsigned long tag) { - __asm__ __volatile__("stxa %0, [%1] %2" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : /* No outputs */ : "r" (tag), "r" (addr), "i" (ASI_IC_TAG)); } @@ -140,6 +165,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; } @@ -155,7 +184,8 @@ extern __inline__ void spitfire_put_dtlb_data(int entry, unsigned long data) { - __asm__ __volatile__("stxa %0, [%1] %2" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : /* No outputs */ : "r" (data), "r" (entry << 3), "i" (ASI_DTLB_DATA_ACCESS)); @@ -168,6 +198,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; } @@ -183,7 +217,8 @@ extern __inline__ void spitfire_put_itlb_data(int entry, unsigned long data) { - __asm__ __volatile__("stxa %0, [%1] %2" + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" : /* No outputs */ : "r" (data), "r" (entry << 3), "i" (ASI_ITLB_DATA_ACCESS)); @@ -194,42 +229,48 @@ /* Context level flushes. */ extern __inline__ void spitfire_flush_dtlb_primary_context(void) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (0x40), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_primary_context(void) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (0x40), "i" (ASI_IMMU_DEMAP)); } extern __inline__ void spitfire_flush_dtlb_secondary_context(void) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (0x50), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_secondary_context(void) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (0x50), "i" (ASI_IMMU_DEMAP)); } extern __inline__ void spitfire_flush_dtlb_nucleus_context(void) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (0x60), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_nucleus_context(void) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (0x60), "i" (ASI_IMMU_DEMAP)); } @@ -237,44 +278,207 @@ /* Page level flushes. */ extern __inline__ void spitfire_flush_dtlb_primary_page(unsigned long page) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (page), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_primary_page(unsigned long page) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (page), "i" (ASI_IMMU_DEMAP)); } extern __inline__ void spitfire_flush_dtlb_secondary_page(unsigned long page) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (page | 0x10), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_secondary_page(unsigned long page) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (page | 0x10), "i" (ASI_IMMU_DEMAP)); } extern __inline__ void spitfire_flush_dtlb_nucleus_page(unsigned long page) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* No outputs */ : "r" (page | 0x20), "i" (ASI_DMMU_DEMAP)); } extern __inline__ void spitfire_flush_itlb_nucleus_page(unsigned long page) { - __asm__ __volatile__("stxa %%g0, [%0] %1" + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" : /* 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\n\t" + "membar #Sync" + : /* No outputs */ + : "r" (0x80), "i" (ASI_DMMU_DEMAP)); +} + +extern __inline__ void cheetah_flush_itlb_all(void) +{ + __asm__ __volatile__("stxa %%g0, [%0] %1\n\t" + "membar #Sync" + : /* 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\n\t" + "membar #Sync" + : /* 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\n\t" + "membar #Sync" + : /* 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\n\t" + "membar #Sync" + : /* 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\n\t" + "membar #Sync" + : /* 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/b1lli.h linux/include/linux/b1lli.h --- v2.4.2/linux/include/linux/b1lli.h Thu Aug 12 09:42:33 1999 +++ linux/include/linux/b1lli.h Mon Mar 26 15:38:19 2001 @@ -1,11 +1,14 @@ /* - * $Id: b1lli.h,v 1.8 1999/07/01 15:26:54 calle Exp $ + * $Id: b1lli.h,v 1.8.8.1 2001/03/15 09:58:30 kai Exp $ * * ISDN lowlevel-module for AVM B1-card. * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1lli.h,v $ + * Revision 1.8.8.1 2001/03/15 09:58:30 kai + * spelling fix + * * Revision 1.8 1999/07/01 15:26:54 calle * complete new version (I love it): * + new hardware independed "capi_driver" interface that will make it easy to: @@ -129,7 +132,7 @@ #define AVMB1_LOAD_AND_CONFIG 3 /* load image and config to card */ #define AVMB1_ADDCARD_WITH_TYPE 4 /* add a new card, with cardtype */ #define AVMB1_GET_CARDINFO 5 /* get cardtype */ -#define AVMB1_REMOVECARD 6 /* remove a card (usefull for T1) */ +#define AVMB1_REMOVECARD 6 /* remove a card (useful for T1) */ #define AVMB1_REGISTERCARD_IS_OBSOLETE 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 Mon Mar 26 15:48:13 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/cdrom.h linux/include/linux/cdrom.h --- v2.4.2/linux/include/linux/cdrom.h Thu Jan 4 14:50:47 2001 +++ linux/include/linux/cdrom.h Mon Mar 26 15:48:11 2001 @@ -524,10 +524,12 @@ __u32 end_sector_l0; }; +#define DVD_LAYERS 4 + struct dvd_physical { __u8 type; __u8 layer_num; - struct dvd_layer layer[4]; + struct dvd_layer layer[DVD_LAYERS]; }; struct dvd_copyright { 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 Mon Mar 26 15:48:10 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/elf.h linux/include/linux/elf.h --- v2.4.2/linux/include/linux/elf.h Wed Feb 21 18:20:45 2001 +++ linux/include/linux/elf.h Mon Mar 26 15:49:13 2001 @@ -299,7 +299,7 @@ #define HWCAP_SPARC_SWAP 4 #define HWCAP_SPARC_MULDIV 8 #define HWCAP_SPARC_V9 16 - +#define HWCAP_SPARC_ULTRA3 32 /* * 68k ELF relocation types diff -u --recursive --new-file v2.4.2/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h --- v2.4.2/linux/include/linux/etherdevice.h Fri Oct 27 12:22:34 2000 +++ linux/include/linux/etherdevice.h Sun Mar 25 18:24:31 2001 @@ -38,11 +38,28 @@ struct hh_cache *hh); extern int eth_header_parse(struct sk_buff *skb, unsigned char *haddr); -extern struct net_device * init_etherdev(struct net_device *, int); +extern struct net_device *init_etherdev(struct net_device *dev, int sizeof_priv); +extern struct net_device *alloc_etherdev(int sizeof_priv); -static __inline__ void eth_copy_and_sum (struct sk_buff *dest, unsigned char *src, int len, int base) +static inline void eth_copy_and_sum (struct sk_buff *dest, unsigned char *src, int len, int base) { memcpy (dest->data, src, len); +} + +/** + * is_valid_ether_addr - Determine if the given Ethernet address is valid + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not + * a multicast address, and is not FF:FF:FF:FF:FF:FF. + * + * Return true if the address is valid. + */ +static inline int is_valid_ether_addr( u8 *addr ) +{ + const char zaddr[6] = {0,}; + + return !(addr[0]&1) && memcmp( addr, zaddr, 6); } #endif diff -u --recursive --new-file v2.4.2/linux/include/linux/ethtool.h linux/include/linux/ethtool.h --- v2.4.2/linux/include/linux/ethtool.h Sun Nov 12 20:37:17 2000 +++ linux/include/linux/ethtool.h Sun Mar 25 18:24:31 2001 @@ -24,10 +24,22 @@ u32 reserved[4]; }; +/* these strings are set to whatever the driver author decides... */ +struct ethtool_drvinfo { + u32 cmd; + char driver[32]; /* driver short name, "tulip", "eepro100" */ + char version[32]; /* driver version string */ + char fw_version[32]; /* firmware version string, if applicable */ + char bus_info[32]; /* Bus info for this interface. For PCI + * devices, use pci_dev->slot_name. */ + char reserved1[32]; + char reserved2[32]; +}; /* CMDs currently supported */ -#define ETHTOOL_GSET 0x00000001 /* Get settings, non-privileged. */ +#define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */ +#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff -u --recursive --new-file v2.4.2/linux/include/linux/fcdevice.h linux/include/linux/fcdevice.h --- v2.4.2/linux/include/linux/fcdevice.h Mon Aug 23 10:12:38 1999 +++ linux/include/linux/fcdevice.h Sun Mar 25 18:24:31 2001 @@ -33,7 +33,10 @@ extern int fc_rebuild_header(struct sk_buff *skb); //extern unsigned short fc_type_trans(struct sk_buff *skb, struct net_device *dev); -extern struct net_device * init_fcdev(struct net_device *, int); +extern struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv); +extern struct net_device *alloc_fcdev(int sizeof_priv); +extern int register_fcdev(struct net_device *dev); +extern void unregister_fcdev(struct net_device *dev); #endif diff -u --recursive --new-file v2.4.2/linux/include/linux/fddidevice.h linux/include/linux/fddidevice.h --- v2.4.2/linux/include/linux/fddidevice.h Fri Jul 14 14:46:30 2000 +++ linux/include/linux/fddidevice.h Sun Mar 25 18:24:31 2001 @@ -34,7 +34,8 @@ extern int fddi_rebuild_header(struct sk_buff *skb); extern unsigned short fddi_type_trans(struct sk_buff *skb, struct net_device *dev); -extern struct net_device * init_fddidev(struct net_device *, int); +extern struct net_device *init_fddidev(struct net_device *dev, int sizeof_priv); +extern struct net_device *alloc_fddidev(int sizeof_priv); #endif #endif /* _LINUX_FDDIDEVICE_H */ 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 Mon Mar 26 15:48:11 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/fs_struct.h linux/include/linux/fs_struct.h --- v2.4.2/linux/include/linux/fs_struct.h Wed Jul 5 11:31:00 2000 +++ linux/include/linux/fs_struct.h Thu Mar 15 09:56:07 2001 @@ -13,7 +13,7 @@ #define INIT_FS { \ ATOMIC_INIT(1), \ RW_LOCK_UNLOCKED, \ - 0022, \ + 0000, \ NULL, NULL, NULL, NULL, NULL, NULL \ } 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 Mon Mar 26 15:48:11 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/hippidevice.h linux/include/linux/hippidevice.h --- v2.4.2/linux/include/linux/hippidevice.h Thu Jan 4 14:52:01 2001 +++ linux/include/linux/hippidevice.h Mon Mar 26 15:49:42 2001 @@ -51,7 +51,9 @@ extern void hippi_net_init(void); void hippi_setup(struct net_device *dev); -extern struct net_device *init_hippi_dev(struct net_device *, int); +extern struct net_device *init_hippi_dev(struct net_device *dev, int sizeof_priv); +extern struct net_device *alloc_hippi_dev(int sizeof_priv); +extern int register_hipdev(struct net_device *dev); extern void unregister_hipdev(struct net_device *dev); #endif 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 Mon Mar 26 15:38:19 2001 @@ -1,4 +1,4 @@ -/* $Id: hysdn_if.h,v 1.1 2000/02/10 19:47:50 werner Exp $ +/* $Id: hysdn_if.h,v 1.1.8.1 2001/03/13 16:17:10 kai Exp $ * Linux driver for HYSDN cards, ioctl definitions shared by hynetmgr and driver. * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hysdn_if.h,v $ + * Revision 1.1.8.1 2001/03/13 16:17:10 kai + * spelling fixes from 2.4.3-pre + * * Revision 1.1 2000/02/10 19:47:50 werner * * Initial release @@ -30,7 +33,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_arp.h linux/include/linux/if_arp.h --- v2.4.2/linux/include/linux/if_arp.h Thu Jan 4 14:51:20 2001 +++ linux/include/linux/if_arp.h Mon Mar 26 15:48:19 2001 @@ -50,9 +50,11 @@ #define ARPHRD_X25 271 /* CCITT X.25 */ #define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ #define ARPHRD_PPP 512 -#define ARPHRD_HDLC 513 /* (Cisco) HDLC */ +#define ARPHRD_CISCO 513 /* Cisco HDLC */ +#define ARPHRD_HDLC ARPHRD_CISCO #define ARPHRD_LAPB 516 /* LAPB */ #define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */ +#define ARPHRD_RAWHDLC 518 /* Raw HDLC */ #define ARPHRD_TUNNEL 768 /* IPIP tunnel */ #define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */ 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 Mon Mar 26 15:48:10 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/isdn_ppp.h linux/include/linux/isdn_ppp.h --- v2.4.2/linux/include/linux/isdn_ppp.h Mon Dec 11 13:21:27 2000 +++ linux/include/linux/isdn_ppp.h Mon Mar 26 15:38:19 2001 @@ -76,7 +76,7 @@ * * We use this same struct for the reset entry of the compressor to commu- * nicate to its caller how to deal with sending of a Reset Ack. In this - * case, expra is not used, but other options still apply (supressing + * case, expra is not used, but other options still apply (suppressing * sending with rsend, appending arbitrary data, etc). */ 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 Mon Mar 26 15:48:13 2001 @@ -395,12 +395,26 @@ extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot); extern void vmtruncate(struct inode * inode, loff_t offset); +extern pmd_t *FASTCALL(__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)); +extern pte_t *FASTCALL(pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)); extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access); extern int make_pages_present(unsigned long addr, unsigned long end); extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len); +/* + * On a two-level page table, this ends up being trivial. Thus the + * inlining and the symmetry break with pte_alloc() that does all + * of this out-of-line. + */ +static inline pmd_t *pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) +{ + if (!pgd_present(*pgd)) + return __pmd_alloc(mm, pgd, address); + return pmd_offset(pgd, address); +} + extern int pgt_cache_water[2]; extern int check_pgt_cache(void); @@ -481,11 +495,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) @@ -497,11 +506,13 @@ if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur || ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) return -ENOMEM; + spin_lock(&vma->vm_mm->page_table_lock); vma->vm_start = address; vma->vm_pgoff -= grow; vma->vm_mm->total_vm += grow; if (vma->vm_flags & VM_LOCKED) vma->vm_mm->locked_vm += grow; + spin_unlock(&vma->vm_mm->page_table_lock); return 0; } 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 26 15:48:11 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 Mon Mar 26 15:48:19 2001 @@ -41,6 +41,9 @@ struct divert_blk; +#define HAVE_ALLOC_NETDEV /* feature macro: alloc_xxxdev + functions are available. */ + #define NET_XMIT_SUCCESS 0 #define NET_XMIT_DROP 1 /* skb dropped */ #define NET_XMIT_CN 2 /* congestion notification */ @@ -630,14 +633,9 @@ 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); -extern int register_trdev(struct net_device *dev); -extern void unregister_trdev(struct net_device *dev); -extern int register_fcdev(struct net_device *dev); -extern void unregister_fcdev(struct net_device *dev); /* Functions used for multicast support */ extern void dev_mc_upload(struct net_device *dev); extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); 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 Mon Mar 26 15:48:15 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 Mon Mar 26 15:48:46 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 +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 Sun Mar 25 18:14:20 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 @@ -559,9 +562,16 @@ #define PCI_VENDOR_ID_SUN 0x108e #define PCI_DEVICE_ID_SUN_EBUS 0x1000 #define PCI_DEVICE_ID_SUN_HAPPYMEAL 0x1001 +#define PCI_DEVICE_ID_SUN_RIO_EBUS 0x1100 +#define PCI_DEVICE_ID_SUN_RIO_GEM 0x1101 +#define PCI_DEVICE_ID_SUN_RIO_1394 0x1102 +#define PCI_DEVICE_ID_SUN_RIO_USB 0x1103 +#define PCI_DEVICE_ID_SUN_GEM 0x2bad #define PCI_DEVICE_ID_SUN_SIMBA 0x5000 #define PCI_DEVICE_ID_SUN_PBM 0x8000 +#define PCI_DEVICE_ID_SUN_SCHIZO 0x8001 #define PCI_DEVICE_ID_SUN_SABRE 0xa000 +#define PCI_DEVICE_ID_SUN_HUMMINGBIRD 0xa001 #define PCI_VENDOR_ID_CMD 0x1095 #define PCI_DEVICE_ID_CMD_640 0x0640 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/sched.h linux/include/linux/sched.h --- v2.4.2/linux/include/linux/sched.h Wed Feb 21 18:20:46 2001 +++ linux/include/linux/sched.h Mon Mar 26 15:48:11 2001 @@ -167,7 +167,7 @@ */ struct files_struct { atomic_t count; - rwlock_t file_lock; + rwlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */ int max_fds; int max_fdset; int next_fd; @@ -208,10 +208,13 @@ atomic_t mm_users; /* How many users with user space? */ atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ int map_count; /* number of VMAs */ - struct semaphore mmap_sem; - spinlock_t page_table_lock; + struct rw_semaphore mmap_sem; + spinlock_t page_table_lock; /* Protects task page tables and mm->rss */ - struct list_head mmlist; /* List of all active mm's */ + struct list_head mmlist; /* List of all active mm's. These are globally strung + * together off init_mm.mmlist, and are protected + * by mmlist_lock + */ unsigned long start_code, end_code, start_data, end_data; unsigned long start_brk, brk, start_stack; @@ -236,7 +239,7 @@ mm_users: ATOMIC_INIT(2), \ mm_count: ATOMIC_INIT(1), \ map_count: 1, \ - mmap_sem: __MUTEX_INITIALIZER(name.mmap_sem), \ + mmap_sem: __RWSEM_INITIALIZER(name.mmap_sem, RW_LOCK_BIAS), \ page_table_lock: SPIN_LOCK_UNLOCKED, \ mmlist: LIST_HEAD_INIT(name.mmlist), \ } @@ -857,6 +860,7 @@ write_unlock_irq(&tasklist_lock); } +/* Protects ->fs, ->files, ->mm, and synchronises with wait4(). Nests inside tasklist_lock */ static inline void task_lock(struct task_struct *p) { spin_lock(&p->alloc_lock); 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 Mon Mar 26 15:48:10 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 Mon Mar 26 15:50:00 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/sysctl.h linux/include/linux/sysctl.h --- v2.4.2/linux/include/linux/sysctl.h Thu Jan 4 14:50:47 2001 +++ linux/include/linux/sysctl.h Mon Mar 26 15:48:10 2001 @@ -378,6 +378,10 @@ }; /* /proc/sys/net/ipx */ +enum { + NET_IPX_PPROP_BROADCASTING=1, + NET_IPX_FORWARDING=2 +}; /* /proc/sys/net/appletalk */ diff -u --recursive --new-file v2.4.2/linux/include/linux/tqueue.h linux/include/linux/tqueue.h --- v2.4.2/linux/include/linux/tqueue.h Thu Jan 4 14:50:46 2001 +++ linux/include/linux/tqueue.h Mon Mar 26 15:48:11 2001 @@ -42,6 +42,25 @@ void *data; /* argument to function */ }; +/* + * Emit code to initialise a tq_struct's routine and data pointers + */ +#define PREPARE_TQUEUE(_tq, _routine, _data) \ + do { \ + (_tq)->routine = _routine; \ + (_tq)->data = _data; \ + } while (0) + +/* + * Emit code to initialise all of a tq_struct + */ +#define INIT_TQUEUE(_tq, _routine, _data) \ + do { \ + INIT_LIST_HEAD(&(_tq)->list); \ + (_tq)->sync = 0; \ + PREPARE_TQUEUE((_tq), (_routine), (_data)); \ + } while (0) + typedef struct list_head task_queue; #define DECLARE_TASK_QUEUE(q) LIST_HEAD(q) diff -u --recursive --new-file v2.4.2/linux/include/linux/trdevice.h linux/include/linux/trdevice.h --- v2.4.2/linux/include/linux/trdevice.h Wed Aug 18 11:38:46 1999 +++ linux/include/linux/trdevice.h Sun Mar 25 18:24:31 2001 @@ -33,7 +33,10 @@ void *saddr, unsigned len); extern int tr_rebuild_header(struct sk_buff *skb); extern unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev); -extern struct net_device * init_trdev(struct net_device *, int); +extern struct net_device *init_trdev(struct net_device *dev, int sizeof_priv); +extern struct net_device *alloc_trdev(int sizeof_priv); +extern int register_trdev(struct net_device *dev); +extern void unregister_trdev(struct net_device *dev); #endif diff -u --recursive --new-file v2.4.2/linux/include/linux/tty.h linux/include/linux/tty.h --- v2.4.2/linux/include/linux/tty.h Thu Jan 4 14:50:47 2001 +++ linux/include/linux/tty.h Mon Mar 26 15:48:11 2001 @@ -307,6 +307,8 @@ struct semaphore atomic_read; struct semaphore atomic_write; spinlock_t read_lock; + /* If the tty has a pending do_SAK, queue it here - akpm */ + struct tq_struct SAK_tq; }; /* tty magic number */ diff -u --recursive --new-file v2.4.2/linux/include/linux/usb.h linux/include/linux/usb.h --- v2.4.2/linux/include/linux/usb.h Thu Jan 4 14:52:19 2001 +++ linux/include/linux/usb.h Mon Mar 26 15:49:54 2001 @@ -555,11 +555,17 @@ int (*unlink_urb) (struct urb* purb); }; +#define DEVNUM_ROUND_ROBIN /***** OPTION *****/ + /* * Allocated per bus we have */ struct usb_bus { int busnum; /* Bus number (in order of reg) */ + +#ifdef DEVNUM_ROUND_ROBIN + int devnum_next; /* Next open device number in round-robin allocation */ +#endif /* DEVNUM_ROUND_ROBIN */ struct usb_devmap devmap; /* Device map */ struct usb_operations *op; /* Operations (specific to the HC) */ 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/ipx.h linux/include/net/ipx.h --- v2.4.2/linux/include/net/ipx.h Sat Feb 3 19:51:32 2001 +++ linux/include/net/ipx.h Mon Mar 26 15:48:20 2001 @@ -24,6 +24,8 @@ #define ipx_broadcast_node "\377\377\377\377\377\377" #define ipx_this_node "\0\0\0\0\0\0" +#define IPX_MAX_PPROP_HOPS 8 + struct ipxhdr { __u16 ipx_checksum __attribute__ ((packed)); @@ -36,7 +38,7 @@ #define IPX_TYPE_SAP 0x04 /* may also be 0 */ #define IPX_TYPE_SPX 0x05 /* SPX protocol */ #define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */ -#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */ +#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast */ ipx_address ipx_dest __attribute__ ((packed)); ipx_address ipx_source __attribute__ ((packed)); }; @@ -71,6 +73,7 @@ unsigned char ir_routed; unsigned char ir_router_node[IPX_NODE_LEN]; struct ipx_route *ir_next; + atomic_t refcnt; } ipx_route; #ifdef __KERNEL__ @@ -78,7 +81,10 @@ u8 ipx_tctrl; u32 ipx_dest_net; u32 ipx_source_net; - int last_hop_index; + struct { + u32 netnum; + int index; + } last_hop; }; #endif #define IPX_MIN_EPHEMERAL_SOCKET 0x4000 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 Mon Mar 19 12:26:25 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/ipc/shm.c linux/ipc/shm.c --- v2.4.2/linux/ipc/shm.c Wed Feb 21 18:20:46 2001 +++ linux/ipc/shm.c Mon Mar 19 12:35:08 2001 @@ -71,7 +71,9 @@ void __init shm_init (void) { ipc_init_ids(&shm_ids, 1); +#ifdef CONFIG_PROC_FS create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL); +#endif } static inline int shm_checkid(struct shmid_kernel *s, int id) @@ -605,9 +607,9 @@ shp->shm_nattch++; shm_unlock(shmid); - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); user_addr = (void *) do_mmap (file, addr, file->f_dentry->d_inode->i_size, prot, flags, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); down (&shm_ids.sem); if(!(shp = shm_lock(shmid))) @@ -636,14 +638,14 @@ struct mm_struct *mm = current->mm; struct vm_area_struct *shmd, *shmdnext; - down(&mm->mmap_sem); + down_write(&mm->mmap_sem); for (shmd = mm->mmap; shmd; shmd = shmdnext) { shmdnext = shmd->vm_next; if (shmd->vm_ops == &shm_vm_ops && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start); } - up(&mm->mmap_sem); + up_write(&mm->mmap_sem); return 0; } diff -u --recursive --new-file v2.4.2/linux/kernel/acct.c linux/kernel/acct.c --- v2.4.2/linux/kernel/acct.c Wed Feb 21 18:20:46 2001 +++ linux/kernel/acct.c Mon Mar 19 12:35:08 2001 @@ -315,13 +315,13 @@ vsize = 0; if (current->mm) { struct vm_area_struct *vma; - down(¤t->mm->mmap_sem); + down_read(¤t->mm->mmap_sem); vma = current->mm->mmap; while (vma) { vsize += vma->vm_end - vma->vm_start; vma = vma->vm_next; } - up(¤t->mm->mmap_sem); + up_read(¤t->mm->mmap_sem); } vsize = vsize / 1024; ac.ac_mem = encode_comp_t(vsize); diff -u --recursive --new-file v2.4.2/linux/kernel/fork.c linux/kernel/fork.c --- v2.4.2/linux/kernel/fork.c Wed Feb 21 18:20:46 2001 +++ linux/kernel/fork.c Mon Mar 19 12:35:08 2001 @@ -201,7 +201,7 @@ { atomic_set(&mm->mm_users, 1); atomic_set(&mm->mm_count, 1); - init_MUTEX(&mm->mmap_sem); + init_rwsem(&mm->mmap_sem); mm->page_table_lock = SPIN_LOCK_UNLOCKED; mm->pgd = pgd_alloc(); if (mm->pgd) @@ -314,9 +314,9 @@ if (!mm_init(mm)) goto fail_nomem; - down(&oldmm->mmap_sem); + down_write(&oldmm->mmap_sem); retval = dup_mmap(mm); - up(&oldmm->mmap_sem); + up_write(&oldmm->mmap_sem); /* * Add it to the mmlist after the parent. 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 19 12:35:08 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; } @@ -131,13 +140,13 @@ if (!mm) return 0; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = find_extend_vma(mm, addr); copied = 0; if (vma) copied = access_mm(mm, vma, addr, buf, len, write); - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); return copied; } 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 Thu Mar 22 09:20:45 2001 @@ -82,6 +82,8 @@ * * If both locks are to be concurrently held, the runqueue_lock * nests inside the tasklist_lock. + * + * task->alloc_lock nests inside tasklist_lock. */ spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* inner */ rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */ @@ -339,7 +341,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 +361,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 +501,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 +569,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 23 14:38:48 2001 @@ -559,7 +559,7 @@ if (page) return 0; - page = page_cache_alloc(); + page = page_cache_alloc(mapping); if (!page) return -ENOMEM; @@ -659,7 +659,7 @@ /* * a rather lightweight function, finding and getting a reference to a - * hashed page atomically, waiting for it if it's locked. + * hashed page atomically. */ struct page * __find_get_page(struct address_space *mapping, unsigned long offset, struct page **hash) @@ -679,7 +679,8 @@ } /* - * Get the lock to a page atomically. + * Same as the above, but lock the page too, verifying that + * it's still valid once we own it. */ struct page * __find_lock_page (struct address_space *mapping, unsigned long offset, struct page **hash) @@ -1174,7 +1175,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 +1475,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); @@ -1752,7 +1753,7 @@ struct vm_area_struct * vma; int unmapped_error, error = -EINVAL; - down(¤t->mm->mmap_sem); + down_read(¤t->mm->mmap_sem); if (start & ~PAGE_MASK) goto out; len = (len + ~PAGE_MASK) & PAGE_MASK; @@ -1798,7 +1799,7 @@ vma = vma->vm_next; } out: - up(¤t->mm->mmap_sem); + up_read(¤t->mm->mmap_sem); return error; } @@ -2097,7 +2098,7 @@ int unmapped_error = 0; int error = -EINVAL; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); if (start & ~PAGE_MASK) goto out; @@ -2148,7 +2149,7 @@ } out: - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return error; } @@ -2250,7 +2251,7 @@ int unmapped_error = 0; long error = -EINVAL; - down(¤t->mm->mmap_sem); + down_read(¤t->mm->mmap_sem); if (start & ~PAGE_CACHE_MASK) goto out; @@ -2302,7 +2303,7 @@ } out: - up(¤t->mm->mmap_sem); + up_read(¤t->mm->mmap_sem); return error; } @@ -2319,7 +2320,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 +2383,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 Mon Mar 26 11:02:24 2001 @@ -42,11 +42,11 @@ #include #include #include -#include -#include #include #include +#include +#include unsigned long max_mapnr; unsigned long num_physpages; @@ -160,6 +160,7 @@ src_pgd = pgd_offset(src, address)-1; dst_pgd = pgd_offset(dst, address)-1; + spin_lock(&dst->page_table_lock); for (;;) { pmd_t * src_pmd, * dst_pmd; @@ -177,13 +178,11 @@ goto out; continue; } - if (pgd_none(*dst_pgd)) { - if (!pmd_alloc(dst_pgd, 0)) - goto nomem; - } - + src_pmd = pmd_offset(src_pgd, address); - dst_pmd = pmd_offset(dst_pgd, address); + dst_pmd = pmd_alloc(dst, dst_pgd, address); + if (!dst_pmd) + goto nomem; do { pte_t * src_pte, * dst_pte; @@ -200,13 +199,11 @@ goto out; goto cont_copy_pmd_range; } - if (pmd_none(*dst_pmd)) { - if (!pte_alloc(dst_pmd, 0)) - goto nomem; - } - + src_pte = pte_offset(src_pmd, address); - dst_pte = pte_offset(dst_pmd, address); + dst_pte = pte_alloc(dst, dst_pmd, address); + if (!dst_pte) + goto nomem; spin_lock(&src->page_table_lock); do { @@ -251,14 +248,14 @@ dst_pmd++; } while ((unsigned long)src_pmd & PMD_TABLE_MASK); } -out: - return 0; - out_unlock: spin_unlock(&src->page_table_lock); +out: + spin_unlock(&dst->page_table_lock); return 0; nomem: + spin_unlock(&dst->page_table_lock); return -ENOMEM; } @@ -377,7 +374,6 @@ address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); - spin_unlock(&mm->page_table_lock); /* * Update rss for the mm_struct (not necessarily current->mm) * Notice that rss is an unsigned long. @@ -386,6 +382,7 @@ mm->rss -= freed; else mm->rss = 0; + spin_unlock(&mm->page_table_lock); } @@ -450,7 +447,7 @@ if (err) return err; - down(&mm->mmap_sem); + down_write(&mm->mmap_sem); err = -EFAULT; iobuf->locked = 0; @@ -501,12 +498,12 @@ ptr += PAGE_SIZE; } - up(&mm->mmap_sem); + up_write(&mm->mmap_sem); dprintk ("map_user_kiobuf: end OK\n"); return 0; out_unlock: - up(&mm->mmap_sem); + up_write(&mm->mmap_sem); unmap_kiobuf(iobuf); dprintk ("map_user_kiobuf: end %d\n", err); return err; @@ -658,7 +655,7 @@ } while (address && (address < end)); } -static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, +static inline int zeromap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, pgprot_t prot) { unsigned long end; @@ -668,7 +665,7 @@ if (end > PGDIR_SIZE) end = PGDIR_SIZE; do { - pte_t * pte = pte_alloc(pmd, address); + pte_t * pte = pte_alloc(mm, pmd, address); if (!pte) return -ENOMEM; zeromap_pte_range(pte, address, end - address, prot); @@ -684,23 +681,27 @@ pgd_t * dir; unsigned long beg = address; unsigned long end = address + size; + struct mm_struct *mm = current->mm; - dir = pgd_offset(current->mm, address); - flush_cache_range(current->mm, beg, end); + dir = pgd_offset(mm, address); + flush_cache_range(mm, beg, end); if (address >= end) BUG(); + + spin_lock(&mm->page_table_lock); do { - pmd_t *pmd = pmd_alloc(dir, address); + pmd_t *pmd = pmd_alloc(mm, dir, address); error = -ENOMEM; if (!pmd) break; - error = zeromap_pmd_range(pmd, address, end - address, prot); + error = zeromap_pmd_range(mm, pmd, address, end - address, prot); if (error) break; address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (address && (address < end)); - flush_tlb_range(current->mm, beg, end); + spin_unlock(&mm->page_table_lock); + flush_tlb_range(mm, beg, end); return error; } @@ -733,7 +734,7 @@ } while (address && (address < end)); } -static inline int remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size, +static inline int remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, unsigned long phys_addr, pgprot_t prot) { unsigned long end; @@ -744,7 +745,7 @@ end = PGDIR_SIZE; phys_addr -= address; do { - pte_t * pte = pte_alloc(pmd, address); + pte_t * pte = pte_alloc(mm, pmd, address); if (!pte) return -ENOMEM; remap_pte_range(pte, address, end - address, address + phys_addr, prot); @@ -761,24 +762,28 @@ pgd_t * dir; unsigned long beg = from; unsigned long end = from + size; + struct mm_struct *mm = current->mm; phys_addr -= from; - dir = pgd_offset(current->mm, from); - flush_cache_range(current->mm, beg, end); + dir = pgd_offset(mm, from); + flush_cache_range(mm, beg, end); if (from >= end) BUG(); + + spin_lock(&mm->page_table_lock); do { - pmd_t *pmd = pmd_alloc(dir, from); + pmd_t *pmd = pmd_alloc(mm, dir, from); error = -ENOMEM; if (!pmd) break; - error = remap_pmd_range(pmd, from, end - from, phys_addr + from, prot); + error = remap_pmd_range(mm, pmd, from, end - from, phys_addr + from, prot); if (error) break; from = (from + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (from && (from < end)); - flush_tlb_range(current->mm, beg, end); + spin_unlock(&mm->page_table_lock); + flush_tlb_range(mm, beg, end); return error; } @@ -787,6 +792,8 @@ * - flush the old one * - update the page tables * - inform the TLB about the new one + * + * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock */ static inline void establish_pte(struct vm_area_struct * vma, unsigned long address, pte_t *page_table, pte_t entry) { @@ -795,6 +802,9 @@ update_mmu_cache(vma, address, entry); } +/* + * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock + */ static inline void break_cow(struct vm_area_struct * vma, struct page * old_page, struct page * new_page, unsigned long address, pte_t *page_table) { @@ -862,7 +872,6 @@ break; flush_cache_page(vma, address); establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte)))); - spin_unlock(&mm->page_table_lock); return 1; /* Minor fault */ } @@ -870,10 +879,10 @@ * Ok, we need to copy. Oh, well.. */ spin_unlock(&mm->page_table_lock); - new_page = page_cache_alloc(); + new_page = alloc_page(GFP_HIGHUSER); + spin_lock(&mm->page_table_lock); if (!new_page) return -1; - spin_lock(&mm->page_table_lock); /* * Re-check the pte - we dropped the lock @@ -886,12 +895,10 @@ /* Free the old page.. */ new_page = old_page; } - spin_unlock(&mm->page_table_lock); page_cache_release(new_page); return 1; /* Minor fault */ bad_wp_page: - spin_unlock(&mm->page_table_lock); printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page); return -1; } @@ -1021,63 +1028,100 @@ return; } +/* + * We hold the mm semaphore and the page_table_lock on entry and exit. + */ static int do_swap_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, pte_t * page_table, swp_entry_t entry, int write_access) { - struct page *page = lookup_swap_cache(entry); + struct page *page; pte_t pte; + spin_unlock(&mm->page_table_lock); + page = lookup_swap_cache(entry); if (!page) { lock_kernel(); swapin_readahead(entry); page = read_swap_cache(entry); unlock_kernel(); - if (!page) + if (!page) { + spin_lock(&mm->page_table_lock); return -1; + } flush_page_to_ram(page); flush_icache_page(vma, page); } - mm->rss++; - - pte = mk_pte(page, vma->vm_page_prot); - /* * Freeze the "shared"ness of the page, ie page_count + swap_count. * Must lock page before transferring our swap count to already * obtained page count. */ lock_page(page); + + /* + * Back out if somebody else faulted in this pte while we + * released the page table lock. + */ + spin_lock(&mm->page_table_lock); + if (pte_present(*page_table)) { + UnlockPage(page); + page_cache_release(page); + return 1; + } + + /* The page isn't present yet, go ahead with the fault. */ + mm->rss++; + pte = mk_pte(page, vma->vm_page_prot); + swap_free(entry); if (write_access && !is_page_shared(page)) pte = pte_mkwrite(pte_mkdirty(pte)); UnlockPage(page); set_pte(page_table, pte); + /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, address, pte); return 1; /* Minor fault */ } /* - * This only needs the MM semaphore + * We are called with the MM semaphore and page_table_lock + * spinlock held to protect against concurrent faults in + * multithreaded programs. */ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr) { - struct page *page = NULL; - pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot)); + pte_t entry; + + /* Read-only mapping of ZERO_PAGE. */ + entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot)); + + /* ..except if it's a write access */ if (write_access) { + struct page *page; + + /* Allocate our own private page. */ + spin_unlock(&mm->page_table_lock); page = alloc_page(GFP_HIGHUSER); + spin_lock(&mm->page_table_lock); if (!page) return -1; - clear_user_highpage(page, addr); - entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + if (!pte_none(*page_table)) { + page_cache_release(page); + return 1; + } mm->rss++; + clear_user_highpage(page, addr); flush_page_to_ram(page); + entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); } + set_pte(page_table, entry); + /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, addr, entry); return 1; /* Minor fault */ @@ -1092,7 +1136,8 @@ * As this is called only for pages that do not currently exist, we * do not need to flush old virtual caches or the TLB. * - * This is called with the MM semaphore held. + * This is called with the MM semaphore held and the page table + * spinlock held. */ static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int write_access, pte_t *page_table) @@ -1102,6 +1147,7 @@ if (!vma->vm_ops || !vma->vm_ops->nopage) return do_anonymous_page(mm, vma, page_table, write_access, address); + spin_unlock(&mm->page_table_lock); /* * The third argument is "no_share", which tells the low-level code @@ -1109,11 +1155,12 @@ * essentially an early COW detection. */ new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access); + + spin_lock(&mm->page_table_lock); if (new_page == NULL) /* no page was available -- SIGBUS */ return 0; if (new_page == NOPAGE_OOM) return -1; - ++mm->rss; /* * This silly early PAGE_DIRTY setting removes a race * due to the bad i386 page protection. But it's valid @@ -1124,15 +1171,24 @@ * so we can make it writable and dirty to avoid having to * handle that later. */ - flush_page_to_ram(new_page); - flush_icache_page(vma, new_page); - entry = mk_pte(new_page, vma->vm_page_prot); - if (write_access) { - entry = pte_mkwrite(pte_mkdirty(entry)); - } else if (page_count(new_page) > 1 && - !(vma->vm_flags & VM_SHARED)) - entry = pte_wrprotect(entry); - set_pte(page_table, entry); + /* Only go through if we didn't race with anybody else... */ + if (pte_none(*page_table)) { + ++mm->rss; + flush_page_to_ram(new_page); + flush_icache_page(vma, new_page); + entry = mk_pte(new_page, vma->vm_page_prot); + if (write_access) { + entry = pte_mkwrite(pte_mkdirty(entry)); + } else if (page_count(new_page) > 1 && + !(vma->vm_flags & VM_SHARED)) + entry = pte_wrprotect(entry); + set_pte(page_table, entry); + } else { + /* One of our sibling threads was faster, back out. */ + page_cache_release(new_page); + return 1; + } + /* no need to invalidate: a not-present page shouldn't be cached */ update_mmu_cache(vma, address, entry); return 2; /* Major fault */ @@ -1162,11 +1218,6 @@ { pte_t entry; - /* - * We need the page table lock to synchronize with kswapd - * and the SMP-safe atomic PTE updates. - */ - spin_lock(&mm->page_table_lock); entry = *pte; if (!pte_present(entry)) { /* @@ -1174,7 +1225,6 @@ * and the PTE updates will not touch it later. So * drop the lock. */ - spin_unlock(&mm->page_table_lock); if (pte_none(entry)) return do_no_page(mm, vma, address, write_access, pte); return do_swap_page(mm, vma, address, pte, pte_to_swp_entry(entry), write_access); @@ -1188,7 +1238,6 @@ } entry = pte_mkyoung(entry); establish_pte(vma, address, pte, entry); - spin_unlock(&mm->page_table_lock); return 1; } @@ -1204,14 +1253,92 @@ current->state = TASK_RUNNING; pgd = pgd_offset(mm, address); - pmd = pmd_alloc(pgd, address); + + /* + * We need the page table lock to synchronize with kswapd + * and the SMP-safe atomic PTE updates. + */ + spin_lock(&mm->page_table_lock); + pmd = pmd_alloc(mm, pgd, address); if (pmd) { - pte_t * pte = pte_alloc(pmd, address); + pte_t * pte = pte_alloc(mm, pmd, address); if (pte) ret = handle_pte_fault(mm, vma, address, write_access, pte); } + spin_unlock(&mm->page_table_lock); return ret; +} + +/* + * Allocate page middle directory. + * + * We've already handled the fast-path in-line, and we own the + * page table lock. + * + * On a two-level page table, this ends up actually being entirely + * optimized away. + */ +pmd_t *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) +{ + pmd_t *new; + + /* "fast" allocation can happen without dropping the lock.. */ + new = pmd_alloc_one_fast(mm, address); + if (!new) { + spin_unlock(&mm->page_table_lock); + new = pmd_alloc_one(mm, address); + spin_lock(&mm->page_table_lock); + if (!new) + return NULL; + + /* + * Because we dropped the lock, we should re-check the + * entry, as somebody else could have populated it.. + */ + if (pgd_present(*pgd)) { + pmd_free(new); + goto out; + } + } + pgd_populate(mm, pgd, new); +out: + return pmd_offset(pgd, address); +} + +/* + * Allocate the page table directory. + * + * We've already handled the fast-path in-line, and we own the + * page table lock. + */ +pte_t *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address) +{ + if (!pmd_present(*pmd)) { + pte_t *new; + + /* "fast" allocation can happen without dropping the lock.. */ + new = pte_alloc_one_fast(mm, address); + if (!new) { + spin_unlock(&mm->page_table_lock); + new = pte_alloc_one(mm, address); + spin_lock(&mm->page_table_lock); + if (!new) + return NULL; + + /* + * Because we dropped the lock, we should re-check the + * entry, as somebody else could have populated it.. + */ + if (pmd_present(*pmd)) { + pte_free(new); + goto out; + } + } + pmd_populate(mm, pmd, new); + } +out: + return pte_offset(pmd, address); } /* diff -u --recursive --new-file v2.4.2/linux/mm/mlock.c linux/mm/mlock.c --- v2.4.2/linux/mm/mlock.c Fri Dec 29 14:07:24 2000 +++ linux/mm/mlock.c Mon Mar 19 12:35:08 2001 @@ -198,7 +198,7 @@ unsigned long lock_limit; int error = -ENOMEM; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); start &= PAGE_MASK; @@ -219,7 +219,7 @@ error = do_mlock(start, len, 1); out: - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return error; } @@ -227,11 +227,11 @@ { int ret; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); start &= PAGE_MASK; ret = do_mlock(start, len, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return ret; } @@ -268,7 +268,7 @@ unsigned long lock_limit; int ret = -EINVAL; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE))) goto out; @@ -286,7 +286,7 @@ ret = do_mlockall(flags); out: - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return ret; } @@ -294,8 +294,8 @@ { int ret; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); ret = do_mlockall(0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return ret; } diff -u --recursive --new-file v2.4.2/linux/mm/mmap.c linux/mm/mmap.c --- v2.4.2/linux/mm/mmap.c Wed Feb 21 18:20:46 2001 +++ linux/mm/mmap.c Wed Mar 28 12:55:34 2001 @@ -133,7 +133,7 @@ unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; - down(&mm->mmap_sem); + down_write(&mm->mmap_sem); if (brk < mm->end_code) goto out; @@ -169,7 +169,7 @@ mm->brk = brk; out: retval = mm->brk; - up(&mm->mmap_sem); + up_write(&mm->mmap_sem); return retval; } @@ -177,7 +177,7 @@ * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits * into "VM_xxx". */ -static inline unsigned long vm_flags(unsigned long prot, unsigned long flags) +static inline unsigned long calc_vm_flags(unsigned long prot, unsigned long flags) { #define _trans(x,bit1,bit2) \ ((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0) @@ -200,6 +200,7 @@ { struct mm_struct * mm = current->mm; struct vm_area_struct * vma; + unsigned int vm_flags; int correct_wcount = 0; int error; @@ -220,19 +221,33 @@ if (mm->map_count > MAX_MAP_COUNT) return -ENOMEM; + /* Obtain the address to map to. we verify (or select) it and ensure + * that it represents a valid section of the address space. + */ + if (flags & MAP_FIXED) { + if (addr & ~PAGE_MASK) + return -EINVAL; + } else { + addr = get_unmapped_area(addr, len); + if (!addr) + return -ENOMEM; + } + + /* Do simple checking here so the lower-level routines won't have + * to. we assume access permissions have been handled by the open + * of the memory object, so we don't do any here. + */ + vm_flags = calc_vm_flags(prot,flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; + /* mlock MCL_FUTURE? */ - if (mm->def_flags & VM_LOCKED) { + if (vm_flags & VM_LOCKED) { unsigned long locked = mm->locked_vm << PAGE_SHIFT; locked += len; if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; } - /* Do simple checking here so the lower-level routines won't have - * to. we assume access permissions have been handled by the open - * of the memory object, so we don't do any here. - */ - if (file != NULL) { + if (file) { switch (flags & MAP_TYPE) { case MAP_SHARED: if ((prot & PROT_WRITE) && !(file->f_mode & FMODE_WRITE)) @@ -246,6 +261,10 @@ if (locks_verify_locked(file->f_dentry->d_inode)) return -EAGAIN; + vm_flags |= VM_SHARED | VM_MAYSHARE; + if (!(file->f_mode & FMODE_WRITE)) + vm_flags &= ~(VM_MAYWRITE | VM_SHARED); + /* fall through */ case MAP_PRIVATE: if (!(file->f_mode & FMODE_READ)) @@ -255,18 +274,43 @@ default: return -EINVAL; } + } else { + vm_flags |= VM_SHARED | VM_MAYSHARE; + switch (flags & MAP_TYPE) { + default: + return -EINVAL; + case MAP_PRIVATE: + vm_flags &= ~(VM_SHARED | VM_MAYSHARE); + /* fall through */ + case MAP_SHARED: + break; + } } - /* Obtain the address to map to. we verify (or select) it and ensure - * that it represents a valid section of the address space. - */ - if (flags & MAP_FIXED) { - if (addr & ~PAGE_MASK) - return -EINVAL; - } else { - addr = get_unmapped_area(addr, len); - if (!addr) - return -ENOMEM; + /* Clear old maps */ + error = -ENOMEM; + if (do_munmap(mm, addr, len)) + return -ENOMEM; + + /* Check against address space limit. */ + if ((mm->total_vm << PAGE_SHIFT) + len + > current->rlim[RLIMIT_AS].rlim_cur) + return -ENOMEM; + + /* Private writable mapping? Check memory availability.. */ + if ((vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE && + !(flags & MAP_NORESERVE) && + !vm_enough_memory(len >> PAGE_SHIFT)) + return -ENOMEM; + + /* Can we just expand an old anonymous mapping? */ + if (addr && !file && !(vm_flags & VM_SHARED)) { + struct vm_area_struct * vma = find_vma(mm, addr-1); + if (vma && vma->vm_end == addr && !vma->vm_file && + vma->vm_flags == vm_flags) { + vma->vm_end = addr + len; + goto out; + } } /* Determine the object being mapped and call the appropriate @@ -280,58 +324,16 @@ vma->vm_mm = mm; vma->vm_start = addr; vma->vm_end = addr + len; - vma->vm_flags = vm_flags(prot,flags) | mm->def_flags; - - if (file) { - VM_ClearReadHint(vma); - vma->vm_raend = 0; - - if (file->f_mode & FMODE_READ) - vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; - if (flags & MAP_SHARED) { - vma->vm_flags |= VM_SHARED | VM_MAYSHARE; - - /* This looks strange, but when we don't have the file open - * for writing, we can demote the shared mapping to a simpler - * private mapping. That also takes care of a security hole - * with ptrace() writing to a shared mapping without write - * permissions. - * - * We leave the VM_MAYSHARE bit on, just to get correct output - * from /proc/xxx/maps.. - */ - if (!(file->f_mode & FMODE_WRITE)) - vma->vm_flags &= ~(VM_MAYWRITE | VM_SHARED); - } - } else { - vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; - if (flags & MAP_SHARED) - vma->vm_flags |= VM_SHARED | VM_MAYSHARE; - } - vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f]; + vma->vm_flags = vm_flags; + vma->vm_page_prot = protection_map[vm_flags & 0x0f]; vma->vm_ops = NULL; vma->vm_pgoff = pgoff; vma->vm_file = NULL; vma->vm_private_data = NULL; - - /* Clear old maps */ - error = -ENOMEM; - if (do_munmap(mm, addr, len)) - goto free_vma; - - /* Check against address space limit. */ - if ((mm->total_vm << PAGE_SHIFT) + len - > current->rlim[RLIMIT_AS].rlim_cur) - goto free_vma; - - /* Private writable mapping? Check memory availability.. */ - if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE && - !(flags & MAP_NORESERVE) && - !vm_enough_memory(len >> PAGE_SHIFT)) - goto free_vma; + vma->vm_raend = 0; if (file) { - if (vma->vm_flags & VM_DENYWRITE) { + if (vm_flags & VM_DENYWRITE) { error = deny_write_access(file); if (error) goto free_vma; @@ -353,15 +355,15 @@ * Answer: Yes, several device drivers can do it in their * f_op->mmap method. -DaveM */ - flags = vma->vm_flags; addr = vma->vm_start; insert_vm_struct(mm, vma); if (correct_wcount) atomic_inc(&file->f_dentry->d_inode->i_writecount); - + +out: mm->total_vm += len >> PAGE_SHIFT; - if (flags & VM_LOCKED) { + if (vm_flags & VM_LOCKED) { mm->locked_vm += len >> PAGE_SHIFT; make_pages_present(addr, addr + len); } @@ -776,9 +778,9 @@ int ret; struct mm_struct *mm = current->mm; - down(&mm->mmap_sem); + down_write(&mm->mmap_sem); ret = do_munmap(mm, addr, len); - up(&mm->mmap_sem); + up_write(&mm->mmap_sem); return ret; } @@ -825,12 +827,11 @@ if (!vm_enough_memory(len >> PAGE_SHIFT)) return -ENOMEM; - flags = vm_flags(PROT_READ|PROT_WRITE|PROT_EXEC, + flags = calc_vm_flags(PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE) | mm->def_flags; flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; - /* Can we just expand an old anonymous mapping? */ if (addr) { struct vm_area_struct * vma = find_vma(mm, addr-1); @@ -841,7 +842,6 @@ } } - /* * create a vma struct for an anonymous mapping */ @@ -889,8 +889,8 @@ spin_lock(&mm->page_table_lock); mpnt = mm->mmap; mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL; - spin_unlock(&mm->page_table_lock); mm->rss = 0; + spin_unlock(&mm->page_table_lock); mm->total_vm = 0; mm->locked_vm = 0; diff -u --recursive --new-file v2.4.2/linux/mm/mprotect.c linux/mm/mprotect.c --- v2.4.2/linux/mm/mprotect.c Fri Dec 29 14:07:24 2000 +++ linux/mm/mprotect.c Mon Mar 19 12:35:08 2001 @@ -242,7 +242,8 @@ if (end == start) return 0; - down(¤t->mm->mmap_sem); + /* XXX: maybe this could be down_read ??? - Rik */ + down_write(¤t->mm->mmap_sem); vma = find_vma(current->mm, start); error = -EFAULT; @@ -278,6 +279,6 @@ } } out: - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return error; } diff -u --recursive --new-file v2.4.2/linux/mm/mremap.c linux/mm/mremap.c --- v2.4.2/linux/mm/mremap.c Fri Dec 29 14:07:24 2000 +++ linux/mm/mremap.c Mon Mar 19 17:17:43 2001 @@ -51,9 +51,9 @@ pmd_t * pmd; pte_t * pte = NULL; - pmd = pmd_alloc(pgd_offset(mm, addr), addr); + pmd = pmd_alloc(mm, pgd_offset(mm, addr), addr); if (pmd) - pte = pte_alloc(pmd, addr); + pte = pte_alloc(mm, pmd, addr); return pte; } @@ -62,7 +62,6 @@ int error = 0; pte_t pte; - spin_lock(&mm->page_table_lock); if (!pte_none(*src)) { pte = ptep_get_and_clear(src); if (!dst) { @@ -72,7 +71,6 @@ } set_pte(dst, pte); } - spin_unlock(&mm->page_table_lock); return error; } @@ -81,9 +79,11 @@ int error = 0; pte_t * src; + spin_lock(&mm->page_table_lock); src = get_one_pte(mm, old_addr); if (src) error = copy_one_pte(mm, src, alloc_one_pte(mm, new_addr)); + spin_unlock(&mm->page_table_lock); return error; } @@ -292,8 +292,8 @@ { unsigned long ret; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); ret = do_mremap(addr, old_len, new_len, flags, new_addr); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return ret; } diff -u --recursive --new-file v2.4.2/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.4.2/linux/mm/page_alloc.c Sat Feb 3 19:51:32 2001 +++ linux/mm/page_alloc.c Tue Mar 20 15:05:46 2001 @@ -455,8 +455,7 @@ memory_pressure++; try_to_free_pages(gfp_mask); wakeup_bdflush(0); - if (!order) - goto try_again; + goto try_again; } } 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 Sun Mar 25 10:37:48 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); @@ -1539,7 +1517,6 @@ return __kmem_cache_alloc(flags & GFP_DMA ? csizep->cs_dmacachep : csizep->cs_cachep, flags); } - BUG(); // too big size return NULL; } diff -u --recursive --new-file v2.4.2/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.4.2/linux/mm/swapfile.c Wed Feb 21 18:20:46 2001 +++ linux/mm/swapfile.c Thu Mar 22 09:22:15 2001 @@ -209,6 +209,7 @@ * share this swap entry, so be cautious and let do_wp_page work out * what to do if a write is requested later. */ +/* tasklist_lock and vma->vm_mm->page_table_lock are held */ static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address, pte_t *dir, swp_entry_t entry, struct page* page) { @@ -234,6 +235,7 @@ ++vma->vm_mm->rss; } +/* tasklist_lock and vma->vm_mm->page_table_lock are held */ static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long size, unsigned long offset, swp_entry_t entry, struct page* page) @@ -261,6 +263,7 @@ } while (address && (address < end)); } +/* tasklist_lock and vma->vm_mm->page_table_lock are held */ static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long size, swp_entry_t entry, struct page* page) @@ -291,6 +294,7 @@ } while (address && (address < end)); } +/* tasklist_lock and vma->vm_mm->page_table_lock are held */ static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir, swp_entry_t entry, struct page* page) { diff -u --recursive --new-file v2.4.2/linux/mm/vmalloc.c linux/mm/vmalloc.c --- v2.4.2/linux/mm/vmalloc.c Wed Feb 21 18:20:46 2001 +++ linux/mm/vmalloc.c Fri Mar 23 16:14:00 2001 @@ -102,9 +102,11 @@ end = PMD_SIZE; do { struct page * page; + spin_unlock(&init_mm.page_table_lock); + page = alloc_page(gfp_mask); + spin_lock(&init_mm.page_table_lock); if (!pte_none(*pte)) printk(KERN_ERR "alloc_area_pte: page already exists\n"); - page = alloc_page(gfp_mask); if (!page) return -ENOMEM; set_pte(pte, mk_pte(page, prot)); @@ -123,7 +125,7 @@ if (end > PGDIR_SIZE) end = PGDIR_SIZE; do { - pte_t * pte = pte_alloc_kernel(pmd, address); + pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; if (alloc_area_pte(pte, address, end - address, gfp_mask, prot)) @@ -143,11 +145,11 @@ dir = pgd_offset_k(address); flush_cache_all(); - lock_kernel(); + spin_lock(&init_mm.page_table_lock); do { pmd_t *pmd; - pmd = pmd_alloc_kernel(dir, address); + pmd = pmd_alloc(&init_mm, dir, address); ret = -ENOMEM; if (!pmd) break; @@ -161,7 +163,7 @@ ret = 0; } while (address && (address < end)); - unlock_kernel(); + spin_unlock(&init_mm.page_table_lock); flush_tlb_all(); return ret; } diff -u --recursive --new-file v2.4.2/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.4.2/linux/mm/vmscan.c Sat Feb 3 19:51:32 2001 +++ linux/mm/vmscan.c Thu Mar 22 11:00:51 2001 @@ -25,16 +25,15 @@ #include /* - * The swap-out functions return 1 if they successfully - * threw something out, and we got a free page. It returns - * zero if it couldn't do anything, and any other value - * indicates it decreased rss, but the page was shared. + * The swap-out function returns 1 if it successfully + * scanned all the pages it was asked to (`count'). + * It returns zero if it couldn't do anything, * - * NOTE! If it sleeps, it *must* return 1 to make sure we - * don't continue with the swap-out. Otherwise we may be - * using a process that no longer actually exists (it might - * have died while we slept). + * rss may decrease because pages are shared, but this + * doesn't count as having freed a page. */ + +/* mm->page_table_lock is held. mmap_sem is not held */ static void try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page) { pte_t pte; @@ -129,6 +128,7 @@ return; } +/* mm->page_table_lock is held. mmap_sem is not held */ static int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count) { pte_t * pte; @@ -165,6 +165,7 @@ return count; } +/* mm->page_table_lock is held. mmap_sem is not held */ static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count) { pmd_t * pmd; @@ -194,6 +195,7 @@ return count; } +/* mm->page_table_lock is held. mmap_sem is not held */ static int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count) { pgd_t *pgdir; @@ -218,6 +220,9 @@ return count; } +/* + * Returns non-zero if we scanned all `count' pages + */ static int swap_out_mm(struct mm_struct * mm, int count) { unsigned long address; 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/Makefile linux/net/atm/Makefile --- v2.4.2/linux/net/atm/Makefile Mon Jan 1 09:54:07 2001 +++ linux/net/atm/Makefile Mon Mar 26 15:36:30 2001 @@ -7,16 +7,14 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -include ../../.config +O_TARGET := atm.o -O_TARGET= atm.o +export-objs := common.o atm_misc.o raw.o resources.o ipcommon.o proc.o -export-objs = common.o atm_misc.o raw.o resources.o ipcommon.o proc.o +list-multi := mpoa.o +mpoa-objs := mpc.o mpoa_caches.o mpoa_proc.o -multi-list = mpoa.o -mpoa-objs = mpc.o mpoa_caches.o mpoa_proc.o - -obj-$(CONFIG_ATM) = addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o +obj-$(CONFIG_ATM) := addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o ifeq ($(CONFIG_ATM_CLIP),y) obj-y += clip.o 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/atm/proc.c linux/net/atm/proc.c --- v2.4.2/linux/net/atm/proc.c Fri Dec 29 14:35:47 2000 +++ linux/net/atm/proc.c Sun Mar 25 18:14:25 2001 @@ -561,7 +561,6 @@ dev->proc_entry->proc_fops = &proc_dev_atm_operations; dev->proc_entry->owner = THIS_MODULE; return 0; - kfree(dev->proc_entry); fail0: kfree(dev->proc_name); fail1: 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/core/dv.c linux/net/core/dv.c --- v2.4.2/linux/net/core/dv.c Mon Dec 11 12:37:04 2000 +++ linux/net/core/dv.c Sun Mar 25 18:14:25 2001 @@ -172,7 +172,7 @@ return -EINVAL; /* user issuing the ioctl must be a super one :) */ - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; /* Device must have a divert_blk member NOT null */ diff -u --recursive --new-file v2.4.2/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c --- v2.4.2/linux/net/decnet/af_decnet.c Wed Feb 21 18:20:47 2001 +++ linux/net/decnet/af_decnet.c Sun Mar 25 18:14:25 2001 @@ -1431,10 +1431,13 @@ struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); struct linkinfo_dn link; - int r_len = *optlen; + int r_len; void *r_data = NULL; - int val; + unsigned int val; + if(get_user(r_len , optlen)) + return -EFAULT; + switch(optname) { case DSO_CONDATA: if (r_len > sizeof(struct optdata_dn)) 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/devinet.c linux/net/ipv4/devinet.c --- v2.4.2/linux/net/ipv4/devinet.c Wed Feb 21 18:20:47 2001 +++ linux/net/ipv4/devinet.c Sun Mar 25 18:14:25 2001 @@ -1,7 +1,7 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.40 2001/02/05 06:03:47 davem Exp $ + * Version: $Id: devinet.c,v 1.41 2001/02/18 09:26:26 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -827,10 +827,8 @@ return NOTIFY_DONE; } -struct notifier_block ip_netdev_notifier={ - inetdev_event, - NULL, - 0 +struct notifier_block ip_netdev_notifier = { + notifier_call: inetdev_event, }; #ifdef CONFIG_RTNETLINK diff -u --recursive --new-file v2.4.2/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c --- v2.4.2/linux/net/ipv4/ip_fragment.c Fri Dec 29 14:07:24 2000 +++ linux/net/ipv4/ip_fragment.c Sun Mar 25 18:14:25 2001 @@ -213,18 +213,17 @@ if (ipq_hash[i] == NULL) continue; - write_lock(&ipfrag_lock); + read_lock(&ipfrag_lock); if ((qp = ipq_hash[i]) != NULL) { /* find the oldest queue for this hash bucket */ while (qp->next) qp = qp->next; - __ipq_unlink(qp); - write_unlock(&ipfrag_lock); + atomic_inc(&qp->refcnt); + read_unlock(&ipfrag_lock); spin_lock(&qp->lock); - if (del_timer(&qp->timer)) - atomic_dec(&qp->refcnt); - qp->last_in |= COMPLETE; + if (!(qp->last_in&COMPLETE)) + ipq_kill(qp); spin_unlock(&qp->lock); ipq_put(qp); @@ -232,7 +231,7 @@ progress = 1; continue; } - write_unlock(&ipfrag_lock); + read_unlock(&ipfrag_lock); } } while (progress); } 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/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.4.2/linux/net/ipv4/sysctl_net_ipv4.c Mon Oct 23 15:48:28 2000 +++ linux/net/ipv4/sysctl_net_ipv4.c Sun Mar 25 18:14:25 2001 @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.47 2000/10/19 15:51:02 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.48 2001/02/23 01:39:05 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -47,10 +47,11 @@ extern int inet_peer_gc_mintime; extern int inet_peer_gc_maxtime; +#ifdef CONFIG_SYSCTL static int tcp_retr1_max = 255; - static int ip_local_port_range_min[] = { 1, 1 }; static int ip_local_port_range_max[] = { 65535, 65535 }; +#endif struct ipv4_config ipv4_config; diff -u --recursive --new-file v2.4.2/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c --- v2.4.2/linux/net/ipv6/ip6_fib.c Sun Sep 17 10:03:43 2000 +++ linux/net/ipv6/ip6_fib.c Sun Mar 25 18:14:25 2001 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_fib.c,v 1.22 2000/09/12 00:38:34 davem Exp $ + * $Id: ip6_fib.c,v 1.23 2001/03/19 20:31:17 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -76,7 +76,7 @@ #endif static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); -static void fib6_repair_tree(struct fib6_node *fn); +static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); /* * A routing update causes an increase of the serial number on the @@ -774,7 +774,7 @@ * is the node we want to try and remove. */ -static void fib6_repair_tree(struct fib6_node *fn) +static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) { int children; int nstate; @@ -809,7 +809,7 @@ } #endif atomic_inc(&fn->leaf->rt6i_ref); - return; + return fn->parent; } pn = fn->parent; @@ -865,7 +865,7 @@ node_free(fn); if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn)) - return; + return pn; rt6_release(pn->leaf); pn->leaf = NULL; @@ -903,7 +903,26 @@ if (fn->leaf == NULL) { fn->fn_flags &= ~RTN_RTINFO; rt6_stats.fib_route_nodes--; - fib6_repair_tree(fn); + fn = fib6_repair_tree(fn); + } + + if (atomic_read(&rt->rt6i_ref) != 1) { + /* This route is used as dummy address holder in some split + * nodes. It is not leaked, but it still holds other resources, + * which must be released in time. So, scan ascendant nodes + * and replace dummy references to this route with references + * to still alive ones. + */ + while (fn) { + if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) { + fn->leaf = fib6_find_prefix(fn); + atomic_inc(&fn->leaf->rt6i_ref); + rt6_release(rt); + } + fn = fn->parent; + } + /* No more references are possiible at this point. */ + if (atomic_read(&rt->rt6i_ref) != 1) BUG(); } #ifdef CONFIG_RTNETLINK diff -u --recursive --new-file v2.4.2/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c --- v2.4.2/linux/net/ipv6/ipv6_sockglue.c Tue Nov 28 21:53:45 2000 +++ linux/net/ipv6/ipv6_sockglue.c Sun Mar 25 18:14:25 2001 @@ -7,7 +7,7 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.34 2000/11/28 13:44:28 davem Exp $ + * $Id: ipv6_sockglue.c,v 1.36 2001/02/26 05:59:07 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -252,6 +252,13 @@ if (optlen == 0) goto update; + + /* 1K is probably excessive + * 1K is surely not enough, 2K per standard header is 16K. + */ + retv = -EINVAL; + if (optlen > 64*1024) + break; opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); retv = -ENOBUFS; diff -u --recursive --new-file v2.4.2/linux/net/ipv6/reassembly.c linux/net/ipv6/reassembly.c --- v2.4.2/linux/net/ipv6/reassembly.c Mon Dec 11 12:37:04 2000 +++ linux/net/ipv6/reassembly.c Sun Mar 25 18:14:25 2001 @@ -203,18 +203,17 @@ if (ip6_frag_hash[i] == NULL) continue; - write_lock(&ip6_frag_lock); + read_lock(&ip6_frag_lock); if ((fq = ip6_frag_hash[i]) != NULL) { /* find the oldest queue for this hash bucket */ while (fq->next) fq = fq->next; - __fq_unlink(fq); - write_unlock(&ip6_frag_lock); + atomic_inc(&fq->refcnt); + read_unlock(&ip6_frag_lock); spin_lock(&fq->lock); - if (del_timer(&fq->timer)) - atomic_dec(&fq->refcnt); - fq->last_in |= COMPLETE; + if (!(fq->last_in&COMPLETE)) + fq_kill(fq); spin_unlock(&fq->lock); fq_put(fq); @@ -222,7 +221,7 @@ progress = 1; continue; } - write_unlock(&ip6_frag_lock); + read_unlock(&ip6_frag_lock); } } while (progress); } diff -u --recursive --new-file v2.4.2/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.4.2/linux/net/ipv6/tcp_ipv6.c Mon Jan 1 11:01:58 2001 +++ linux/net/ipv6/tcp_ipv6.c Sun Mar 25 18:14:25 2001 @@ -421,7 +421,7 @@ struct sock *sk2, **skp; struct tcp_tw_bucket *tw; - write_lock(&head->lock); + write_lock_bh(&head->lock); for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp)!=NULL; skp = &sk2->next) { tw = (struct tcp_tw_bucket*)sk2; 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 Mon Mar 26 15:43:01 2001 @@ -65,6 +65,12 @@ * Arnaldo Carvalho de Melo , * December, 2000 * Revision 044: Call ipxitf_hold on NETDEV_UP (acme) + * Revision 045: fix PPROP routing bug (acme) + * Revision 046: Further fixes to PPROP, ipxitf_create_internal was + * doing an unneeded MOD_INC_USE_COUNT, implement + * sysctl for ipx_pprop_broacasting, fix the ipx sysctl + * handling, making it dynamic, some cleanups, thanks to + * Petr Vandrovec for review and good suggestions. (acme) * * Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT * pair. Also, now usage count is managed this way @@ -81,7 +87,6 @@ */ #include -#if defined (CONFIG_IPX) || defined (CONFIG_IPX_MODULE) #include #include #include @@ -111,14 +116,14 @@ #include #include -#ifdef MODULE -static void ipx_proto_finito(void); -#endif /* def MODULE */ +extern void ipx_register_sysctl(void); +extern void ipx_unregister_sysctl(void); /* Configuration Variables */ static unsigned char ipxcfg_max_hops = 16; static char ipxcfg_auto_select_primary; static char ipxcfg_auto_create_interfaces; +static int sysctl_ipx_pprop_broadcasting = 1; /* Global Variables */ static struct datalink_proto *p8022_datalink; @@ -139,6 +144,8 @@ static ipx_interface *ipx_primary_net; static ipx_interface *ipx_internal_net; +#define IPX_SKB_CB(__skb) ((struct ipx_cb *)&((__skb)->cb[0])) + #undef IPX_REFCNT_DEBUG #ifdef IPX_REFCNT_DEBUG atomic_t ipx_sock_nr; @@ -450,11 +457,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); @@ -674,17 +682,30 @@ return skb2; } -/* caller must hold a reference to intrfc */ +/* caller must hold a reference to intrfc and the skb has to be unshared */ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node) { struct ipxhdr *ipx = skb->nh.ipxh; - struct ipx_cb *cb = (struct ipx_cb *) skb->cb; struct net_device *dev = intrfc->if_dev; struct datalink_proto *dl = intrfc->if_dlink; char dest_node[IPX_NODE_LEN]; int send_to_wire = 1; int addr_len; + + ipx->ipx_tctrl = IPX_SKB_CB(skb)->ipx_tctrl; + ipx->ipx_dest.net = IPX_SKB_CB(skb)->ipx_dest_net; + ipx->ipx_source.net = IPX_SKB_CB(skb)->ipx_source_net; + + /* see if we need to include the netnum in the route list */ + if (IPX_SKB_CB(skb)->last_hop.index >= 0) { + u32 *last_hop = (u32 *)(((u8 *) skb->data) + + sizeof(struct ipxhdr) + + IPX_SKB_CB(skb)->last_hop.index * + sizeof(u32)); + *last_hop = IPX_SKB_CB(skb)->last_hop.netnum; + IPX_SKB_CB(skb)->last_hop.index = -1; + } /* * We need to know how many skbuffs it will take to send out this @@ -701,7 +722,7 @@ * up clones. */ - if (cb->ipx_dest_net == intrfc->if_netnum) { + if (ipx->ipx_dest.net == intrfc->if_netnum) { /* * To our own node, loop and free the original. * The internal net will receive on all node address. @@ -730,7 +751,7 @@ * We are still charging the sender. Which is right - the driver * free will handle this fairly. */ - if (cb->ipx_source_net != intrfc->if_netnum) { + if (ipx->ipx_source.net != intrfc->if_netnum) { /* * Unshare the buffer before modifying the count in * case its a flood or tcpdump @@ -738,7 +759,7 @@ skb = skb_unshare(skb, GFP_ATOMIC); if (!skb) return 0; - if (++(cb->ipx_tctrl) > ipxcfg_max_hops) + if (++ipx->ipx_tctrl > ipxcfg_max_hops) send_to_wire = 0; } @@ -759,17 +780,6 @@ if (!skb) return 0; - ipx->ipx_tctrl = cb->ipx_tctrl; - ipx->ipx_dest.net = cb->ipx_dest_net; - ipx->ipx_source.net = cb->ipx_source_net; - /* see if we need to include the netnum in the route list */ - if (cb->last_hop_index >= 0) { - u32 *last_hop = (u32 *)(((u8 *) skb->data) + - sizeof(struct ipxhdr) + cb->last_hop_index * - sizeof(u32)); - *last_hop = intrfc->if_netnum; - } - /* set up data link and physical headers */ skb->dev = dev; skb->protocol = htons(ETH_P_IPX); @@ -789,93 +799,40 @@ static const char * ipx_frame_name(unsigned short); static const char * ipx_device_name(ipx_interface *); +static void ipxitf_discover_netnum(ipx_interface *intrfc, struct sk_buff *skb); +static int ipxitf_pprop(ipx_interface *intrfc, struct sk_buff *skb); static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb) { struct ipxhdr *ipx = skb->nh.ipxh; - struct ipx_cb *cb = (struct ipx_cb *) skb->cb; int ret = 0; ipxitf_hold(intrfc); /* See if we should update our network number */ - if (!intrfc->if_netnum && /* net number of intrfc not known yet */ - cb->ipx_source_net == cb->ipx_dest_net && /* intra packet */ - cb->ipx_source_net) { - ipx_interface *i = ipxitf_find_using_net(cb->ipx_source_net); - /* NB: NetWare servers lie about their hop count so we - * dropped the test based on it. This is the best way - * to determine this is a 0 hop count packet. - */ - if (!i) { - intrfc->if_netnum = cb->ipx_source_net; - ipxitf_add_local_route(intrfc); - } else { - printk(KERN_WARNING "IPX: Network number collision %lx\n %s %s and %s %s\n", - (long unsigned int) htonl(cb->ipx_source_net), - ipx_device_name(i), - ipx_frame_name(i->if_dlink_type), - ipx_device_name(intrfc), - ipx_frame_name(intrfc->if_dlink_type)); - ipxitf_put(i); - } - } + if (!intrfc->if_netnum) /* net number of intrfc not known yet */ + ipxitf_discover_netnum(intrfc, skb); - cb->last_hop_index = -1; - - if (ipx->ipx_type == IPX_TYPE_PPROP && cb->ipx_tctrl < 8 && - skb->pkt_type != PACKET_OTHERHOST && - /* header + 8 network numbers */ - ntohs(ipx->ipx_pktsize) >= sizeof(struct ipxhdr) + 8 * 4) { - int i; - ipx_interface *ifcs; - struct sk_buff *skb2; - char *c = ((char *) skb->data) + sizeof(struct ipxhdr); - u32 *l = (u32 *) c; - - /* Dump packet if already seen this net */ - for (i = 0; i < cb->ipx_tctrl; i++) - if (*l++ == intrfc->if_netnum) - break; - - if (i == cb->ipx_tctrl) { - /* < 8 hops && input itfc not in list */ - /* insert recvd netnum into list */ - cb->last_hop_index = i; - cb->ipx_tctrl++; - /* xmit on all other interfaces... */ - spin_lock_bh(&ipx_interfaces_lock); - for (ifcs = ipx_interfaces; ifcs; - ifcs = ifcs->if_next) { - /* Except unconfigured interfaces */ - if (!ifcs->if_netnum) - continue; - - /* That aren't in the list */ - l = (__u32 *) c; - for (i = 0; i <= cb->ipx_tctrl; i++) - if (ifcs->if_netnum == *l++) - break; - if (i - 1 == cb->ipx_tctrl) { - cb->ipx_dest_net = ifcs->if_netnum; - skb2=skb_clone(skb, GFP_ATOMIC); - if (skb2) - ipxrtr_route_skb(skb2); - } - } - spin_unlock_bh(&ipx_interfaces_lock); - } + IPX_SKB_CB(skb)->last_hop.index = -1; + if (ipx->ipx_type == IPX_TYPE_PPROP) { + ret = ipxitf_pprop(intrfc, skb); + if (ret) + goto out_free_skb; } - if (!cb->ipx_dest_net) - cb->ipx_dest_net = intrfc->if_netnum; - if (!cb->ipx_source_net) - cb->ipx_source_net = intrfc->if_netnum; - - if (intrfc->if_netnum != cb->ipx_dest_net) { + /* local processing follows */ + if (!IPX_SKB_CB(skb)->ipx_dest_net) + IPX_SKB_CB(skb)->ipx_dest_net = intrfc->if_netnum; + if (!IPX_SKB_CB(skb)->ipx_source_net) + IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum; + + /* it doesn't make sense to route a pprop packet, there's no meaning + * in the ipx_dest_net for such packets */ + if (ipx->ipx_type != IPX_TYPE_PPROP && + intrfc->if_netnum != IPX_SKB_CB(skb)->ipx_dest_net) { /* We only route point-to-point packets. */ if (skb->pkt_type == PACKET_HOST) { - skb=skb_unshare(skb, GFP_ATOMIC); + skb = skb_unshare(skb, GFP_ATOMIC); if (skb) ret = ipxrtr_route_skb(skb); goto out_intrfc; @@ -899,6 +856,124 @@ return ret; } +static void ipxitf_discover_netnum(ipx_interface *intrfc, struct sk_buff *skb) +{ + const struct ipx_cb *cb = IPX_SKB_CB(skb); + + /* see if this is an intra packet: source_net == dest_net */ + if (cb->ipx_source_net == cb->ipx_dest_net && cb->ipx_source_net) { + ipx_interface *i = ipxitf_find_using_net(cb->ipx_source_net); + /* NB: NetWare servers lie about their hop count so we + * dropped the test based on it. This is the best way + * to determine this is a 0 hop count packet. */ + if (!i) { + intrfc->if_netnum = cb->ipx_source_net; + ipxitf_add_local_route(intrfc); + } else { + printk(KERN_WARNING "IPX: Network number collision " + "%lx\n %s %s and %s %s\n", + (unsigned long) htonl(cb->ipx_source_net), + ipx_device_name(i), + ipx_frame_name(i->if_dlink_type), + ipx_device_name(intrfc), + ipx_frame_name(intrfc->if_dlink_type)); + ipxitf_put(i); + } + } +} + +/** + * ipxitf_pprop - Process packet propagation IPX packet type 0x14, used for + * NetBIOS broadcasts + * @intrfc: IPX interface receiving this packet + * @skb: Received packet + * + * Checks if packet is valid: if its more than %IPX_MAX_PPROP_HOPS hops or if it + * is smaller than a IPX header + the room for %IPX_MAX_PPROP_HOPS hops we drop + * it, not even processing it locally, if it has exact %IPX_MAX_PPROP_HOPS we + * don't broadcast it, but process it locally. See chapter 5 of Novell's "IPX + * RIP and SAP Router Specification", Part Number 107-000029-001. + * + * If it is valid, check if we have pprop broadcasting enabled by the user, + * if not, just return zero for local processing. + * + * If it is enabled check the packet and don't broadcast it if we have already + * seen this packet. + * + * Broadcast: send it to the interfaces that aren't on the packet visited nets + * array, just after the IPX header. + * + * Returns -EINVAL for invalid packets, so that the calling function drops + * the packet without local processing. 0 if packet is to be locally processed. + */ +static int ipxitf_pprop(ipx_interface *intrfc, struct sk_buff *skb) +{ + struct ipxhdr *ipx = skb->nh.ipxh; + int i, ret = -EINVAL; + ipx_interface *ifcs; + char *c; + u32 *l; + + /* Illegal packet - too many hops or too short */ + /* We decide to throw it away: no broadcasting, no local processing. + * NetBIOS unaware implementations route them as normal packets - + * tctrl <= 15, any data payload... */ + if (IPX_SKB_CB(skb)->ipx_tctrl > IPX_MAX_PPROP_HOPS || + ntohs(ipx->ipx_pktsize) < sizeof(struct ipxhdr) + + IPX_MAX_PPROP_HOPS * sizeof(u32)) + goto out; + /* are we broadcasting this damn thing? */ + ret = 0; + if (!sysctl_ipx_pprop_broadcasting) + goto out; + /* We do broadcast packet on the IPX_MAX_PPROP_HOPS hop, but we + * process it locally. All previous hops broadcasted it, and process it + * locally. */ + if (IPX_SKB_CB(skb)->ipx_tctrl == IPX_MAX_PPROP_HOPS) + goto out; + + c = ((u8 *) ipx) + sizeof(struct ipxhdr); + l = (u32 *) c; + + /* Don't broadcast packet if already seen this net */ + for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++) + if (*l++ == intrfc->if_netnum) + goto out; + + /* < IPX_MAX_PPROP_HOPS hops && input interface not in list. Save the + * position where we will insert recvd netnum into list, later on, + * in ipxitf_send */ + IPX_SKB_CB(skb)->last_hop.index = i; + IPX_SKB_CB(skb)->last_hop.netnum = intrfc->if_netnum; + /* xmit on all other interfaces... */ + spin_lock_bh(&ipx_interfaces_lock); + for (ifcs = ipx_interfaces; ifcs; ifcs = ifcs->if_next) { + /* Except unconfigured interfaces */ + if (!ifcs->if_netnum) + continue; + + /* That aren't in the list */ + if (ifcs == intrfc) + continue; + l = (__u32 *) c; + /* don't consider the last entry in the packet list, + * it is our netnum, and it is not there yet */ + for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++) + if (ifcs->if_netnum == *l++) + break; + if (i == IPX_SKB_CB(skb)->ipx_tctrl) { + struct sk_buff *s = skb_copy(skb, GFP_ATOMIC); + + if (s) { + IPX_SKB_CB(s)->ipx_dest_net = ifcs->if_netnum; + ipxrtr_route_skb(s); + } + } + } + spin_unlock_bh(&ipx_interfaces_lock); +out: return ret; +} + static void ipxitf_insert(ipx_interface *intrfc) { ipx_interface *i; @@ -918,6 +993,30 @@ ipx_primary_net = intrfc; } +static ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum, + unsigned short dlink_type, + struct datalink_proto *dlink, + unsigned char internal, int ipx_offset) +{ + ipx_interface *intrfc = kmalloc(sizeof(ipx_interface), GFP_ATOMIC); + + if (intrfc) { + intrfc->if_dev = dev; + intrfc->if_netnum = netnum; + intrfc->if_dlink_type = dlink_type; + intrfc->if_dlink = dlink; + intrfc->if_internal = internal; + intrfc->if_ipx_offset = ipx_offset; + intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET; + intrfc->if_sklist = NULL; + atomic_set(&intrfc->refcnt, 1); + spin_lock_init(&intrfc->if_sklist_lock); + MOD_INC_USE_COUNT; + } + + return intrfc; +} + static int ipxitf_create_internal(ipx_interface_definition *idef) { ipx_interface *intrfc; @@ -935,23 +1034,11 @@ ipxitf_put(intrfc); return -EADDRINUSE; } - - intrfc = kmalloc(sizeof(ipx_interface),GFP_ATOMIC); + intrfc = ipxitf_alloc(NULL, idef->ipx_network, 0, NULL, 1, 0); if (!intrfc) return -EAGAIN; - intrfc->if_dev = NULL; - intrfc->if_netnum = idef->ipx_network; - intrfc->if_dlink_type = 0; - intrfc->if_dlink = NULL; - intrfc->if_sklist = NULL; - intrfc->if_internal = 1; - intrfc->if_ipx_offset = 0; - intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET; memcpy((char *)&(intrfc->if_node), idef->ipx_node, IPX_NODE_LEN); ipx_internal_net = ipx_primary_net = intrfc; - spin_lock_init(&intrfc->if_sklist_lock); - atomic_set(&intrfc->refcnt, 1); - MOD_INC_USE_COUNT; ipxitf_hold(intrfc); ipxitf_insert(intrfc); @@ -1040,7 +1127,8 @@ case IPX_FRAME_NONE: default: - break; + err = -EPROTONOSUPPORT; + goto out_dev; } err = -ENETDOWN; @@ -1052,28 +1140,18 @@ if (dev->addr_len > IPX_NODE_LEN) goto out_dev; - err = -EPROTONOSUPPORT; - if (!datalink) - goto out_dev; - intrfc = ipxitf_find_using_phys(dev, dlink_type); if (!intrfc) { /* Ok now create */ - intrfc = kmalloc(sizeof(ipx_interface), GFP_ATOMIC); + intrfc = ipxitf_alloc(dev, idef->ipx_network, dlink_type, + datalink, 0, dev->hard_header_len + + datalink->header_length); err = -EAGAIN; if (!intrfc) goto out_dev; - intrfc->if_dev = dev; - intrfc->if_netnum = idef->ipx_network; - intrfc->if_dlink_type = dlink_type; - intrfc->if_dlink = datalink; - intrfc->if_sklist = NULL; - intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET; /* Setup primary if necessary */ if (idef->ipx_special == IPX_PRIMARY) ipx_primary_net = intrfc; - intrfc->if_internal = 0; - intrfc->if_ipx_offset = dev->hard_header_len + datalink->header_length; if (!memcmp(idef->ipx_node, "\000\000\000\000\000\000", IPX_NODE_LEN)) { memset(intrfc->if_node, 0, IPX_NODE_LEN); @@ -1081,9 +1159,6 @@ dev->dev_addr, dev->addr_len); } else memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN); - spin_lock_init(&intrfc->if_sklist_lock); - atomic_set(&intrfc->refcnt, 1); - MOD_INC_USE_COUNT; ipxitf_hold(intrfc); ipxitf_insert(intrfc); } @@ -1145,8 +1220,15 @@ static ipx_interface *ipxitf_auto_create(struct net_device *dev, unsigned short dlink_type) { - struct datalink_proto *datalink = NULL; - ipx_interface *intrfc; + ipx_interface *intrfc = NULL; + struct datalink_proto *datalink; + + if (!dev) + goto out; + + /* Check addresses are suitable */ + if (dev->addr_len > IPX_NODE_LEN) + goto out; switch (htons(dlink_type)) { case ETH_P_IPX: @@ -1166,38 +1248,23 @@ break; default: - return NULL; + goto out; } - if (!dev) - return NULL; - - /* Check addresses are suitable */ - if (dev->addr_len > IPX_NODE_LEN) - return NULL; + intrfc = ipxitf_alloc(dev, 0, dlink_type, datalink, 0, + dev->hard_header_len + datalink->header_length); - intrfc = kmalloc(sizeof(ipx_interface), GFP_ATOMIC); if (intrfc) { - intrfc->if_dev = dev; - intrfc->if_netnum = 0; - intrfc->if_dlink_type = dlink_type; - intrfc->if_dlink = datalink; - intrfc->if_sklist = NULL; - intrfc->if_internal = 0; - intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET; - intrfc->if_ipx_offset = dev->hard_header_len + - datalink->header_length; memset(intrfc->if_node, 0, IPX_NODE_LEN); memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]), dev->dev_addr, dev->addr_len); spin_lock_init(&intrfc->if_sklist_lock); atomic_set(&intrfc->refcnt, 1); - MOD_INC_USE_COUNT; ipxitf_insert(intrfc); dev_hold(dev); } - return intrfc; +out: return intrfc; } static int ipxitf_ioctl(unsigned int cmd, void *arg) @@ -1283,6 +1350,17 @@ * * \**************************************************************************/ +static inline void ipxrtr_hold(ipx_route *rt) +{ + atomic_inc(&rt->refcnt); +} + +static inline void ipxrtr_put(ipx_route *rt) +{ + if (atomic_dec_and_test(&rt->refcnt)) + kfree(rt); +} + static ipx_route *ipxrtr_lookup(__u32 net) { ipx_route *r; @@ -1290,6 +1368,8 @@ read_lock_bh(&ipx_routes_lock); for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next) ; + if (r) + ipxrtr_hold(r); read_unlock_bh(&ipx_routes_lock); return r; @@ -1300,21 +1380,27 @@ static int ipxrtr_add_route(__u32 network, ipx_interface *intrfc, unsigned char *node) { ipx_route *rt; + int ret; /* Get a route structure; either existing or create */ rt = ipxrtr_lookup(network); if (!rt) { rt = kmalloc(sizeof(ipx_route),GFP_ATOMIC); + ret = -EAGAIN; if (!rt) - return -EAGAIN; + goto out; + atomic_set(&rt->refcnt, 1); + ipxrtr_hold(rt); write_lock_bh(&ipx_routes_lock); rt->ir_next = ipx_routes; ipx_routes = rt; write_unlock_bh(&ipx_routes_lock); + } else { + ret = -EEXIST; + if (intrfc == ipx_internal_net) + goto out_put; } - else if (intrfc == ipx_internal_net) - return -EEXIST; rt->ir_net = network; rt->ir_intrfc = intrfc; @@ -1326,7 +1412,10 @@ rt->ir_routed = 1; } - return 0; + ret = 0; +out_put: + ipxrtr_put(rt); +out: return ret; } static void ipxrtr_del_routes(ipx_interface *intrfc) @@ -1337,7 +1426,7 @@ for (r = &ipx_routes; (tmp = *r) != NULL;) { if (tmp->ir_intrfc == intrfc) { *r = tmp->ir_next; - kfree(tmp); + ipxrtr_put(tmp); } else r = &(tmp->ir_next); } @@ -1373,7 +1462,7 @@ goto out; *r = tmp->ir_next; - kfree(tmp); + ipxrtr_put(tmp); err = 0; goto out; } @@ -1432,7 +1521,6 @@ struct sk_buff *skb; ipx_interface *intrfc; struct ipxhdr *ipx; - struct ipx_cb *cb; int size; int ipx_offset; ipx_route *rt = NULL; @@ -1444,9 +1532,9 @@ intrfc = ipx_primary_net; } else { rt = ipxrtr_lookup(usipx->sipx_network); + err = -ENETUNREACH; if (!rt) - return -ENETUNREACH; - + goto out; intrfc = rt->ir_intrfc; } @@ -1456,45 +1544,44 @@ skb = sock_alloc_send_skb(sk, size, 0, noblock, &err); if (!skb) - goto out; + goto out_put; skb_reserve(skb,ipx_offset); skb->sk = sk; - cb = (struct ipx_cb *) skb->cb; /* Fill in IPX header */ ipx = (struct ipxhdr *)skb_put(skb, sizeof(struct ipxhdr)); ipx->ipx_pktsize= htons(len + sizeof(struct ipxhdr)); - cb->ipx_tctrl = 0; + IPX_SKB_CB(skb)->ipx_tctrl = 0; ipx->ipx_type = usipx->sipx_type; skb->h.raw = (void *)skb->nh.ipxh = ipx; - cb->last_hop_index = -1; - + IPX_SKB_CB(skb)->last_hop.index = -1; #ifdef CONFIG_IPX_INTERN - cb->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum; + IPX_SKB_CB(skb)->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum; memcpy(ipx->ipx_source.node, sk->protinfo.af_ipx.node, IPX_NODE_LEN); #else err = ntohs(sk->protinfo.af_ipx.port); if (err == 0x453 || err == 0x452) { /* RIP/SAP special handling for mars_nwe */ - cb->ipx_source_net = intrfc->if_netnum; + IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum; memcpy(ipx->ipx_source.node, intrfc->if_node, IPX_NODE_LEN); } else { - cb->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum; + IPX_SKB_CB(skb)->ipx_source_net = + sk->protinfo.af_ipx.intrfc->if_netnum; memcpy(ipx->ipx_source.node, sk->protinfo.af_ipx.intrfc->if_node, IPX_NODE_LEN); } #endif /* CONFIG_IPX_INTERN */ ipx->ipx_source.sock = sk->protinfo.af_ipx.port; - cb->ipx_dest_net = usipx->sipx_network; + IPX_SKB_CB(skb)->ipx_dest_net = usipx->sipx_network; memcpy(ipx->ipx_dest.node,usipx->sipx_node,IPX_NODE_LEN); ipx->ipx_dest.sock = usipx->sipx_port; err = memcpy_fromiovec(skb_put(skb,len),iov,len); if (err) { kfree_skb(skb); - goto out; + goto out_put; } /* Apply checksum. Not allowed on 802.3 links. */ @@ -1505,15 +1592,19 @@ err = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? rt->ir_router_node : ipx->ipx_dest.node); -out: ipxitf_put(intrfc); - return err; +out_put: + ipxitf_put(intrfc); + if (rt) + ipxrtr_put(rt); +out: return err; } - + +/* the skb has to be unshared, we'll end up calling ipxitf_send, that'll + * modify the packet */ int ipxrtr_route_skb(struct sk_buff *skb) { struct ipxhdr *ipx = skb->nh.ipxh; - struct ipx_cb *cb = (struct ipx_cb *) skb->cb; - ipx_route *r = ipxrtr_lookup(cb->ipx_dest_net); + ipx_route *r = ipxrtr_lookup(IPX_SKB_CB(skb)->ipx_dest_net); if (!r) { /* no known route */ kfree_skb(skb); @@ -1524,6 +1615,7 @@ ipxitf_send(r->ir_intrfc, skb, (r->ir_routed) ? r->ir_router_node : ipx->ipx_dest.node); ipxitf_put(r->ir_intrfc); + ipxrtr_put(r); return 0; } @@ -2033,6 +2125,7 @@ { struct sock *sk = sock->sk; struct sockaddr_ipx *addr; + ipx_route *rt; sk->state = TCP_CLOSE; sock->state = SS_UNCONNECTED; @@ -2064,8 +2157,8 @@ /* We can either connect to primary network or somewhere * we can route to */ - if (!(!addr->sipx_network && ipx_primary_net) && - !ipxrtr_lookup(addr->sipx_network)) + rt = ipxrtr_lookup(addr->sipx_network); + if (!rt && !(!addr->sipx_network && ipx_primary_net)) return -ENETUNREACH; sk->protinfo.af_ipx.dest_addr.net = addr->sipx_network; @@ -2079,6 +2172,8 @@ sk->state = TCP_ESTABLISHED; } + if (rt) + ipxrtr_put(rt); return 0; } @@ -2129,7 +2224,6 @@ /* NULL here for pt means the packet was looped back */ ipx_interface *intrfc; struct ipxhdr *ipx; - struct ipx_cb *cb; u16 ipx_pktsize; int ret; @@ -2151,21 +2245,22 @@ ipx->ipx_checksum != ipx_cksum(ipx, ipx_pktsize)) goto drop; - cb = (struct ipx_cb *) skb->cb; - cb->ipx_tctrl = ipx->ipx_tctrl; - cb->ipx_dest_net = ipx->ipx_dest.net; - cb->ipx_source_net = ipx->ipx_source.net; + IPX_SKB_CB(skb)->ipx_tctrl = ipx->ipx_tctrl; + IPX_SKB_CB(skb)->ipx_dest_net = ipx->ipx_dest.net; + IPX_SKB_CB(skb)->ipx_source_net = ipx->ipx_source.net; /* Determine what local ipx endpoint this is */ intrfc = ipxitf_find_using_phys(dev, pt->type); if (!intrfc) { if (ipxcfg_auto_create_interfaces && - ntohl(cb->ipx_dest_net)) { + ntohl(IPX_SKB_CB(skb)->ipx_dest_net)) { intrfc = ipxitf_auto_create(dev, pt->type); - ipxitf_hold(intrfc); + if (intrfc) + ipxitf_hold(intrfc); } if (!intrfc) /* Not one of ours */ + /* or invalid packet for auto creation */ goto drop; } @@ -2290,11 +2385,10 @@ msg->msg_namelen = sizeof(*sipx); if (sipx) { - struct ipx_cb *cb = (struct ipx_cb *) skb->cb; sipx->sipx_family = AF_IPX; sipx->sipx_port = ipx->ipx_source.sock; memcpy(sipx->sipx_node,ipx->ipx_source.node,IPX_NODE_LEN); - sipx->sipx_network = cb->ipx_source_net; + sipx->sipx_network = IPX_SKB_CB(skb)->ipx_source_net; sipx->sipx_type = ipx->ipx_type; } err = copied; @@ -2469,6 +2563,10 @@ static unsigned char ipx_8022_type = 0xE0; static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 }; +static const char banner[] __initdata = + KERN_INFO "NET4: Linux IPX 0.46 for NET4.0\n" + KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n" \ + KERN_INFO "IPX Portions Copyright (c) 2000, 2001 Conectiva, Inc.\n"; static int __init ipx_init(void) { @@ -2489,14 +2587,13 @@ printk(KERN_CRIT "IPX: Unable to register with SNAP\n"); register_netdevice_notifier(&ipx_dev_notifier); + ipx_register_sysctl(); #ifdef CONFIG_PROC_FS proc_net_create("ipx", 0, ipx_get_info); proc_net_create("ipx_interface", 0, ipx_interface_get_info); proc_net_create("ipx_route", 0, ipx_rt_get_info); #endif - printk(KERN_INFO "NET4: Linux IPX 0.44 for NET4.0\n"); - printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n"); - printk(KERN_INFO "IPX Portions Copyright (c) 2000 Conectiva, Inc.\n"); + printk(banner); return 0; } @@ -2506,8 +2603,13 @@ int ipx_if_offset(unsigned long ipx_net_number) { ipx_route *rt = ipxrtr_lookup(ipx_net_number); + int ret = -ENETUNREACH; - return rt ? rt->ir_intrfc->if_ipx_offset : -ENETUNREACH; + if (!rt) + goto out; + ret = rt->ir_intrfc->if_ipx_offset; + ipxrtr_put(rt); +out: return ret; } /* Export symbols for higher layers */ @@ -2530,8 +2632,7 @@ * sockets be closed from user space. */ -#ifdef MODULE -static void ipx_proto_finito(void) +static void __exit ipx_proto_finito(void) { /* no need to worry about having anything on the ipx_interfaces * list, when a interface is created we increment the module @@ -2541,6 +2642,7 @@ proc_net_remove("ipx_route"); proc_net_remove("ipx_interface"); proc_net_remove("ipx"); + ipx_unregister_sysctl(); unregister_netdevice_notifier(&ipx_dev_notifier); @@ -2562,5 +2664,3 @@ } module_exit(ipx_proto_finito); -#endif /* MODULE */ -#endif /* CONFIG_IPX || CONFIG_IPX_MODULE */ diff -u --recursive --new-file v2.4.2/linux/net/ipx/sysctl_net_ipx.c linux/net/ipx/sysctl_net_ipx.c --- v2.4.2/linux/net/ipx/sysctl_net_ipx.c Mon Apr 1 22:03:35 1996 +++ linux/net/ipx/sysctl_net_ipx.c Sun Mar 25 18:14:25 2001 @@ -3,11 +3,51 @@ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipx directory entry (empty =) ). [MS] + * Added /proc/sys/net/ipx/ipx_pprop_broadcasting - acme March 4, 2001 */ #include #include +/* From af_ipx.c */ +extern int sysctl_ipx_pprop_broadcasting; + +#ifdef CONFIG_SYSCTL ctl_table ipx_table[] = { - {0} + { NET_IPX_PPROP_BROADCASTING, "ipx_pprop_broadcasting", + &sysctl_ipx_pprop_broadcasting, sizeof(int), 0644, NULL, + &proc_dointvec }, + { 0 } +}; + +static ctl_table ipx_dir_table[] = { + { NET_IPX, "ipx", NULL, 0, 0555, ipx_table }, + { 0 } +}; + +static ctl_table ipx_root_table[] = { + { CTL_NET, "net", NULL, 0, 0555, ipx_dir_table }, + { 0 } }; + +static struct ctl_table_header *ipx_table_header; + +void ipx_register_sysctl(void) +{ + ipx_table_header = register_sysctl_table(ipx_root_table, 1); +} + +void ipx_unregister_sysctl(void) +{ + unregister_sysctl_table(ipx_table_header); +} + +#else +void ipx_register_sysctl(void) +{ +} + +void ipx_unregister_sysctl(void) +{ +} +#endif 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/Makefile linux/net/irda/ircomm/Makefile --- v2.4.2/linux/net/irda/ircomm/Makefile Fri Dec 29 14:07:24 2000 +++ linux/net/irda/ircomm/Makefile Mon Mar 26 15:36:30 2001 @@ -9,7 +9,7 @@ O_TARGET := ircomm_and_tty.o -multi-objs := ircomm.o ircomm-tty.o +list-multi := ircomm.o ircomm-tty.o ircomm-objs := ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o ircomm-tty-objs := ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o ircomm_param.o 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/khttpd/main.c linux/net/khttpd/main.c --- v2.4.2/linux/net/khttpd/main.c Fri Nov 17 16:48:51 2000 +++ linux/net/khttpd/main.c Sun Mar 25 18:14:25 2001 @@ -138,7 +138,7 @@ changes +=DataSending(CPUNR); changes +=Userspace(CPUNR); changes +=Logging(CPUNR); - /* Test for incomming connections _again_, because it is possible + /* Test for incoming connections _again_, because it is possible one came in during the other steps, and the wakeup doesn't happen then. */ diff -u --recursive --new-file v2.4.2/linux/net/khttpd/rfc.c linux/net/khttpd/rfc.c --- v2.4.2/linux/net/khttpd/rfc.c Wed Feb 21 18:20:48 2001 +++ linux/net/khttpd/rfc.c Sun Mar 25 18:14:25 2001 @@ -101,7 +101,7 @@ /* The returned string is for READ ONLY, ownership of the memory is NOT - transfered. + transferred. */ { diff -u --recursive --new-file v2.4.2/linux/net/netsyms.c linux/net/netsyms.c --- v2.4.2/linux/net/netsyms.c Wed Feb 21 18:20:48 2001 +++ linux/net/netsyms.c Sun Mar 25 18:24:31 2001 @@ -432,17 +432,7 @@ #endif /* CONFIG_INET */ #ifdef CONFIG_TR -EXPORT_SYMBOL(tr_setup); EXPORT_SYMBOL(tr_type_trans); -EXPORT_SYMBOL(register_trdev); -EXPORT_SYMBOL(unregister_trdev); -EXPORT_SYMBOL(init_trdev); -#endif - -#ifdef CONFIG_NET_FC -EXPORT_SYMBOL(register_fcdev); -EXPORT_SYMBOL(unregister_fcdev); -EXPORT_SYMBOL(init_fcdev); #endif /* Device callback registration */ @@ -451,14 +441,10 @@ /* support for loadable net drivers */ #ifdef CONFIG_NET -EXPORT_SYMBOL(init_etherdev); EXPORT_SYMBOL(loopback_dev); EXPORT_SYMBOL(register_netdevice); EXPORT_SYMBOL(unregister_netdevice); -EXPORT_SYMBOL(register_netdev); -EXPORT_SYMBOL(unregister_netdev); EXPORT_SYMBOL(netdev_state_change); -EXPORT_SYMBOL(ether_setup); EXPORT_SYMBOL(dev_new_index); EXPORT_SYMBOL(dev_get_by_index); EXPORT_SYMBOL(__dev_get_by_index); @@ -469,8 +455,6 @@ EXPORT_SYMBOL(eth_type_trans); #ifdef CONFIG_FDDI EXPORT_SYMBOL(fddi_type_trans); -EXPORT_SYMBOL(fddi_setup); -EXPORT_SYMBOL(init_fddidev); #endif /* CONFIG_FDDI */ #if 0 EXPORT_SYMBOL(eth_copy_and_sum); @@ -511,8 +495,6 @@ #ifdef CONFIG_HIPPI EXPORT_SYMBOL(hippi_type_trans); -EXPORT_SYMBOL(init_hippi_dev); -EXPORT_SYMBOL(unregister_hipdev); #endif #ifdef CONFIG_SYSCTL @@ -522,12 +504,6 @@ EXPORT_SYMBOL(sysctl_ip_default_ttl); #endif #endif - -#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) -#include -EXPORT_SYMBOL(ltalk_setup); -#endif - /* Packet scheduler modules want these. */ EXPORT_SYMBOL(qdisc_destroy); 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 Sun Mar 25 18:14:25 2001 @@ -76,7 +76,7 @@ struct tcindex_filter *f; if (p->perfect) - return p->perfect[key].res.classid ? p->perfect+key : NULL; + return p->perfect[key].res.class ? p->perfect+key : NULL; if (!p->h) return NULL; for (f = p->h[key % p->hash]; f; f = f->next) { @@ -122,8 +122,14 @@ static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle) { + struct tcindex_data *p = PRIV(tp); + struct tcindex_filter_result *r; + DPRINTK("tcindex_get(tp %p,handle 0x%08x)\n",tp,handle); - return (unsigned long) lookup(PRIV(tp),handle); + if (p->perfect && handle >= p->alloc_hash) + return 0; + r = lookup(PRIV(tp),handle); + return r && r->res.class ? (unsigned long) r : 0; } @@ -164,7 +170,7 @@ DPRINTK("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n",tp,arg,p,f); if (p->perfect) { - if (!r->res.classid) + if (!r->res.class) return -ENOENT; } else { int i; @@ -212,7 +218,7 @@ struct tcindex_filter *f; struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg; struct tcindex_filter **walk; - int hash; + int hash,shift; __u16 mask; DPRINTK("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p," @@ -237,17 +243,22 @@ return -EINVAL; mask = *(__u16 *) RTA_DATA(tb[TCA_TCINDEX_MASK-1]); } - if (p->perfect && hash <= mask) + if (!tb[TCA_TCINDEX_SHIFT-1]) + shift = p->shift; + else { + if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(__u16)) + return -EINVAL; + shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]); + } + if (p->perfect && hash <= (mask >> shift)) return -EBUSY; - if ((p->perfect || p->h) && hash > p->alloc_hash) + if (p->perfect && hash > p->alloc_hash) + return -EBUSY; + if (p->h && hash != p->alloc_hash) return -EBUSY; p->hash = hash; p->mask = mask; - if (tb[TCA_TCINDEX_SHIFT-1]) { - if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(__u16)) - return -EINVAL; - p->shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]); - } + p->shift = shift; if (tb[TCA_TCINDEX_FALL_THROUGH-1]) { if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH-1]) < sizeof(int)) return -EINVAL; @@ -258,9 +269,9 @@ tb[TCA_TCINDEX_POLICE-1]); if (!tb[TCA_TCINDEX_CLASSID-1] && !tb[TCA_TCINDEX_POLICE-1]) return 0; - if (!p->hash) { - if (p->mask < PERFECT_HASH_THRESHOLD) { - p->hash = p->mask+1; + if (!hash) { + if ((mask >> shift) < PERFECT_HASH_THRESHOLD) { + p->hash = (mask >> shift)+1; } else { p->hash = DEFAULT_HASH_SIZE; } @@ -268,7 +279,7 @@ if (!p->perfect && !p->h) { p->alloc_hash = p->hash; DPRINTK("hash %d mask %d\n",p->hash,p->mask); - if (p->hash > p->mask) { + if (p->hash > (mask >> shift)) { p->perfect = kmalloc(p->hash* sizeof(struct tcindex_filter_result),GFP_KERNEL); if (!p->perfect) @@ -283,7 +294,15 @@ memset(p->h, 0, p->hash*sizeof(struct tcindex_filter *)); } } - if (handle > p->mask) + /* + * Note: this could be as restrictive as + * if (handle & ~(mask >> shift)) + * but then, we'd fail handles that may become valid after some + * future mask change. While this is extremely unlikely to ever + * matter, the check below is safer (and also more + * backwards-compatible). + */ + if (p->perfect && handle >= p->alloc_hash) return -EINVAL; if (p->perfect) { r = p->perfect+handle; @@ -308,17 +327,16 @@ } } #ifdef CONFIG_NET_CLS_POLICE - if (!tb[TCA_TCINDEX_POLICE-1]) { - r->police = NULL; - } else { - struct tcf_police *police = - tcf_police_locate(tb[TCA_TCINDEX_POLICE-1],NULL); + { + struct tcf_police *police; - tcf_tree_lock(tp); + police = tb[TCA_TCINDEX_POLICE-1] ? + tcf_police_locate(tb[TCA_TCINDEX_POLICE-1],NULL) : NULL; + tcf_tree_lock(tp); police = xchg(&r->police,police); - tcf_tree_unlock(tp); + tcf_tree_unlock(tp); tcf_police_release(police); - } + } #endif if (r != &new_filter_result) return 0; @@ -339,13 +357,13 @@ 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); if (p->perfect) { for (i = 0; i < p->hash; i++) { - if (!p->perfect[i].res.classid) + if (!p->perfect[i].res.class) continue; if (walker->count >= walker->skip) { if (walker->fn(tp, @@ -361,7 +379,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 Sun Mar 25 18:14:25 2001 @@ -506,7 +506,7 @@ } } - q->wd_expires = delay; + q->wd_expires = base_delay; } } @@ -1740,9 +1740,13 @@ } for (h = 0; h < 16; h++) { - for (cl = q->classes[h]; cl; cl = cl->next) + struct cbq_class *next; + + for (cl = q->classes[h]; cl; cl = next) { + next = cl->next; if (cl != &q->link) cbq_destroy_class(cl); + } } qdisc_put_rtab(q->link.R_tab); diff -u --recursive --new-file v2.4.2/linux/net/sched/sch_dsmark.c linux/net/sched/sch_dsmark.c --- v2.4.2/linux/net/sched/sch_dsmark.c Wed Feb 21 18:20:50 2001 +++ linux/net/sched/sch_dsmark.c Sun Mar 25 18:14:25 2001 @@ -84,7 +84,9 @@ static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg) { - return NULL; + struct dsmark_qdisc_data *p = PRIV(sch); + + return p->q; } @@ -187,7 +189,7 @@ struct dsmark_qdisc_data *p = PRIV(sch); struct tcf_result res; int result; - int ret; + int ret = NET_XMIT_POLICED; D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p); if (p->set_tc_index) { @@ -237,7 +239,7 @@ ((ret = p->q->enqueue(skb,p->q)) != 0)) { sch->stats.drops++; - return 0; + return ret; } sch->stats.bytes += skb->len; sch->stats.packets++; diff -u --recursive --new-file v2.4.2/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c --- v2.4.2/linux/net/sched/sch_tbf.c Fri Apr 28 22:50:14 2000 +++ linux/net/sched/sch_tbf.c Sun Mar 25 18:14:25 2001 @@ -66,7 +66,7 @@ N(t+delta) = min{B/R, N(t) + delta} If the first packet in queue has length S, it may be - transmited only at the time t_* when S/R <= N(t_*), + transmitted only at the time t_* when S/R <= N(t_*), and in this case N(t) jumps: N(t_* + 0) = N(t_* - 0) - S/R. @@ -276,7 +276,7 @@ struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; - int max_size; + int max_size,n; if (rtattr_parse(tb, TCA_TBF_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) || tb[TCA_TBF_PARMS-1] == NULL || @@ -295,15 +295,18 @@ goto done; } - max_size = psched_mtu(sch->dev); + for (n = 0; n < 256; n++) + if (rtab->data[n] > qopt->buffer) break; + max_size = (n << qopt->rate.cell_log)-1; if (ptab) { - int n = max_size>>qopt->peakrate.cell_log; - while (n>0 && ptab->data[n-1] > qopt->mtu) { - max_size -= (1<peakrate.cell_log); - n--; - } + int size; + + for (n = 0; n < 256; n++) + if (ptab->data[n] > qopt->mtu) break; + size = (n << qopt->peakrate.cell_log)-1; + if (size < max_size) max_size = size; } - if (rtab->data[max_size>>qopt->rate.cell_log] > qopt->buffer) + if (max_size < 0) goto done; sch_tree_lock(sch); 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 Wed Mar 14 14:37:36 2001 @@ -212,16 +212,20 @@ 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 +1038,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/sysctl_net.c linux/net/sysctl_net.c --- v2.4.2/linux/net/sysctl_net.c Sat Feb 3 19:51:33 2001 +++ linux/net/sysctl_net.c Sun Mar 25 18:14:25 2001 @@ -20,10 +20,6 @@ extern ctl_table ipv4_table[]; #endif -#ifdef CONFIG_IPX -extern ctl_table ipx_table[]; -#endif - extern ctl_table core_table[]; #ifdef CONFIG_NET @@ -50,9 +46,6 @@ #endif #ifdef CONFIG_INET {NET_IPV4, "ipv4", NULL, 0, 0555, ipv4_table}, -#endif -#ifdef CONFIG_IPX - {NET_IPX, "ipx", NULL, 0, 0555, ipx_table}, #endif #ifdef CONFIG_IPV6 {NET_IPV6, "ipv6", NULL, 0, 0555, ipv6_table}, 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/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c --- v2.4.2/linux/net/wanrouter/wanmain.c Wed Feb 21 18:20:50 2001 +++ linux/net/wanrouter/wanmain.c Sun Mar 25 18:14:25 2001 @@ -5,7 +5,7 @@ * the following common services for the WAN Link Drivers: * o WAN device managenment (registering, unregistering) * o Network interface management -* o Physical connection management (dial-up, incomming calls) +* o Physical connection management (dial-up, incoming calls) * o Logical connection management (switched virtual circuits) * o Protocol encapsulation/decapsulation * 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